using FLY.FilmCasting.AutoDie.IService;
using Newtonsoft.Json;
using PropertyChanged;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;

namespace FLY.FilmCasting.AutoDie.Server
{
    /// <summary>
    /// 加热棒检测
    /// </summary>
    class HeatCheck : IHeatCheck, INotifyPropertyChanged
    {
        const int HEAT_WAIT = 3;//3s
        const int HeatsOfGroup = 12;//1块加热板 12路
        HeatCell mHeatCell;

        enum CHECK_MODE
        {
            /// <summary>
            /// 什么都不干
            /// </summary>
            IDLE,
            /// <summary>
            /// 当前0输出，检测电流是否为0
            /// </summary>
            CHECK_ZERO,
            /// <summary>
            /// 当前有输出, 电流不应该为0
            /// </summary>
            CHECK_NOZERO,
            /// <summary>
            /// 检测每根加热棒
            /// </summary>
            CHECK_EVERYONE
        }
        CHECK_MODE checkMode = CHECK_MODE.IDLE;
        int counter = 0;
        #region IHeatCheck

        /// <summary>
        /// 有这个功能
        /// </summary>
        public bool Has { get; set; }

        /// <summary>
        /// 动作使能
        /// </summary>
        public bool Enable { get; set; }

        /// <summary>
        /// 有电流
        /// </summary>
        public bool HasElectricity { get; set; }
        /// <summary>
        /// 当前正在检测的加热棒号， 1~88
        /// </summary>
        public int CheckNo { get; set; }

        /// <summary>
        /// 当前检测的阶段
        /// </summary>
        public int CheckStep { get; set; }

        #region 根据电流判断的加热棒状态
        /// <summary>
        /// 加热棒是好的，但电流小，必须两条同时加热才可以；
        /// 加热棒分组
        /// </summary>
        private int groupIdx;

        private List<GroupBad> groupBads = new List<GroupBad>();
        class GroupBad
        {
            /// <summary>
            /// 分组号
            /// </summary>
            public int group;
            /// <summary>
            /// 在 好的 maybe序号
            /// </summary>
            public int goodIdx = -1;
            /// <summary>
            /// 全部待测的加热棒序号
            /// </summary>
            List<int> maybe = new List<int>();

            /// <summary>
            /// 已经测试过的 maybe序号
            /// </summary>
            List<int> hasCheck = new List<int>();

            /// <summary>
            /// 获取下一个 需要检查的 序号
            /// </summary>
            /// <returns></returns>
            public bool GetNextIdx()
            {
                for (int i = 0; i < maybe.Count(); i++)
                {
                    if (!hasCheck.Contains(i))
                    {
                        //这个没检查过，可以
                        checkIdx1 = i;
                        return true;
                    }
                }
                return false;
            }

            /// <summary>
            /// 同时加热的加热棒0
            /// </summary>
            int checkIdx0;
            /// <summary>
            /// 同时加热的加热棒1
            /// </summary>
            int checkIdx1;

            public int NextCheckIdx
            {
                get { return checkIdx1 + 1; }
            }
            public int HeatIdx0
            {
                get { return maybe[checkIdx0]; }
            }
            public int HeatIdx1
            {
                get { return maybe[checkIdx1]; }
            }

            public bool GetCheckIdx(int startIdx)
            {
                if (startIdx >= maybe.Count() - 1)
                    return false;//不够数


                //同一个组可以一起加热测试
                checkIdx0 = startIdx;
                checkIdx1 = startIdx + 1;
                return true;
            }

            public void PushToHasCheck()
            {
                if (!hasCheck.Contains(checkIdx0))
                    hasCheck.Add(checkIdx0);
                if (!hasCheck.Contains(checkIdx1))
                    hasCheck.Add(checkIdx1);
            }
            public void MarkGoodIdx()
            {
                goodIdx = checkIdx0;
            }
            public bool HasGood
            {
                get
                {

                    return goodIdx != -1;
                }
            }
            public void Add(int heatIdx)
            {
                maybe.Add(heatIdx);
            }
        }
        /// <summary>
        /// 坏的加热棒
        /// </summary>
        public bool[] Bads { get; private set; }


        /// <summary>
        /// 没加热，也有电流, 电路板短路了
        /// </summary>
        public bool ShortCircuit { get; set; }

        /// <summary>
        /// 没有上电, 或者电流计坏了
        /// </summary>
        public bool PowerOff { get; set; }

        /// <summary>
        /// 有加热棒断路了
        /// </summary>
        public bool OpenCircuit { get; set; }
        #endregion

        #endregion

        public void Init(HeatCell heatCell)
        {
            mHeatCell = heatCell;
            FObjBase.PollModule.Current.Poll_Config(FObjBase.PollModule.POLL_CONFIG.ADD, OnPoll, TimeSpan.FromSeconds(1));

            Init();
            Load();

            mHeatCell.PropertyChanged += new PropertyChangedEventHandler(mHeatCell_PropertyChanged);

            this.PropertyChanged += HeatCheck_PropertyChanged;
        }

        private void HeatCheck_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(Enable))
            {
                if (Enable)
                    Start();
                else
                    Stop();
            }
        }

        void mHeatCell_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(mHeatCell.ChannelCnt))
            {
                Init();
                Load();
            }
        }
        void Init()
        {
            Bads = new bool[mHeatCell.ChannelCnt];
            OpenCircuit = false;
            PowerOff = false;
            ShortCircuit = false;
        }
        /// <summary>
        /// 启动
        /// </summary>
        void Start()
        {
            checkMode = CHECK_MODE.CHECK_EVERYONE;
            CheckStep = 0;
            counter = 0;
            Array.Clear(Bads, 0, Bads.Count());
            NotifyPropertyChanged(nameof(Bads));
            OpenCircuit = false;
            PowerOff = false;
            ShortCircuit = false;
        }
        /// <summary>
        /// 停止
        /// </summary>
        void Stop()
        {
            checkMode = CHECK_MODE.IDLE;
            //清空全部加热
            mHeatCell.ClearPreHeats();
            mHeatCell.HeatApply();


            //保存Bads
            Save();
        }
        void Load()
        {
            if (HeatCheckJsonDb.Load(this, "heatCheck.json")) 
            {
                NotifyPropertyChanged(nameof(Bads));
                OpenCircuit = Bads.Any(b => b);
            }
        }
        void Save()
        {
            HeatCheckJsonDb.Save(this, "heatCheck.json");
        }


        void OnPoll()
        {
            switch (checkMode)
            {
                case CHECK_MODE.CHECK_EVERYONE:
                    OnPoll_Check();
                    break;
                default:
                    OnPoll_Normal();
                    break;
            }
        }
        /// <summary>
        /// 平常，测有没电流
        /// </summary>
        void OnPoll_Normal()
        {
            if (!Has)
                return;

            if (mHeatCell.Heats.All(h => h == 0))//没有加热，不应该有电流 
            {
                if (checkMode != CHECK_MODE.CHECK_ZERO) //第1次
                {
                    checkMode = CHECK_MODE.CHECK_ZERO;
                    counter = 0;
                }
                //先等待3秒，3秒后再判断
                counter++;
                if (counter > 5)
                {
                    counter = 0;
                    if (HasElectricity)//有电流，有问题 
                    {
                        ShortCircuit = true;
                    }
                    else
                    {
                        ShortCircuit = false;
                    }
                }
            }
            else
            {
                if (checkMode != CHECK_MODE.CHECK_NOZERO) //第1次
                {
                    checkMode = CHECK_MODE.CHECK_NOZERO;
                    counter = 0;
                }
                if (HasElectricity)
                {
                    counter = 0;
                    PowerOff = false;
                }
                else
                {
                    counter++;
                    if (counter > 7)//连续7秒，都没有一秒有电流，没有上电
                    {
                        PowerOff = true;
                        counter = 0;
                    }
                }
            }
        }

        bool GetCheckIdx_2_loop(int grougIdx_start, int startIdx)
        {
            for (int i = grougIdx_start; i < groupBads.Count(); i++)
            {
                if (groupBads[i].GetCheckIdx(startIdx))
                {
                    groupIdx = i;
                    return true;
                }
                startIdx = 0;
            }
            return false;
        }




        /// <summary>
        /// 加热棒检测周期
        /// </summary>
        void OnPoll_Check()
        {
            switch (CheckStep)
            {
                case 0://刚按了开始，清空，检查应该没电流才对
                    {
                        if (counter == 0)
                        {
                            mHeatCell.ClearPreHeats();
                            mHeatCell.HeatApply();
                            counter++;
                        }
                        else if (counter < HEAT_WAIT)
                        {
                            counter++;
                        }
                        else//3秒后
                        {
                            if (HasElectricity)
                            {
                                ShortCircuit = true;//没输出，也有电流，板烧了
                                Enable = false;//停止检测
                                return;
                            }
                            CheckStep++;
                            counter = 0;
                        }
                    }
                    break;
                case 1://全部加热30%
                    {
                        if (counter == 0)
                        {
                            mHeatCell.ModifyPreHeats(getAllHeat_30(mHeatCell.ChannelCnt));
                            mHeatCell.HeatApply();
                            counter++;
                        }
                        else if (counter < HEAT_WAIT)
                        {
                            if (HasElectricity)
                            {
                                //有上电！！！
                                //正式开始
                                CheckStep++;
                                counter = 0;
                                break;
                            }
                            counter++;
                        }
                        else//3秒内，都没1秒有电，不正常，应该是没上电
                        {
                            PowerOff = true;
                            Enable = false;//停止检测
                            return;
                        }
                    }
                    break;
                case 2://正式开始
                    {
                        if (counter == 0)
                        {
                            CheckNo = 1;
                            mHeatCell.ModifyPreHeats(getSingleHeat_100(mHeatCell.ChannelCnt, CheckNo - 1));
                            mHeatCell.HeatApply();
                            counter = 1;
                        }
                        else if (counter < HEAT_WAIT)
                        {
                            counter++;
                        }
                        else
                        {
                            //3秒后
                            if (!HasElectricity)//这个位没电流,可能是坏了，还需要2次检查
                            {
                                Bads[CheckNo - 1] = true;

                                NotifyPropertyChanged(nameof(Bads));

                                OpenCircuit = true;
                            }
                            if (CheckNo < mHeatCell.ChannelCnt)
                            {
                                CheckNo++;
                                mHeatCell.ModifyPreHeats(getSingleHeat_100(mHeatCell.ChannelCnt, CheckNo - 1));
                                mHeatCell.HeatApply();
                                counter = 1;
                            }
                            else
                            {
                                //检查是否2次检测
                                int cnt = Bads.Count((b) => { return b; });
                                if (cnt < 2)
                                {
                                    //没有坏,或只有一条加热棒坏了，没法2次检测
                                    //完成
                                    Enable = false;//停止检测
                                    return;
                                }
                                else
                                {
                                    //需要2次检测
                                    CheckStep++;
                                    counter = 0;
                                }
                            }
                        }
                    }
                    break;
                case 3://2次检测
                    {
                        if (counter == 0)//刚进入！！！
                        {
                            groupIdx = -1;
                            groupBads.Clear();

                            for (int i = 0; i < Bads.Count(); i++)//分组登记全部坏的加热棒
                            {
                                int group = i / HeatsOfGroup;
                                if (Bads[i])
                                {
                                    if (groupBads.Count() == 0)
                                        groupBads.Add(new GroupBad() { group = group });
                                    else
                                    {
                                        if (groupBads.Last().group != group)
                                        {
                                            groupBads.Add(new GroupBad() { group = group });
                                        }
                                    }
                                    groupBads.Last().Add(i);
                                }
                            }


                            if (!GetCheckIdx_2_loop(0, 0))
                            {
                                //没有两条同一组，测试结束
                                Enable = false;//停止检测
                                return;
                            }
                            var groupBad = groupBads[groupIdx];
                            CheckNo = groupBad.HeatIdx1 + 1;//当前检测的位置，现在没用！！！
                            mHeatCell.ModifyPreHeats(getSingleHeat_100(mHeatCell.ChannelCnt,
                                groupBad.HeatIdx0,
                                groupBad.HeatIdx1));

                            mHeatCell.HeatApply();
                            counter = 1;
                        }
                        else if (counter < HEAT_WAIT)//3秒延时
                        {
                            counter++;
                        }
                        else//3秒后
                        {
                            var groupBad = groupBads[groupIdx];
                            if (!HasElectricity)//没电流,肯定是坏了
                            {
                                if (!groupBad.HasGood)//还没找到好的加热棒
                                {
                                    //继续
                                    if (!GetCheckIdx_2_loop(groupIdx, groupBad.NextCheckIdx))
                                    {
                                        //没有两条同一组，测试结束
                                        Enable = false;//停止检测
                                        return;
                                    }
                                }
                                else
                                {
                                    //checkIdx1是坏的
                                    groupBad.PushToHasCheck();
                                    //获取下一个需要测试的
                                    if (!groupBad.GetNextIdx())
                                    {
                                        //这个分组已经查完，下一个分组
                                        groupIdx++;
                                        if (!GetCheckIdx_2_loop(groupIdx, 0))
                                        {
                                            //没有两条同一组，测试结束
                                            Enable = false;//停止检测
                                            return;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                //刚才测量的是好的！！！！！只是电流不够的加热棒
                                groupBad.MarkGoodIdx(); //找到好的加热棒了，这个组的加热棒全部测试一次
                                groupBad.PushToHasCheck();
                                Bads[groupBad.HeatIdx0] = false;//清除坏的记录
                                Bads[groupBad.HeatIdx1] = false;
                                NotifyPropertyChanged(nameof(Bads));
                                OpenCircuit = Bads.Any(b => b);

                                //获取下一个需要测试的
                                if (!groupBad.GetNextIdx())
                                {
                                    //这个分组已经查完，下一个分组
                                    groupIdx++;
                                    if (!GetCheckIdx_2_loop(groupIdx, 0))
                                    {
                                        //没有两条同一组，测试结束
                                        Enable = false;//停止检测
                                        return;
                                    }
                                }
                            }

                            groupBad = groupBads[groupIdx];
                            CheckNo = groupBad.HeatIdx1 + 1;
                            mHeatCell.ModifyPreHeats(getSingleHeat_100(mHeatCell.ChannelCnt,
                                groupBad.HeatIdx0,
                                groupBad.HeatIdx1));

                            mHeatCell.HeatApply();
                            counter = 1;
                        }
                    }
                    break;
            }

        }

        int[] getSingleHeat_100(int channelcnt, params int[] index)
        {
            int[] heats = new int[channelcnt];
            Array.Clear(heats, 0, heats.Count());
            foreach (int i in index)
                heats[i] = 100;
            return heats;
        }
        int[] getSingleHeat_100(int channelcnt, int index)
        {
            int[] heats = new int[channelcnt];
            Array.Clear(heats, 0, heats.Count());
            heats[index] = 100;
            return heats;
        }
        int[] getAllHeat_30(int channelcnt)
        {
            int[] heats = new int[channelcnt];
            for (int i = 0; i < heats.Count(); i++)
            {
                heats[i] = 30;
            }
            return heats;
        }
        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyname)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }
        #endregion
    }

    class HeatCheckJsonDb
    {
        public bool[] Bads;
        public static bool Load(HeatCheck src, string filePath)
        {
            if (!File.Exists(filePath))
                return false;
            try
            {
                string json = File.ReadAllText(filePath);
                var jsonDb = JsonConvert.DeserializeObject<HeatCheckJsonDb>(json);
                if (jsonDb.Bads != null && jsonDb.Bads.Count()== src.Bads.Count())
                    Array.Copy(jsonDb.Bads, src.Bads, src.Bads.Count());
                return true;
            }
            catch
            {
                //异常，没有json 解码失败
                return true;
            }
        }

        public static bool Save(HeatCheck src, string filePath)
        {
            try
            {
                HeatCheckJsonDb jsonDb = new HeatCheckJsonDb()
                {
                    Bads = src.Bads
                };
                File.WriteAllText(filePath, JsonConvert.SerializeObject(jsonDb, Formatting.Indented));
                return true;
            }
            catch
            {
                //异常，没有json 编码失败

            }
            return false;
        }
    }
}
