using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using GcDevicePc.ProThread;

namespace GcDevicePc.Common
{
    class MoudbusOperation
    {
        private static MoudbusOperation instance = null;  //静态私有成员变量
        /// <summary>
        /// 单实例对象锁
        /// </summary>
        private static object _lock = new object();

        #region 单实例实现
        public static MoudbusOperation GetInstance()
        {
            if (instance == null)
            {
                lock (_lock)
                {
                    if (instance == null)
                    {
                        instance = new MoudbusOperation();
                    }
                }
            }
            return instance;
        }
        #endregion

        #region 基础参数flag
        private string strIP = null;
     //   private ushort netPost = 0;
        private bool setflag = false;

        /// <summary>
        /// 排序最大参数
        /// </summary>
        private UInt32 fDetMax_Time = 0;

        private int LoseNum = 0;
        #endregion

        #region 转换参数
        private struct stFloat
        {
            public ushort usCurFloat_Word1;
            public ushort usCurFloat_Word2;
        }

        [StructLayout(LayoutKind.Explicit, Size = 8)]
        private struct UNION_FLOAT
        {
            [FieldOffset(0)]
            public float fCurFloat;

            [FieldOffset(0)]
            public stFloat t;
        }

        UNION_FLOAT channel1_value;
        UNION_FLOAT utemp;

        #endregion

        #region 常量
        private const ushort modbus_port = 502;  //modbus端口
        //Modbus地址
        private const ushort temp_start = 100;
        private const ushort temp_num = 24;
        private const ushort status_start = 124;
        private const ushort value_status = 16;
        private const ushort value_num = 4;
        private const ushort tenvalue_status = 16;
        private const ushort tenvalue_num = 10;
        private const ushort detfire_status = 3;
        private const ushort detfire_num= 3;
        private const ushort fireup_status = 155;
        private const ushort fireup_num = 4;
        private const ushort hmi_status = 144;
        private const ushort hmistatus_num = 9;
        private const ushort error_status = 36;
        private const ushort error_num = 9;
        private const ushort channel_start = 160;
        private const ushort channel_num = 120;
        #endregion

        #region 设置函数
        public void SetModbusIP(string ip)
        {
            this.strIP = ip;
            this.setflag = true;
        }
        #endregion


        #region 转换函数
        private void BubbleSort(ref UInt32[] arr, ref float[] value, int len, ushort useflag)
        {
            int i = 0;
            int j = 0;
            int k = len - 1;
            int n = 0;

            for (i = 0; i < len - 1; i++)
            {
                int flag = 1;
                n = 0;

                for (j = 0; j < k; j++)
                {
                    UInt32 tmp = 0;
                    float tmpv = 0.0f;
                    if (arr[j] > arr[j + 1])
                    {
                        tmp = arr[j];
                        tmpv = value[j];

                        arr[j] = arr[j + 1];
                        value[j] = value[j + 1];

                        arr[j + 1] = tmp;
                        value[j + 1] = tmpv;

                        flag = 0;
                        n = j;
                    }
                }
                if (flag == 1)
                    break;
                k = n;
            }

            if (useflag == 0)
            {
                if ((Int32)(arr[0] - fDetMax_Time) < -100000)
                {
                    fDetMax_Time = arr[0];
                }
            }
        }

        internal void GetEPCDataStatus()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region 通用函数
        private int GetHoldingRegFloatTemp(ushort address, ushort num, ref float[] temp)
        {
            UInt16[] dest = new UInt16[num];
            int ret = 0;
            if (setflag)
            {
                ret = globaldata.global_moudbus.ReadHoldingReg(address, num, this.strIP, modbus_port, ref dest);
                if (ret == 0)
                {
                    //实时温度
                    for (int i = 0; i < 12; i += 2)
                    {
                        utemp.t.usCurFloat_Word1 = dest[i];
                        utemp.t.usCurFloat_Word2 = dest[i + 1];
                        temp[i / 2] = utemp.fCurFloat;
                    }

                    //设置温度
                    int no = 6;
                    for (int j = 16; j < 22; j++)
                    {
                        temp[no] = (dest[j]);
                        no++;
                    }
                }
                else
                {
                    Log.Info("读取温度数据失败");
                }
            }
            return ret;
        }

        private int GetHoldingReg(ushort address, ushort num, ref UInt16[] state)
        {
            int ret = -1;
            int count = 0;
            if (setflag)
            {
                ret = globaldata.global_moudbus.ReadHoldingReg(address, num, this.strIP, modbus_port, ref state);
                while (ret != 0)
                {
                    count++;
                    if (count > 3)
                        break;
                    ret = globaldata.global_moudbus.ReadHoldingReg(address, num, this.strIP, modbus_port, ref state);
                }
            }
            return ret;
        }

        private int GetEPCHoldingReg(ushort address, ushort num, ref UInt16[] state)
        {
            int ret = -1;
            int count = 0;
            if (setflag)
            {
                ret = globaldata.global_moudbus.ReadHoldingReg(address, num, this.strIP, modbus_port, ref state);
                while (ret != 0)
                {
                    count++;
                    if (count > 3)
                        break;
                    ret = globaldata.global_moudbus.ReadHoldingReg(address, num, this.strIP, modbus_port, ref state);
                }
            }
            return ret;
        }

        private int GetCoil(ushort address, ushort num, ref byte[] temp)
        {
            int ret = -1;
            if (setflag)
            {
                ret = globaldata.global_moudbus.ReadCoilStatus(address, num, this.strIP, modbus_port, ref temp);
            }
            return ret;
        }


        

        /// <summary>
        /// 获取方法开始时间
        /// </summary>
        /// <returns></returns>
        private UInt32 Get_Method_StartTime()
        {
            UInt32 time = 0;
            UInt32 tmp = 0;
            int ret = 0;
            int count = 0;
            UInt16[] dest = new UInt16[2];

            if (setflag)
            {
                ret = globaldata.global_moudbus.ReadHoldingReg(88, 2, this.strIP, modbus_port, ref dest);
                while (ret != 0)
                {
                    count++;
                    if (count > 3)
                        break;
                    ret = globaldata.global_moudbus.ReadHoldingReg(88, 2, this.strIP, modbus_port, ref dest);
                }
                if (ret == 0)
                {
                    tmp = dest[1];
                    tmp <<= 16;
                    tmp = tmp + dest[0];
                    time = tmp;
                }
                else
                {
                    time = 0;
                }
            }
            return time;
        }

        /// <summary>
        /// 获取方法结束时间
        /// </summary>
        /// <returns></returns>
        private UInt32 Get_Method_EndTime()
        {
            UInt32 time = 0;
            UInt32 tmp = 0;
            int ret = 0;
            int count = 0;
            UInt16[] dest = new UInt16[2];

            if (this.setflag)
            {
                ret = globaldata.global_moudbus.ReadHoldingReg(90, 2, this.strIP, modbus_port, ref dest);
                while (ret != 0)
                {
                    count++;
                    if (count > 3)
                        break;
                    ret = globaldata.global_moudbus.ReadHoldingReg(90, 2, this.strIP, modbus_port, ref dest);
                }

                if (ret == 0)
                {
                    tmp = dest[1];
                    tmp <<= 16;
                    tmp = tmp + dest[0];
                    time = tmp;
                }
                else
                {
                    time = 0;
                }
            }
            return time;
        }

        #endregion


        #region 功能函数
        public void Get_Channel_Data()
        {
            UInt16[] dest = new UInt16[channel_num];

            UInt32[] timev = new UInt32[30];
            float[] fidv = new float[30];

            int ret;
            if (this.setflag)
            {
                ret = globaldata.global_moudbus.ReadHoldingReg(channel_start, channel_num, this.strIP, modbus_port, ref dest);
                if (ret == 0)
                {
                    UInt32 tmp;
                    for (int start = 0, i = 0; start < channel_num;)
                    {
                        tmp = dest[start + 1];
                        tmp <<= 16;
                        tmp = tmp + dest[start];
                        timev[i] = tmp;

                        channel1_value.t.usCurFloat_Word1 = dest[start + 2];
                        channel1_value.t.usCurFloat_Word2 = dest[start + 3];
                        fidv[i] = channel1_value.fCurFloat;
                        start += 4;
                        i++;
                    }
                    BubbleSort(ref timev, ref fidv, channel_num / 4, 0);
                    for (int i = 0; i < channel_num / 4; i++)
                    {
                        tmp = timev[i];

                        if (tmp > fDetMax_Time)
                        {
                            fDetMax_Time = tmp;
                            globaldata.m_signalbuffer.Channel1_Port.ctimer = tmp;
                            globaldata.m_signalbuffer.Channel1_Port.cdata = fidv[i];
                            globaldata.m_dpbuffer.ShowList.showDet.fDetValue = fidv[i] * 1000.0f;


                            globaldata.m_signalbuffer.Draw_Port.Add(globaldata.m_signalbuffer.Channel1_Port);
                        }
                    }
                }
                else
                {
                    Log.Info("读取信号数据失败");
                } 
            }   
        }


        /// <summary>
        /// 读取所有温度
        /// </summary>
        public void GetGCTemp()
        {
            float[] gctemp = new float[12] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            try
            {
                if(GetHoldingRegFloatTemp(temp_start, temp_num, ref gctemp) == 0)
                {
                    globaldata.m_dpbuffer.ShowList.showtemp.FPActualTemp = gctemp[0];
                    globaldata.m_dpbuffer.ShowList.showtemp.BPActualTemp = gctemp[4];
                    globaldata.m_dpbuffer.ShowList.showtemp.FPSetTemp = gctemp[6];
                    globaldata.m_dpbuffer.ShowList.showtemp.BPSetTemp = gctemp[10];
                    globaldata.m_dpbuffer.ShowList.showtemp.ColActualTemp = gctemp[3];
                    globaldata.m_dpbuffer.ShowList.showtemp.ColSetTemp = gctemp[9];

                    //前检测器
                    if (globaldata.m_hwconfig.hwconfiginfo.u16DetFront == 1)
                    {
                        globaldata.m_dpbuffer.ShowList.showtemp.fDetActualTemp = gctemp[1];
                        globaldata.m_dpbuffer.ShowList.showtemp.fDetSetTemp = gctemp[7];
                    }

                    //中检测器
                    if (globaldata.m_hwconfig.hwconfiginfo.u16DetInter == 1)
                    {
                        globaldata.m_dpbuffer.ShowList.showtemp.iDetActualTemp = gctemp[2];
                        globaldata.m_dpbuffer.ShowList.showtemp.iDetSetTemp = gctemp[8];
                    }

                    //后检测器
                    if (globaldata.m_hwconfig.hwconfiginfo.u16DetBehind == 1)
                    {
                        globaldata.m_dpbuffer.ShowList.showtemp.bDetActualTemp = gctemp[5];
                        globaldata.m_dpbuffer.ShowList.showtemp.bDetSetTemp = gctemp[11];
                    }

                    //辅助加热器
                    if (globaldata.m_hwconfig.hwconfiginfo.u16AuxHeaterNum > 0)
                    {
                        //共享中检测器
                        if (globaldata.m_hwconfig.hwconfiginfo.u16AuxHeater1 == 1)  //TCD
                        {
                            globaldata.m_dpbuffer.ShowList.showtemp.AuxActualTemp1 = gctemp[2];
                            globaldata.m_dpbuffer.ShowList.showtemp.AuxSetTemp1 = gctemp[8];
                        }

                        //共享后检测器
                        if (globaldata.m_hwconfig.hwconfiginfo.u16AuxHeater2 == 1)
                        {
                            globaldata.m_dpbuffer.ShowList.showtemp.AuxActualTemp2 = gctemp[5];
                            globaldata.m_dpbuffer.ShowList.showtemp.AuxSetTemp2 = gctemp[11];
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }
        }

        /// <summary>
        /// 读取阀状态
        /// </summary>
        public void GetValveState()
        {
            byte[] valvestate = new byte[4];
            try
            {
                if (GetCoil(value_status, value_num, ref valvestate) == 0)
                {
                    globaldata.m_dpbuffer.ShowList.showValve.u16ValveOne = (((valvestate[0] >> 0) & 0x1) == 1) ? true : false;
                    globaldata.m_dpbuffer.ShowList.showValve.u16ValveTwo = (((valvestate[0] >> 1) & 0x1) == 1) ? true : false;
                    globaldata.m_dpbuffer.ShowList.showValve.u16ValveThree = (((valvestate[0] >> 2) & 0x1) == 1) ? true : false;
                    globaldata.m_dpbuffer.ShowList.showValve.u16ValveFour = (((valvestate[0] >> 3) & 0x1) == 1) ? true : false;
                }
                else
                {
                    Log.Info("阀数据读取失败");
                }
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void GetALLSWState()
        {
            byte[] tenstate = new byte[2] { 0, 0 };
            try
            {
                if (GetCoil(tenvalue_status, tenvalue_num, ref tenstate) == 0)
                {
                    //十路阀
                    for (int i = 0; i < 10; i++)
                    {
                        if (i < 8)
                            globaldata.m_hmibuffer.gcinfo.TenRelay[i] = (byte)((((tenstate[0] >> i) & 0x1) == 1) ? 1 : 0);
                        else
                            globaldata.m_hmibuffer.gcinfo.TenRelay[i] = (byte)((((tenstate[1] >> (i - 8)) & 0x1) == 1) ? 1 : 0);
                    }

                    //扩展阀5，6
                    globaldata.m_dpbuffer.ShowList.showValve.u16ValveFive = (((tenstate[1] >> 1) & 0x1) == 1) ? true : false;
                    globaldata.m_dpbuffer.ShowList.showValve.u16ValveSix = (((tenstate[1] >> 0) & 0x1) == 1) ? true : false;
                }
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }
           
        }

        /// <summary>
        /// 点火状态
        /// </summary>
        public void GetFireState()
        {
            byte[] detstate = new byte[3];
            ushort[] firestate = new ushort[4];
            try
            {
                //开关状态
                if (GetCoil(detfire_status, detfire_num, ref detstate) == 0)
                {
                    globaldata.m_dpbuffer.ShowList.showDet.fDetSwitch = ((((detstate[0] >> 0) & 0x1) == 1) ? true : false);
                }
                else
                {
                    Log.Info("点火获取失败");
                }

                if (GetHoldingReg(fireup_status, fireup_num, ref firestate) == 0)
                {
                    globaldata.m_hmibuffer.gcinfo.FireStatus[0] = firestate[0];
                    globaldata.m_dpbuffer.ShowList.showDet.fDetStatue = firestate[0];
                }
                else
                {
                    Log.Info("点火状态获取失败");
                }
                
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }
        }


        public void GetErrorState()
        {
            byte[] errstate = new byte[2] { 0, 0 };
            try
            {
                if (GetCoil(error_status, error_num, ref errstate) == 0)
                {
                    for (int i = 0; i < error_num; i++)
                    {
                        globaldata.m_hmibuffer.gcinfo.ErrorStatus[i] = (byte)((((errstate[0] >> i) & 0x1) == 1) ? 1 : 0);
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }

        }

        private int GetHMIState(ref ushort[] state)
        {
            int ret = -1;
            try
            {
                ret = GetHoldingReg(hmi_status, hmistatus_num, ref state);

                if (ret != 0)
                {
                    LoseNum++;
                    if (LoseNum > 5)
                    {
                        globaldata.m_hmibuffer.gcinfo.hmioffline = true;
                    }
                }
                else
                {
                    globaldata.m_hmibuffer.gcinfo.hmioffline = false;
                    LoseNum = 0;
                }
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }

            return ret;
        }

        public int GetEPCStatusData(ref ushort[] data)
        {
            int ret = -1;
            try
            {
                ret = GetEPCHoldingReg(700, 16, ref data);
            }
            catch (Exception e)
            {
                Log.Error(e.Message);
            }
            return ret;
        }

        /// <summary>
        /// 获取HMI状态
        /// </summary>
        public void GetHMIStatusData()
        {
            UInt16[] hmistate = new UInt16[9];
            UInt16[] epcdata = new UInt16[16];
            int ret = -1;
            ret = GetHMIState(ref hmistate);

            if (ret == 0)
            {
                globaldata.m_hmibuffer.gcinfo.batno = hmistate[0];
                globaldata.m_hmibuffer.gcinfo.batruncount = hmistate[1];
                globaldata.m_hmibuffer.gcinfo.oneruntime = hmistate[2];
                globaldata.m_hmibuffer.gcinfo.singlerun = hmistate[3];
                globaldata.m_hmibuffer.gcinfo.batrun = hmistate[4];
                globaldata.m_hmibuffer.gcinfo.methodstatus = hmistate[5];
                globaldata.m_hmibuffer.gcinfo.waitstart = hmistate[6];
                globaldata.m_hmibuffer.gcinfo.hmistatus = hmistate[7];
                globaldata.m_hmibuffer.gcinfo.runtime = hmistate[8];

                //额外设置
                globaldata.m_dpbuffer.ShowList.showtime.runtimenow = hmistate[2];
                globaldata.m_dpbuffer.ShowList.showtime.alltime = hmistate[8];

                //获取开始时间
                if (globaldata.m_hmibuffer.gcinfo.methodstatus == 4 || globaldata.m_hmibuffer.gcinfo.methodstatus == 5)
                {
                    globaldata.m_hmibuffer.gcinfo.NowStartTime = Get_Method_StartTime();
                }

                //获取结束时间
                if (globaldata.m_hmibuffer.gcinfo.methodstatus <= 3 || globaldata.m_hmibuffer.gcinfo.methodstatus > 5)
                {
                    globaldata.m_hmibuffer.gcinfo.NowEndTime = Get_Method_EndTime();
                }
            }
            else
            {
                Log.Info("HMI状态获取失败");
            }

            ret = -1;
            ret = GetEPCStatusData(ref epcdata);
            if (ret == 0)
            {
                globaldata.m_hmibuffer.gcinfo.EPCStatus = epcdata;
            }
        }

        #endregion
    }
}
