using System;
using System.Runtime.InteropServices;
using NAudio.Wave;
using Nativ;

namespace Avi {
    public abstract class Stream: IDisposable {
        protected AVISTREAMINFO streaminfo;
        protected IntPtr stream;
        public virtual int position
        {
            get;
            set;
        }
        public string Name { get { return streaminfo.name; } }
        //protected virtual long Position
        //{
        //    get {
        //        return position;
        //    }
        //    set { throw new Exception("fail"); }
        //}
        protected Stream(IntPtr inStream, AVISTREAMINFO instreaminfo)
        {
            stream = inStream;
            streaminfo = instreaminfo;
        }
        protected Stream()
        {
        }

        ~Stream() {
            Dispose(false);
        }
        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {

            Close();
        }

        internal virtual void Close() {
            // Освободить опток
            if(stream != IntPtr.Zero) {
               // AForge.Video.VFW.
                NativeMethods.AVIStreamRelease(stream);
                stream = IntPtr.Zero;
            }
        }
 
    }



   // public abstract class AudioStream:Stream {
   ////     protected IntPtr streamCompressed = IntPtr.Zero;
   //     protected WAVEFORMATEX wf;
   //     internal AudioStream(IntPtr inStream, AVISTREAMINFO instreaminfo)
   //         : base(inStream, instreaminfo) { }
   //     protected AudioStream() { }
   //     internal override void Close()
   //     {
   //         // Освободить сжатый поток

   //         //if (streamCompressed != IntPtr.Zero)
   //         //{
   //         //    NativeMethods.AVIStreamRelease(streamCompressed);
   //         //    streamCompressed = IntPtr.Zero;
   //         //}
   //         base.Close();
   //     }

   //     protected override void Dispose(bool disposing)
   //     {
   //         base.Dispose(disposing);
   //     }
   // }




   // public class AudioStreamRead : AudioStream, IRecorded
   // {


   //     public class MyProvide : System.IO.Stream, IWaveProvider
   //     {
   //         WaveFormat format;

   //         int length;
   //         long pos = -44;
   //         int framesize = 0;
   //         bool canread = true;
   //         IntPtr stream;
   //         long byterate;
   //         byte[] header;
   //         object obj = new object();

   //         public override bool CanRead
   //         {
   //             get { return true; }
   //         }

   //         public override bool CanSeek
   //         {
   //             get { return true; }
   //         }

   //         public override bool CanWrite
   //         {
   //             get { return false; }
   //         }

   //         public override void Flush()
   //         {
   //             throw new NotImplementedException();
   //         }

   //         public override long Length
   //         {
   //             get { return length; }
   //         }

   //         public override long Position
   //         {
   //             get
   //             {
   //                 if (!canread)
   //                     throw new System.ObjectDisposedException("ПОток не открыт");
   //                 return pos + 44;
   //             }
   //             set
   //             {
   //                 lock (obj)
   //                 {
   //                     if (!canread)
   //                         throw new System.ObjectDisposedException("ПОток не открыт");
   //                     pos = value - 44;
   //                 }
   //             }
   //         }

   //         public override int Read(byte[] buffer, int offset, int count)
   //         {
   //             lock (obj)
   //             {
   //                 if (buffer == null)
   //                     throw new System.ArgumentNullException("buffer имеет значение null");
   //                 if (offset + count > buffer.Length)
   //                     throw new System.ArgumentException("Сумма значений параметров offset и count больше длины буфера.");
   //                 if ((count < 0) || (offset < 0))
   //                     throw new System.ArgumentOutOfRangeException("offset или count являются отрицательными");
   //                 if (!canread)
   //                     throw new System.ObjectDisposedException("ПОток не открыт");
   //                 if (pos < 0)
   //                 {
   //                     if (count + pos < 0)
   //                     {
   //                         for (long i = 0; i < count; i++)
   //                         {
   //                             buffer[offset + i] = header[i + 44 + pos];
   //                         }
   //                         pos += count;
   //                         return count;
   //                     }
   //                     else
   //                     {
   //                         for (long i = 0; i < -pos; i++)
   //                         {
   //                             buffer[offset + i] = header[i + 44 + pos];
   //                         }
   //                         int tmp = (int)(-pos);
   //                         pos = 0;
   //                         int c = ReadData(buffer, offset + tmp, count - tmp);
   //                         pos += c;
   //                         return tmp + c;
   //                         //надо счиать count - pos символов данных с начала
   //                     }
   //                 }
   //                 else if (pos < length - 44)
   //                 {
   //                     int c = ReadData(buffer, offset, count);
   //                     pos += c;

   //                     return c;

   //                 }
   //                 else
   //                 {
   //                     return 0;
   //                 }
   //             }
   //         }

   //         unsafe private int ReadData(byte[] buffer, int offset, int count)
   //         {
   //             //Прочитать чимволы из потока начиная с pos

   //             int tmp = 0;
   //             int res = 0;
   //             byte[] buf1 = new byte[count];
   //             int currentframe = (int)(pos / framesize);
   //             fixed (byte* buf = buf1)
   //             {
   //                 if (0 != NativeMethods.AVIStreamRead(stream, currentframe, 0, (IntPtr)buf, (int)(count), out tmp, out res))
   //                 {
   //                     return 0;
   //                     throw new Exception("asdf");
   //                 }

   //             }
   //             for (int i = 0; i < tmp; i++)
   //                 buffer[i + offset] = buf1[i];
   //             return (int)(tmp);



   //         }

   //         public override long Seek(long offset, System.IO.SeekOrigin origin)
   //         {
   //             if (!canread)
   //                 throw new System.ObjectDisposedException("ПОток не открыт");
   //             if (origin == System.IO.SeekOrigin.Begin)
   //             {
   //                 pos = offset;
   //             }
   //             else if (origin == System.IO.SeekOrigin.Current)
   //             {
   //                 pos += offset;
   //             }
   //             else
   //             {
   //                 pos = length - offset;
   //             }
   //             if ((pos < 0) || (pos > length))
   //             {
   //                 throw new System.IO.IOException();
   //             }
   //             return pos;
   //         }

   //         public override void SetLength(long value)
   //         {
   //             throw new System.NotSupportedException();
   //         }

   //         public override void Write(byte[] buffer, int offset, int count)
   //         {
   //             throw new System.NotSupportedException();
   //         }

   //         public MyProvide(IntPtr audiostream, int len, WAVEFORMATEX wf)
   //         {
   //             stream = audiostream;
   //             length = (int)(len * wf.nAvgBytesPerSec / 10 + 44);
   //             WavHeader wh = new WavHeader();
   //             wh.ChunkId = 0x46464952;
   //             wh.ChunkSize = (uint)(len * wf.nAvgBytesPerSec / 10 + 44 - 8);// g_streamSampleLength * wf.nBlockAlign + 450;
   //             wh.Format = 0x45564157;
   //             wh.Subchunk1Id = 0x20746D66;
   //             wh.Subchunk1Size = 16;
   //             wh.AudioFormat = wf.wFormatTag;
   //             wh.NumChannels = wf.nChannels;
   //             wh.SampleRate = wf.nSamplesPerSec;
   //             wh.ByteRate = wf.nSamplesPerSec * wf.wBitsPerSample / 8 * wf.nChannels;
   //             wh.BlockAlign = wf.nBlockAlign;
   //             wh.BitsPerSample = wf.wBitsPerSample;
   //             wh.Subchunk2Id = 0x61746164;
   //             wh.Subchunk2Size = (uint)(len * wf.nAvgBytesPerSec / 10);//numSamples * numChannels * bitsPerSample / 8;
   //             header = WavHeader.getBytes(wh);
   //             byterate = wh.ByteRate;
   //             framesize = wh.NumChannels * wf.wBitsPerSample / 8;
   //             format = new WaveFormat((int)wf.nSamplesPerSec, wf.wBitsPerSample, wf.nChannels);
   //         }

   //         public WaveFormat WaveFormat
   //         {
   //             get { return format; }
   //         }

   //         public long TimeToPos(long time)
   //         {
   //             return time * byterate / 1000;
   //         }
   //     }



   //     public MyProvide provider;
   //     int maxtime = 0;

   //     public AudioStreamRead(IntPtr inStream, AVISTREAMINFO instreaminfo)
   //         : base(inStream, instreaminfo)
   //     {
   //         int lSize = 0;
   //         NativeMethods.AVIStreamReadFormat(stream, 0, ref wf, ref lSize);
   //         NativeMethods.AVIStreamReadFormat(stream, 0, ref wf, ref lSize);
   //         provider = new MyProvide(stream, instreaminfo.length, wf);
   //         int audioStreamStart = NativeMethods.AVIStreamStart(stream); // AForge.Video.VFW.
   //         if (0 != NativeMethods.AVIStreamBeginStreaming(stream, audioStreamStart, instreaminfo.length, 1000))
   //             throw new Exception("asdf");
   //         maxtime = instreaminfo.length * 100;
   //     }

   //     public override int position
   //     {
   //         get { return (int)provider.Position; }
   //         set { provider.Position = value; }
   //     }

   //     public int Length()
   //     {
   //         return maxtime;
   //     }

   //     protected override void  Dispose(bool disposing)
   //     {
   //         provider.Close();
   //         base.Dispose(disposing);
   //     }



   // }

   // public struct WavHeader
   // {
   //     // WAV-формат начинается с RIFF-заголовка:

   //     // Содержит символы "RIFF" в ASCII кодировке
   //     // (0x52494646 в big-endian представлении)
   //     public UInt32 ChunkId;

   //     // 36 + subchunk2Size, или более точно:
   //     // 4 + (8 + subchunk1Size) + (8 + subchunk2Size)
   //     // Это оставшийся размер цепочки, начиная с этой позиции.
   //     // Иначе говоря, это размер файла - 8, то есть,
   //     // исключены поля chunkId и chunkSize.
   //     public UInt32 ChunkSize;

   //     // Содержит символы "WAVE"
   //     // (0x57415645 в big-endian представлении)
   //     public UInt32 Format;

   //     // Формат "WAVE" состоит из двух подцепочек: "fmt " и "data":
   //     // Подцепочка "fmt " описывает формат звуковых данных:

   //     // Содержит символы "fmt "
   //     // (0x666d7420 в big-endian представлении)
   //     public UInt32 Subchunk1Id;

   //     // 16 для формата PCM.
   //     // Это оставшийся размер подцепочки, начиная с этой позиции.
   //     public UInt32 Subchunk1Size;

   //     // Аудио формат, полный список можно получить здесь http://audiocoding.ru/wav_formats.txt
   //     // Для PCM = 1 (то есть, Линейное квантование).
   //     // Значения, отличающиеся от 1, обозначают некоторый формат сжатия.
   //     public UInt16 AudioFormat;

   //     // Количество каналов. Моно = 1, Стерео = 2 и т.д.
   //     public UInt16 NumChannels;

   //     // Частота дискретизации. 8000 Гц, 44100 Гц и т.д.
   //     public UInt32 SampleRate;

   //     // sampleRate * numChannels * bitsPerSample/8
   //     public UInt32 ByteRate;

   //     // numChannels * bitsPerSample/8
   //     // Количество байт для одного сэмпла, включая все каналы.
   //     public UInt16 BlockAlign;

   //     // Так называемая "глубиная" или точность звучания. 8 бит, 16 бит и т.д.
   //     public UInt16 BitsPerSample;

   //     // Подцепочка "data" содержит аудио-данные и их размер.

   //     // Содержит символы "data"
   //     // (0x64617461 в big-endian представлении)
   //     public UInt32 Subchunk2Id;//0x64617461 = ;

   //     // numSamples * numChannels * bitsPerSample/8
   //     // Количество байт в области данных.
   //     public UInt32 Subchunk2Size;

   //     // Далее следуют непосредственно Wav данные.
   //     public static byte[] getBytes(WavHeader str)
   //     {
   //         int size = Marshal.SizeOf(str);
   //         byte[] arr = new byte[size];
   //         IntPtr ptr = Marshal.AllocHGlobal(size);

   //         Marshal.StructureToPtr(str, ptr, true);
   //         Marshal.Copy(ptr, arr, 0, size);
   //         Marshal.FreeHGlobal(ptr);

   //         return arr;
   //     }
   // }




   // public class AudioStreamWrite:AudioStream {
   //     // Длина одной линии
   //     private object sync = new object();

   //     internal AudioStreamWrite(IntPtr file): base() {
   //         // Рассчитываем шаг
   //         wf = new WAVEFORMATEX();
   //         wf.cbSize = (ushort)Marshal.SizeOf(wf); //размер структуры WAVEFORMATEX.
   //         wf.wFormatTag = 1; //формат, у нас pcm.
   //         wf.nChannels = 2; //кол-во каналов: 1 - моно, 2 - стерео.
   //         wf.nSamplesPerSec = 44100; //частота звука, герц в секунду.
   //         wf.wBitsPerSample = 16; //количество бит за один квант на одном канале.
   //         wf.nBlockAlign = (ushort)((wf.wBitsPerSample * wf.nChannels) / 8); // байт за один квант.
   //         wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; // кол-во байт в секунду

   //         streaminfo = new AVISTREAMINFO();
   //         streaminfo.type = (int)StreamType.AUDIO;//.mmioFOURCC("auds"); //тип потока.
   //         streaminfo.scale = wf.nBlockAlign;
   //         streaminfo.rate = (int)(wf.nSamplesPerSec * streaminfo.scale); // байт в сек.
   //         streaminfo.initialFrames = 1; //номер первого кадра.
   //         streaminfo.sampleSize = wf.nBlockAlign; //кол-во байт за квант на всех каналах.
   //         streaminfo.quality = -1; //качество, -1 - по умолчанию.

   //         AviError err;
   //         if ((err = (AviError)NativeMethods.AVIFileCreateStream(file, out stream, ref streaminfo)) != 0)
   //             throw new VideoException("Failed creating stream." + err.ToString());

            
   //         if ((err = (AviError)NativeMethods.AVIStreamSetFormat(stream, 0, ref wf, Marshal.SizeOf(wf))) != 0)
   //             throw new VideoException("Failed setting format of the compressed stream." + err);

   //    //    NativeMethods.AVISaveOptions(stream, ref options); // Выбираем кодек и формат

   //         //if ((err = (AviError)NativeMethods.AVIMakeCompressedStream(out streamCompressed, stream, ref options, IntPtr.Zero)) != 0)
   //         //    throw new VideoException("Failed creating compressed stream." + err);

   //          position = 0;

   //     }

   //     public void AddSample(byte[] buffer, int count) {
   //         lock(sync) {
   //             IntPtr unmanagedPointer = Marshal.AllocHGlobal(count);
   //             Marshal.Copy(buffer, 0, unmanagedPointer, count);
   //             // запись в поток
   //             if(NativeMethods.AVIStreamWrite(stream, position, 1, unmanagedPointer,
   //                 count, 0, IntPtr.Zero, IntPtr.Zero) != 0)
   //                 throw new VideoException("Failed adding sample.");
   //             Marshal.FreeHGlobal(unmanagedPointer);
   //             position++;
   //         }
   //     }

   // }
}
