using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TwoCamWPF.Settings;
using Avi;
using System.Threading;
using System.Diagnostics;
using System.Drawing;
using AForge.Video.DirectShow;
using System.Reflection;
using System.Runtime.InteropServices;
namespace TwoCamWPF.Helpers
{


    class FileWatcher : BaseViewModel, IDisposable
    {
        AviFile file;
        List<SingleVideoBuffer> dict = new List<SingleVideoBuffer>();
        Settings.ClassSettings settings;
        Thread thr;
        volatile bool closeEvent = false;
        ManualResetEvent pausedEvent = new ManualResetEvent(true);
        volatile bool isPaused = true;

        public bool IsRecording
        {
            get
            {
                return !isPaused;
            }
            set
            {
                if (value)
                {
                    isPaused = false;
                    pausedEvent.Reset();
                }
                else
                {
                    isPaused = true;
                    pausedEvent.WaitOne();
                }

                RaisePropertyChanged("IsRecording");
            }
        }

        void CreateFile()
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Создание нового файла");
            DeleteOldFiles();

            file = AviFile.CreateAviFile(GetNext(settings));

            foreach (OneCameraSettings ocs in settings.CamerasSettings)
            {

                if ((ocs.device != null) && (ocs.IsUsing))
                {

                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Добавление потока");
                    System.Drawing.Size size = ocs.Capability.FrameSize;
                    VideoStreamWrite sw = file.AddVideoStream(
                        size.Width,
                        size.Height,
                        settings.RecordSettings.BitRate,
                        ocs.Codec.Fcc,
                        ocs.StreamName
                        );
                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Добавление в словарь привязок ");
                    dict.Add(new SingleVideoBuffer(
                        ocs.device,
                        sw,
                        new MagicQueue<Bitmap>(
                        //  new NewFramePtrEventArgs(
                            VideoStreamWrite.NoSignal(size.Width, size.Height),
                        //.GetHbitmap(),
                        //  size.Height,
                        //  size.Width,
                        //  size.Width*3),
                            1000 / settings.RecordSettings.BitRate,
                            MemoryHelper.GetPhysicalMemorySize() * settings.CamerasSettings.bufferSize / 100,
                            size.Width * size.Height * 3


                            ),
                        sw.Rate * settings.RecordSettings.FileLength
                    ));
                    // ocs.device.Subscribe(sw, (bmp) => lol(sw, bmp));

                }
            }
        }

        void CloseFile()
        {

            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Закрытие файла");
            if (file == null)
                return;

            lock (dict)
            {

                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Посылаем сигнал потокам на завершение");
                dict.ForEach(p => p.Dispose());// Говорим потокам, что хотим прекратить запись

                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Ожидаем завершения потоков");
                while (!dict.All(p => p.IsFinished())) //Подождать пока всё допишется
                {
                    Thread.Sleep(100);
                }

                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Очищаем список привязок");
                dict.Clear();
            }
            file.Close();
         //   file.WaitClose();
            file.Dispose();
            file = null;
        }
        
        public FileWatcher(Settings.ClassSettings settings)
        {
            this.settings = settings;
            //   int startdelay;

            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Зоздание экземпляра записывателя");
            thr = new Thread(new ThreadStart(Exec)) { Name = "FileWatcher"};
            thr.Start();
            if (settings.StartSettings.RunAndRecord)
            {

                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Автостарт:  Отложенная запись через  " + settings.StartSettings.RunDelay + " Секунд");
                Helpers.AutoStartDelayer.AutoStartDelay(settings.StartSettings.RunDelay * 1000, (_, s) => IsRecording = true);
            }
            else
            {
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Автостарт отключен ");
           
            }
        }

        void DeleteOldFiles()
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Удаление старых файлов");
           
            Helpers.FileArchive.DeleteOldFiles(settings.RecordSettings.SaveFolder, settings.RecordSettings.FilesCount);
      

        }

        void Exec()
        {
            while (true)
            {

                if (closeEvent)
                {
                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Заканчиваем запись");
                    CloseFile();
                    return;
                } 
                if (pausedEvent.WaitOne(10))
                    continue;
                if (isPaused)
                {
                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Поставили запись на паузу");   
                    CloseFile();
                    pausedEvent.Set();
                    continue;
                }

                if (dict.All(p => p.IsFinished()))
                {
                    
                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Все потоки записались " );
                    if (file == null)
                    {
                        
                        Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Создаем новый файл ");
                        CreateFile();
                    }
                    else
                    {
                        
                        DeleteOldFiles();
                        AviFile bk = file;
                        Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(),  "   Создание нового файла из старого");
                        file = AviFile.CreateNextAviFile(GetNext(settings), bk,
                            (olds, news) =>
                            {
                                lock (dict)
                                {
                                    SingleVideoBuffer oldThree = dict.First(p => p.stream == olds);
                                    SingleVideoBuffer newThree = new SingleVideoBuffer(oldThree, news);
                                    dict.Add(newThree);
                                    dict.Remove(oldThree);
                                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Поток " + news.Name + " создан из потока " + olds.Name );
                                }
                            });

                        bk.Dispose();
                        bk = null;
                    }
                }
            }
            
        }

        static string GetNext(Settings.ClassSettings settings)
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Получаем имя нового файла " );
            string folder = (settings["RecordSettings"] as RecordSettings).SaveFolder;
            string file = folder + @"\" + DateTime.Now.ToString().Replace('/', '_').Replace(":", "_") + ".avi";
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "   Получаем имя нового файла " + file);
            return file;
        }

        public void Dispose()
        {
            closeEvent = true;
            if (thr.ThreadState == System.Threading.ThreadState.Running)
                thr.Join();
        }

    }

    

    class Mixer
    {
        List<SingleVideoBuffer> buffers = new List<SingleVideoBuffer>();

    }


}
