using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using Nativ;

namespace Avi
{

    public delegate void Action<in T1, in T2>(T1 obj1, T2 obj2);
    public delegate T Func<out T>();


    public class AviFile : IDisposable
    {
        // Указатель на AVI файл
        IntPtr file;
        string filename;
        private AviFile(string fileName)
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Создание видеофайла");
               
            NativeMethods.AVIFileInit();
             filename = fileName;
        }

   
        public List<Stream> streams = new List<Stream>();

        public static AviFile CreateAviFile(string fileName)
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Создание видеофайла " + fileName);
               

            try
            {
                AviFile result = new AviFile(fileName);
                AviError err;
                if ((err = (AviError)NativeMethods.AVIFileOpen(out result.file, fileName, OpenFileMode.Create | OpenFileMode.Write , IntPtr.Zero)) != 0)
                    throw new System.IO.IOException("Failed opening the specified file." + err);
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Ресурсы созданы " + fileName);
               // result.Thr.Start();
                return result;
            }
            catch (Exception e)
            {

                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Ошибка создания видеофайла " + e.Message);
                return null;
            }
        }

        public static AviFile CreateNextAviFile(string fileName, AviFile backFile, Action<VideoStreamWrite, VideoStreamWrite> callback = null)
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Создание СЛЕДУЮЩЕГО видеофайла " + fileName);
              
            try
            {

                AviFile result = CreateAviFile(fileName);
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Копирование видеопотоков в  видеофайле " + fileName);
          
                foreach (Stream stream in backFile.streams)
                {
                    if (stream is VideoStreamWrite)
                    {
                        result.AddVideoStream(stream as VideoStreamWrite, callback);
                    }
                }
                return result;
            }
            catch (Exception e)

            {
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Ошибка создания  СЛЕДУЮЩЕГО видеофайла " + e.Message);
          
                return null;
            }
        }



        //public static AviFile OpenAviFile(string fileName)
        //{
        //    //    try {
        //    AviFile result = new AviFile(fileName);
        //    if (NativeMethods.AVIFileOpen(out result.file, fileName, OpenFileMode.Read, IntPtr.Zero) != 0)
        //    {
        //        result.Dispose();
        //        throw new System.IO.IOException("Failed opening the specified file.");
        //    }
        //    AVIFILEINFO info = new AVIFILEINFO();
        //    if (NativeMethods.AVIFileInfo(result.file, out info, Marshal.SizeOf(info)) != 0)
        //    {
        //        result.Dispose();
        //        throw new System.IO.IOException("Failed opening the specified file.");

        //    }
        
        //    result.GetStreams();
        //    //result.videostreams = new List<VideoStream>(result.GetVideoStreams());
        //    //result.audiostreams = new List<AudioStream>(result.GetAudioStreams());
        //    return result;
        //    //} catch {
        //    //    return null;
        //    //}
        //}



        //void GetStreams()
        //{
        //    for (int i = 0; ; i++)
        //    {
        //        IntPtr stream;
        //        if (0 != NativeMethods.AVIFileGetStream(file, out stream, 0, i))
        //            break;
        //        AVISTREAMINFO streaminfo = new AVISTREAMINFO();
        //        if (0 != NativeMethods.AVIStreamInfo(stream, ref streaminfo, Marshal.SizeOf(streaminfo)))
        //            throw new VideoException("Ошибка чтения аудио потока");
        //        if (streaminfo.type == (int)StreamType.VIDEO)
        //            streams.Add(new VideoStreamRead(stream, streaminfo));
        //        else if (streaminfo.type == (int)StreamType.AUDIO)
        //            streams.Add(new AudioStreamRead(stream, streaminfo));
        //    }
        //}


        //public int Length()
        //{
        //    return streams.Cast<IRecorded>().Select(p => p.Length()).Max();
        //}


        public VideoStreamWrite AddVideoStream(int width, int height, int framerate, string codec, string name, Bitmap screen = null)
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Добавление нового видеопотока " + name);
            VideoStreamWrite stream = new VideoStreamWrite(this.file, width, height, framerate, codec, name, screen);
            streams.Add(stream);
            return stream;
  
        }

        public VideoStreamWrite AddVideoStream(VideoStreamWrite oldstream, Action<VideoStreamWrite,VideoStreamWrite> callback = null)
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Копирование видеопотока " + oldstream.Name );
            VideoStreamWrite stream = new VideoStreamWrite(this.file, oldstream.Width, oldstream.Height, oldstream.Rate, oldstream.Codec, oldstream.Name);
            streams.Add(stream);
            if (callback != null)
            {
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Выполнение функций копирования видеопотока");

                callback(oldstream, stream);

            }
            return stream;

        }
        //AudioStreamWrite AddAudioStream()
        //{
        //    if (((int)mode & 1) != 1)
        //        throw new Exception("Нельзя открыть аудиопоток");
        //    AudioStreamWrite stream = new AudioStreamWrite(this.file);


        //    streams.Add(stream);
        //    return stream;// s.Count - 1;
        //}

   

        public void Close()
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Отправляем сигнал на закрытие видеофайла " + filename);
           // exitEvent = true;
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Сигнал закрытия видеофайла " + filename);

            if (file != IntPtr.Zero)
            {
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Закрытие видеопотоков в " + filename);

                foreach (Stream stream in streams)
                    stream.Close();
                NativeMethods.AVIFileRelease(file);
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Освобождение ресурсов видеофайла " + filename);
                file = IntPtr.Zero;
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {

            }
            Close();
        }

        ~AviFile()
        {
            Dispose(false);
        }

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

}
