﻿using System;
using System.IO;

namespace Oni.Sound
{
    internal class AifFile
    {
        #region Private data
        private const int fcc_FORM = 0x464f524d;
        private const int fcc_AIFC = 0x41494643;
        private const int fcc_COMM = 0x434f4d4d;
        private const int fcc_SSND = 0x53534e44;

        private int channelCount;
        private int numSampleFrames;
        private int sampleSize;
        private byte[] sampleRate;
        private int format;
        private byte[] soundData;
        #endregion

        public static AifFile FromFile(string filePath)
        {
            using (var reader = new BinaryReader(filePath, true))
            {
                var header = new AifFile();

                if (reader.ReadInt32() != fcc_FORM)
                    throw new InvalidDataException("Not an AIF file");

                int size = reader.ReadInt32();

                if (reader.ReadInt32() != fcc_AIFC)
                    throw new InvalidDataException("Not a compressed AIF file");

                for (int chunkType, chunkSize, chunkStart; reader.Position < size; reader.Position = chunkStart + chunkSize)
                {
                    chunkType = reader.ReadInt32();
                    chunkSize = reader.ReadInt32();
                    chunkStart = reader.Position;

                    if (chunkType == fcc_COMM)
                        header.ReadFormatChunk(reader, chunkSize);
                    else if (chunkType == fcc_SSND)
                        header.ReadDataChunk(reader, chunkSize);
                }

                return header;
            }
        }

        private void ReadFormatChunk(BinaryReader reader, int chunkSize)
        {
            channelCount = reader.ReadInt16();
            numSampleFrames = reader.ReadInt32();
            sampleSize = reader.ReadInt16();
            sampleRate = reader.ReadBytes(10);
            format = reader.ReadInt32();
        }

        private void ReadDataChunk(BinaryReader reader, int chunkSize)
        {
            reader.Position += 8;
            soundData = reader.ReadBytes(chunkSize - 8);
        }

        public int ChannelCount => channelCount;
        public int SampleFrames => numSampleFrames;
        public int SampleSize => sampleSize;
        public byte[] SampleRate => sampleRate;
        public int Format => format;
        public byte[] SoundData => soundData;
    }
}
