using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Threading;
//using System.Windows.Forms;
using AForge.Video.DirectShow;


namespace InputDevices
{
    public delegate void SetImageCallback(Bitmap hBitmap);
   // public delegate void SetImagePtrCallback(NewFramePtrEventArgs hBitmap);

    public class VideoDevice: IDisposable
    {
        VideoCaptureDevice device = null;
        VideoCapabilities capability
        {
            set;
            get;

        }
        Timer tmr;


    #region  Внешние свойства
        //volatile Bitmap _LastFrame;
  //      Bitmap LastFrame;
        //{
        //    get
        //    {
        //        return _LastFrame;
        //    }
        //    private set
        //    {
        //        _LastFrame = value;
        //    }
        //}
        volatile float _fps;
        public float fps { 
            get {
                return _fps;   
            }
            private set
            {
                _fps = value;
            }
        }

        string _Name = null;
        public string Name
        {
            get
            {
                return _Name;


            }
        }
        public VideoCapabilities[] VideoCapabilities
        {
            get
            {
                return device.VideoCapabilities;
            }

        }
        public VideoCapabilities Capability
        {
            set
            {
                if (device != null)
                {
                    StopDevice();
                    capability = value;
                    device.DesiredFrameRate = value.FrameRate;
                    device.DesiredFrameSize = value.FrameSize;
                    StartDevice();
                }
                else
                {
                    throw new Exception("Нет устройства");
                }
            }
            get
            {
                return capability;



            }
        }

        public string MonikerString
        {
            get { return device.Source; }
            private set
            {
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Добавление новго устройства ");
        
                if (device != null)
                {
                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Устрогйство было создано. Ожидаем удаления ");
        
                    device.SignalToStop();
                    device.WaitForStop();
                    device = null;
                }
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Создаем устройство ");
        
                device = new VideoCaptureDevice(value);
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Применяем настрйоки");
        
                device.NewFrame += new AForge.Video.NewFrameEventHandler(device_NewFrame);
             //   device.NewFramePtr += new NewFramePtrEventHandler(device_NewFramePtr);  
                device.VideoSourceError += new AForge.Video.VideoSourceErrorEventHandler(device_VideoSourceError);
                Capability = device.VideoCapabilities[0];//.First();
                // device.DesiredFrameRate = device.VideoCapabilities.First().FrameRate;
                // device.DesiredFrameSize = device.VideoCapabilities.First().FrameSize;
                //if (!device.IsRunning)
                //{
                //    device.Start();
                //    stopWatch.Start();
                //}           

            }

        }

        public event SetImageCallback NewFrame;
    #endregion

    #region Конструкторы
        public VideoDevice(string MonikerString)
        {
            this.MonikerString =MonikerString;
            List<FilterInfo> filters = GetInfo();
            fps = 0;
            foreach (FilterInfo p in filters)
            {
                if (p.MonikerString == device.Source)
                {
                    _Name = p.Name;
                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), " Определили имя устройства " + _Name);
        
                    return;
                }
            }
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), " Имя устройства не определено" );
        
         //   LastFrame = NoSignal;
            
        }
    #endregion

    #region Поведение
        void t_Tick()
        {
            int framesReceived1 = 0;
            if (device != null)
            {
                framesReceived1 = device.FramesReceived;
            }
            else
            {
                framesReceived1 = 0;
            }

            if (framesReceived1 == 0)
            {
                UpdateScreenImage(NoSignal);
            }

            fps = framesReceived1;

        }
        void device_VideoSourceError(object sender, AForge.Video.VideoSourceErrorEventArgs eventArgs)
        {
            UpdateScreenImage(NoSignal);
        }
        void device_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            UpdateScreenImage(eventArgs.Frame);
        }
        //void device_NewFramePtr(object sender, NewFramePtrEventArgs eventArgs)
        //{
        //    UpdateScreenImage(eventArgs);
        //}
      
        void UpdateScreenImage(Bitmap hBitmap)
        {
            //if (LastFrame != null)
            //    LastFrame.Dispose();
            if (NewFrame != null)
                using (Bitmap LastFrame = (Bitmap)hBitmap)//.Clone())
                    NewFrame(LastFrame);
        }

        //void UpdateScreenImage(NewFramePtrEventArgs hBitmap)
        //{
        //    //if (LastFrame != null)
        //    //    LastFrame.Dispose();
        //    if (NewFramePtr != null)
        //        NewFramePtr(hBitmap);
        //}

        Bitmap NoSignal
        {
            get
            {
                if (device != null)
                {
                    return _NoSignalCreate(device.DesiredFrameSize);
                }
                else
                {
                    return _NoSignalCreate(new System.Drawing.Size(640, 480));
                }
            }
        }

        //Bitmap NoSignal
        //{
        //    get
        //    {
        //        if (device != null)
        //        {
        //            return _NoSignalCreate(device.DesiredFrameSize);
        //        }
        //        else
        //        {
        //            return _NoSignalCreate(new System.Drawing.Size(640, 480));
        //        }
        //    }
        //}

    #endregion

    #region Методы
        public void StopDevice()
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), " Остановить устройство " + _Name);
        
            if (device.IsRunning)
            {
                device.SignalToStop();
                device.WaitForStop();
                tmr.Dispose();
            }
        }
        public void StartDevice()
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), " Запустить устройство " + _Name);
       
            if (!device.IsRunning)
            {
                device.Start();
                tmr = new Timer((_) => this.t_Tick(), null, 0, 1000);
            }
        }
    #endregion

    #region Финализаторы
        ~VideoDevice()
        {
            Dispose(false);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (device != null)
            {
                device.SignalToStop();
                device.WaitForStop();
                device = null;
            }
            if (tmr != null)
            {
                tmr.Dispose();
                tmr = null;
            }
        }
    #endregion
        static Font font = new Font("Arial", 16);
        static Brush brush = new SolidBrush(Color.White);
        static Bitmap _NoSignalCreate(System.Drawing.Size s)
        {
            try
            {
                using (Bitmap result = new Bitmap(s.Width, s.Height))
                {
                    using (Graphics g = Graphics.FromImage(result))
                    {
                        using (Brush back = new SolidBrush(Color.Black))
                            g.FillRectangle(back, 0, 0, s.Width, s.Height);
                        g.DrawString("Нет сигнала", font, brush, (s.Width - g.MeasureString("Нет сигнала", font).Width) / 2, (s.Height - g.MeasureString("Нет сигнала", font).Height) / 2);
                    }
                    return (Bitmap)result.Clone();
                }
            }
            catch
            {
                return _NoSignalCreate(new System.Drawing.Size(640, 480));
            }
        }
       

        //Статические члены - для коллекции
        public static List<FilterInfo> GetInfo()
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Получение списка устройств");
        
            List<FilterInfo> result = new List<FilterInfo>();
            FilterInfoCollection source = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            foreach (FilterInfo fi in source)
            {
                result.Add(fi);
            }
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Найдено "+ result.Count + " устройств");
        
            return result;

        }
    }
}
