using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using FLY.FeedbackRenZiJia.IService;
using FLY.FeedbackRenZiJia.Common;
using PropertyChanged;

namespace FLY.FeedbackRenZiJia.Server
{
    /// <summary>
    /// 加热棒检测
    /// </summary>
    class HeatCheck:IHeatCheck,INotifyPropertyChanged
    {
        const int HEAT_WAIT = 3;//3s
        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
        public int HeatsOfGroup { get; set; } = 12;
        /// <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>
        [DoNotCheckEquality]
        public bool[] Bads { get; 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 == "Enable")
            {
                if (Enable)
                    Start();
                else
                    Stop();
            }
        }

        void mHeatCell_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "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("Bads");
            OpenCircuit = false;
            PowerOff = false;
            ShortCircuit = false;
        }
        /// <summary>
        /// 停止
        /// </summary>
        void Stop()
        {
            checkMode = CHECK_MODE.IDLE;
            //清空全部加热
            mHeatCell.ClearPreHeats();
            mHeatCell.HeatApply();


            //保存Bads
            Save();
        }
        void Load() 
        {
            string path = "bads.xml";

            FeedbackHeatsMark mark = FeedbackHeatsMark.Load(path);
            if ((mark != null) && (mark.heats != null))
            {
                for (int i = 0; i < Bads.Count() ; i++)
                {
                    if (i < mark.heats.Count())
                        Bads[i] = ((mark.heats[i] == 0) ? false : true);
                    else
                        Bads[i] = false;
                }
                NotifyPropertyChanged("Bads");

                OpenCircuit = Bads.Any(b => b);
            }
        }
        void Save() 
        {
            string path = "bads.xml";
            FeedbackHeatsMark mark = new FeedbackHeatsMark();
            mark.heats = (from b in Bads select (b) ? 1 : 0).ToArray();
            mark.Save(path);
        }


        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
    }


}