using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; 

namespace WCS.Core
{
    public abstract class SystemBase: DescriptionClass
    {
        public World World { get; private set; }
        public SystemBase()
        {
            var attr = this.GetType().GetCustomAttribute<BelongToAttribute>(); 
            if (attr != null)
            {
                var wt = attr.WorldType;
                this.World = World.Worlds.Where(v => v.GetType() == wt).First();
            }
        }

        public abstract List<object> GetObjects();
        public abstract void Update(List<WorkTimes> list);
         
    }

   

    public abstract class SystemBase<T> : SystemBase
    { 
        public List<T> Objects { get; set; }
        
        /// <summary>
        /// 对所有Objects并行循环执行Do
        /// </summary>
        protected abstract bool ParallelDo { get; }

        /// <summary>
        /// 保存日志到文件
        /// </summary>
        protected abstract bool SaveLogsToFile { get; }

        public SystemBase()
        {
            Objects = Create();//.Select(v=>Activator.CreateInstance(typeof(T),v)).OfType<T>().ToList();
        }

        public override void Update(List<WorkTimes> list)
        {
            if (ParallelDo)
            {
                Parallel.ForEach(Objects, new ParallelOptions { MaxDegreeOfParallelism = 256 }, obj =>
                {
                    var sw= new Stopwatch();
                    sw.Start();
                    InvokeDo(obj);
                    sw.Stop();
                    list.AddSafe(new WorkTimes { Key = $"{obj?.ToString()}", Total = sw.ElapsedMilliseconds });

                });
            }
            else
            {
                foreach (var obj in Objects)
                {
                    var sw = new Stopwatch();
                    sw.Start();
                    InvokeDo(obj);
                    sw.Stop();
                    list.AddSafe(new WorkTimes { Key = $"{obj?.ToString()}", Total = sw.ElapsedMilliseconds });

                }
            }
         
        }
         
        void InvokeDo(T obj)
        {
            var channel = new Channel
            {
                World = World.Description,
                Stage = "DoLogics",
                System = Description,
                Item = obj.ToString()
            };
            try
            { 
                Ltc.SetChannel(channel);
                World.OnInternalLog(channel, "开始");
                Do(obj);
            } 
            catch (Exception ex)
            {
                World.OnError(channel, ex);
            }
            finally
            {
                World.OnInternalLog(channel, "结束");
                World.Publish();
            }
        }

        public abstract List<T> Create();
        public abstract void Do(T obj);
        public override List<object> GetObjects()
        {
            return Objects.OfType<object>().ToList();
        } 
    }

    public abstract class DeviceSystem<T> : SystemBase<T> where T : EntityEx<Device>
    {
        public override List<T> Create()
        {
            var t = typeof(T);
            while (true)
            {
                if (t.IsGenericType)
                {
                    break;
                }
                t = t.BaseType;
            }

            var types = t.GetGenericArguments();
            var list= Device.All.Where(v => types.All(d => v.HasProtocol(d)))
                .Where(v => Select(v))
                .Select(v => Activator.CreateInstance(typeof(T), v,this.World)).OfType<T>().ToList();//此时才实例化Protocol
            if (list.Count == 0)
            {
                //throw new Exception($"{this.GetType().Name}未匹配到任何Device");
            }
            return list;
        }

        /// <summary>
        /// 筛选出需要实例化Protocol的Device
        /// </summary>
        /// <param name="dev"></param>
        /// <returns></returns>
        public abstract bool Select(Device dev);

        //public abstract List<Device> CreateDevices();
    }


    public abstract class ServiceSystem<T, TR> : SystemBase
    {
        ConcurrentQueue<Action<List<WorkTimes>>> Actions = new ConcurrentQueue<Action<List<WorkTimes>>>();
        public TR Invoke(T obj)
        {
            var flag = false;
            TR result = default(TR);
            Actions.Enqueue(list =>
            {
                var sw = new Stopwatch();
                sw.Start();
                try
                { 
                    result = InvokeDo(obj);
                }
                finally
                {
                    sw.Stop(); 
                    list.AddSafe(new WorkTimes { Key = $"{obj?.ToString()}", Total = sw.ElapsedMilliseconds });
                    flag = true;
                }
            });
            SpinWait.SpinUntil(() => flag);
            return result;
        }
        protected abstract TR Do(T obj);
        public override List<object> GetObjects()
        {
            return new List<object>();
        }

        public override void Update(List<WorkTimes> list)
        { 
            while (Actions.TryDequeue(out var act))
            {
                act(list); 
            }
        }
         
        TR InvokeDo(T obj)
        {
            var channel = new Channel
            {
                World = World.Description,
                Stage = "DoLogics",
                System = Description,
                Item = obj.ToString()
            };
            try
            {
                Ltc.SetChannel(channel);  
                World.OnInternalLog(channel,"开始");
                return Do(obj);
            } 
            catch (Exception ex)
            { 
                throw;
            }
            finally
            {
                World.OnInternalLog(channel, "结束"); 
                World.Publish();
            }
        }
    }

    public abstract class ServiceSystem<T> :SystemBase
    {
        ConcurrentQueue<Action<List<WorkTimes>>> Actions = new ConcurrentQueue<Action<List<WorkTimes>>>();
        public void Invoke(T obj)
        {
            Actions.Enqueue(list =>
            {
                var sw = new Stopwatch();
                sw.Start();
                try
                {
                    InvokeDo(obj);
                }
                finally
                {
                    sw.Stop();
                    list.AddSafe(new WorkTimes { Key = $"{obj?.ToString()}", Total = sw.ElapsedMilliseconds }); 
                }
            });
        }

        protected abstract void Do(T obj);

        void InvokeDo(T obj)
        {
            var channel = new Channel
            {
                World = World.Description,
                Stage = "DoLogics",
                System = Description,
                Item = obj.ToString()
            };
            try
            {
                Ltc.SetChannel(channel);
                World.OnInternalLog(channel, "开始");
                Do(obj);
            }
            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                World.OnInternalLog(channel, "结束");
                World.Publish();
            }
        }

        public override List<object> GetObjects()
        {
            return new List<object>();
        }

        public override void Update(List<WorkTimes> list)
        {
            while (Actions.TryDequeue(out var act))
            {
                act(list);
            }
        }
    }
}
