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;

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

        /// <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 HalfIdx;
        private List<int> maybeIdx = new List<int>();


        /// <summary>
        /// 坏的加热棒
        /// </summary>
        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;
                    }
                }
            }
        }

        /// <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("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)//刚进入!!!
                        {
                            HalfIdx = -1;//可能坏的加热棒中,还没有一条是好的
                            for (int i = 0; i < Bads.Count(); i++)//登记全部坏的加热棒
                            {
                                if (Bads[i])
                                {
                                    maybeIdx.Add(i);
                                }
                            }
                            CheckNo = maybeIdx.First() + 1;//当前检测的位置,现在没用!!!

                            //肯定有2条加热棒是坏了,不用检测maybeIdx.Count()
                            mHeatCell.ModifyPreHeats(getSingleHeat_100(mHeatCell.ChannelCnt,
                                maybeIdx[0],
                                maybeIdx[1]));

                            mHeatCell.HeatApply();
                            counter = 1;
                        }
                        else if (counter < HEAT_WAIT)//3秒延时
                        {
                            counter++;
                        }
                        else//3秒后
                        {
                            if (!HasElectricity)//没电流,肯定是坏了
                            {
                                if (HalfIdx < 0)//还没有一个 "肯定是好的,只是电流不够的加热棒"
                                {
                                    maybeIdx.RemoveRange(0, 2);//之前测试的两条肯定是坏的,不用再查了(这个有bug的)

                                    if (maybeIdx.Count() <= 1)
                                    {
                                        //只剩下一个,没法检测结束
                                        Enable = false;//停止检测
                                        return;
                                    }
                                }
                                else
                                {
                                    //已经有 好的!!!, 刚才测的那条肯定是坏的
                                    maybeIdx.RemoveAt(0);

                                    if (maybeIdx.Count() == 0)
                                    {
                                        //全部检测完了
                                        Enable = false;//停止检测
                                        return;
                                    }
                                }

                                
                                CheckNo = maybeIdx[0] + 1;

                                int idx1 = (HalfIdx >= 0) ? HalfIdx : maybeIdx[1];

                                mHeatCell.ModifyPreHeats(getSingleHeat_100(mHeatCell.ChannelCnt,
                                    maybeIdx[0],
                                    idx1));

                                mHeatCell.HeatApply();
                                counter = 1;
                            }
                            else
                            {
                                //刚才测量的是好的!!!!!
                                if (HalfIdx < 0)//还没有一个 "肯定是好的,只是电流不够的加热棒"
                                {
                                    Bads[maybeIdx[0]] = false;//清除坏的记录
                                    Bads[maybeIdx[1]] = false;
                                    HalfIdx = maybeIdx[0];//登记其中一条好的加热棒
                                    maybeIdx.RemoveRange(0, 2);
                                }
                                else
                                {
                                    Bads[maybeIdx[0]] = false;//清除坏的记录
                                    maybeIdx.RemoveAt(0);
                                }
                                NotifyPropertyChanged("Bads");

                                OpenCircuit = Bads.Any(b => b);

                                if (maybeIdx.Count() <= 0)
                                {
                                    //一个都不剩,完成
                                    Enable = false;//停止检测
                                    return;
                                }

                                CheckNo = maybeIdx[0] + 1;
                                
                                mHeatCell.ModifyPreHeats(getSingleHeat_100(mHeatCell.ChannelCnt,
                                    maybeIdx[0],
                                    HalfIdx));

                                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
    }


}