using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InputDevices;
using AForge.Video.DirectShow;
using System.Drawing;
using System.Diagnostics;
using AForge.Video;
using System.Reflection;

namespace TwoCamWPF.Helpers
{
    abstract class VideoOutput
    {
        protected class IDelegatePair
        {

            internal object sender;
        }

        protected class DelegatePair : IDelegatePair
        {
            internal SetImageCallback Delegate;
        }
        //protected class DelegatePairPtr : IDelegatePair
        //{
        //    internal SetImagePtrCallback Delegate;
        //}


        protected List<IDelegatePair> Delegats = new List<IDelegatePair>();

        public virtual void Subscribe(object obj, SetImageCallback callback)
        {
            lock (Delegats)
            {

              //  Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), obj + " подписался на " + device.Name);
                Delegats.Add(new DelegatePair() { sender = obj, Delegate = callback });
                //device.StartDevice();
                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Подписано " + Delegats.Count + " объектов");
            }
            if (Delegats.Count > 0)
                StartDevice();
        }

        public virtual void Unsubscribe(object obj)
        {
            lock (Delegats)
            {
             //   Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), obj + " отписался от " );
                Delegats.RemoveAll(p => p.sender == obj);

                Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Подписано " + Delegats.Count + " объектов");
            }
            if (Delegats.Count == 0)
                StopDevice();

        }

        protected void DelegatsExecute(Bitmap bmp)
        {

            //   Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Новый кадр c " + this.Name);
            lock (Delegats)
            {
                foreach (IDelegatePair p in Delegats)
                {
                    if (p is DelegatePair)
                    {
                        try
                        {
                            if ((p as DelegatePair).Delegate != null)
                                (p as DelegatePair).Delegate(bmp);
                        }
                        catch (Exception e)
                        {
                            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Ошибка " + e);
                            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "в делегате " + (p as DelegatePair).Delegate.Method.Name);
                            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "объекта " + p.sender);
                        }
                    }
                }
            }
        }

        //protected void DelegatsExecute(NewFramePtrEventArgs bmp)
        //{
        //    //   Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "  Новый кадр c " + this.Name);

        //    lock (Delegats)
        //    {
        //        foreach (IDelegatePair p in Delegats)
        //        {
        //            if (p is DelegatePairPtr)
        //            {
        //                try
        //                {
        //                    if ((p as DelegatePairPtr).Delegate != null)
        //                        (p as DelegatePairPtr).Delegate(bmp);
        //                }
        //                catch (Exception e)
        //                {
        //                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Ошибка " + e);
        //                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "в делегате " + (p as DelegatePairPtr).Delegate.Method.Name);
        //                    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "объекта " + p.sender);
        //                }
        //            }
        //        }
        //    }
        //}

        public abstract void StartDevice();
        public abstract void StopDevice();


    }


    class VideoDeviceWatcher : VideoOutput
    { 
      
        VideoDevice device;
        public VideoDeviceWatcher(VideoDevice device)
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Наблюдение за камерой " + device.Name);
              
            this.device = device;
            device.NewFrame += DelegatsExecute;
        //    device.NewFramePtr += DelegatsExecute;
        }
        public static List<VideoDeviceWatcher> watchers = new List<VideoDeviceWatcher>();
        public VideoCapabilities Capability
        {
            get
            {
                return device.Capability;
            }
            set
            {
                device.Capability = value;
            }
        }
        public VideoCapabilities[] VideoCapabilities
        {
            get
            {
                return device.VideoCapabilities;
            }
        }
        public float fps
        {
            get
            {
                return device.fps;
            }
        }
        public string MonikerString
        {
            get
            {
                return device.MonikerString;
            }
        }

        public string Name
        {
            get
            {
                return device.Name;
            }
        }
        public static implicit operator VideoDeviceWatcher(VideoDevice obj)
        {
            return obj.GetWatcher();
        }

        //public void Subscribe(object obj, SetImagePtrCallback callback)
        //{
        //    lock (Delegats)
        //    {

        //        Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), obj + " подписался на " + device.Name);
        //        Delegats.Add(new DelegatePairPtr() { sender = obj, Delegate = callback });
        //        //device.StartDevice();
        //        Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Подписано " + Delegats.Count + " объектов");
        //    }
        //    if (Delegats.Count > 0)
        //        device.StartDevice();
        //}
        public static void ReloadCamList()
        {
            Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Получение списка камер ");
         //   Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Было " + VideoDeviceWatcher.watchers.Count);
            VideoDevice.GetInfo().ForEach(p => p.MonikerString.GetWatcher());
        //    Log.LogClass.Enqueue(MethodBase.GetCurrentMethod(), "Стало " + VideoDeviceWatcher.watchers.Count);
        }

        public override void StartDevice()
        {
            device.StartDevice();
        }
        public override void StopDevice()
        {
            device.StopDevice();
        }
        
    }



    static class VideoDeviceWatcherExtention
    {
        public static VideoDeviceWatcher GetWatcher(this VideoDevice device)
        {
            VideoDeviceWatcher result = VideoDeviceWatcher.watchers.FirstOrDefault(p => p.MonikerString == device.MonikerString);
            if (result == null)
            {
                result = new VideoDeviceWatcher(device);
                VideoDeviceWatcher.watchers.Add(result);
            }
            return result;

        }

        public static VideoDeviceWatcher GetWatcher(this string MonikerString)
        {
            VideoDeviceWatcher result = VideoDeviceWatcher.watchers.FirstOrDefault(p => p.MonikerString == MonikerString);
            if (result == null)
            {
                result = new VideoDeviceWatcher(new VideoDevice(MonikerString));
                VideoDeviceWatcher.watchers.Add(result);
            }
            return result;

        }
    }


}
