using GcDevicePc.IniParam;
using Modbus.Data;
using Modbus.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace GcDevicePc.Common
{
    class NModbusSlave
    {
       private ModbusSlave slave;

        public NModbusSlave()
        {
            listener = new TcpListener(IPAddress.Any, 502);// 端口根据需要确定
            listener.Start();

            slave = ModbusTcpSlave.CreateTcp(1, listener);

            slave.DataStore = DataStoreFactory.CreateDefaultDataStore();

            slave.DataStore.DataStoreWrittenTo += new EventHandler<DataStoreEventArgs>(Modbus_DataStoreWriteTo);

            slave.ModbusSlaveRequestReceived += new EventHandler<ModbusSlaveRequestEventArgs>(Modbus_Request_Event);

            slave.DataStore.DataStoreReadFrom += new EventHandler<DataStoreEventArgs>(DataStore_DataStoreReadFrom);

            slave.DataStore.DataStoreWrittenTo += new EventHandler<DataStoreEventArgs>(DataStore_DataStoreWrittenTo);

            slave.Listen();

            //// 后台线程1：用于接收tcp连接请求，并将网络流加入列表。随主线程的退出而退出。
            //new Thread(() =>
            //{
            //    while (true)
            //    {
            //        Thread.Sleep(100);// 可以根据需要设置时间
            //        if (!listener.Pending())
            //        {
            //            continue;
            //        }
            //        var client = listener.AcceptTcpClient();
            //        // 下面属性根据需要进行设置
            //        // client.ReceiveBufferSize
            //        // client.ReceiveTimeout
            //        // client.SendBufferSize
            //        // client.SendTimeout
            //        if (!client.Connected)
            //        {
            //            continue;
            //        }
            //        streams.Add(client.GetStream());
            //    }
            //})
            //{ IsBackground = true }.Start();

            //// 后台线程2：用于接收请求，并作出响应。随主线程的退出而退出。
            //new Thread(() =>
            //{
            //    while (true)
            //    {
            //        Thread.Sleep(100);// 可以根据需要设置时间
            //        if (streams == null || streams.Count == 0)
            //        {
            //            continue;
            //        }
            //        streams = streams.Where(s => s.CanRead && s.CanWrite).ToList();
            //        foreach (var stream in streams.Where(stream => stream.CanRead && stream.CanWrite))
            //        {
            //            AsyncReceiveBytes(stream,
            //                s =>
            //                {
            //                    // todo:对result进行解码
            //                    // todo:对收到指令进行逻辑判断，得出待响应的C#对象
            //                    AsyncSendBytes(s, new byte[0]); // todo:将待响应的C#对象转换成字节数组，替换new byte[0]。
            //                });
            //        }
            //    }
            //})
            //{ IsBackground = true }.Start();
        }

        public void NModbusSlaveClose()
        {
            //listener.Stop();
            //slave.Dispose();
        }

        ~NModbusSlave()
        {
            listener.Stop();
            slave.Dispose();
        }
        // 发送事件和目标的入口
        //public void SendEventAndTarget()
        //{
        //    if (streams == null || streams.Count == 0)
        //    {
        //        return;
        //    }
        //    streams = streams.Where(s => s.CanRead && s.CanWrite).ToList();
        //    foreach (var stream in streams.TakeWhile(stream => stream.CanWrite))
        //    {
        //        AsyncSendBytes(stream, new byte[0]);// todo:这里将待发送的C#对象转换的字节数组替换new byte[0]。
        //    }
        //}

        //private static void AsyncReceiveBytes(NetworkStream stream,
        //    Action<NetworkStream> callback)
        //{
        //    // 短时后台线程：用于处理网络流的读操作，处理完成后即归还线程池。
        //    // 每个网络流都会分配一个线程。
        //    //ThreadPool.SetMaxThreads();根据需要设置。
        //    ThreadPool.QueueUserWorkItem(delegate
        //    {
        //        var buffer = new byte[1024];// 1024：根据需要进行设置。
        //        var result = new byte[0];
        //        do
        //        {
        //            var a = stream.Read(buffer, 0, buffer.Length);
        //            result = result.Concat(buffer.Take(a)).ToArray();
        //        } while (stream.DataAvailable);
        //        callback(stream);
        //    });
        //}
        //private static void AsyncSendBytes(NetworkStream stream, byte[] bytes)
        //{
        //    // 短时后台线程：用于处理网络流的写操作，处理完成后即归还线程池。
        //    // 每个网络流都会分配一个线程。
        //    //ThreadPool.SetMaxThreads();根据需要设置。
        //    ThreadPool.QueueUserWorkItem(delegate
        //    {
        //        try
        //        {
        //            stream.Write(bytes, 0, bytes.Count());
        //        }
        //        catch (Exception)
        //        {
        //            Console.WriteLine("远程主机主动断开此连接！");// 也可以做其它处理。
        //        }
        //    });
        //}

        private readonly TcpListener listener;
        // 网络流列表
        //private List<NetworkStream> streams = new List<NetworkStream>();

        private void DataStore_DataStoreWrittenTo(object sender, DataStoreEventArgs e)
        {
        }

        private void DataStore_DataStoreReadFrom(object sender, DataStoreEventArgs e)
        {


            //int iAddress = e.StartAddress;
            try
            {
                //if (e.ModbusDataType == ModbusDataType.HoldingRegister)
                //{
                //    //for (int i = 0; i < e.Data.B.Count; i++)
                //    {
                //        //Set AO 
                //        //e.Data.B[i] already write to 
                //        //slave.DataStore.HoldingRegisters[e.StartAddress + i + 1] = slavereadhreg(Convert.ToUInt16(e.StartAddress + i + 1));
                //        //e.StartAddress starts from 0
                //        //You can set AO value to hardware here 
                //    }

                //    slave.DataStore.HoldingRegisters[e.StartAddress + 1] = slavereadhreg(Convert.ToUInt16(e.StartAddress + 1));
                //}

                switch (e.ModbusDataType)
                {
                    case ModbusDataType.HoldingRegister:
                        for (int i = 0; i < e.Data.B.Count; i++)
                        {
                            //Set AO
                            //e.Data.B[i] already write to
                            //slave.DataStore.HoldingRegisters[e.StartAddress + i + 1] = 1;
                            slave.DataStore.HoldingRegisters[e.StartAddress + i + 1] = slavereadhreg(Convert.ToUInt16(e.StartAddress + i + 1)); 
                            //e.StartAddress starts from 0
                            //You can set AO value to hardware here
                        }
                        break;
                    case ModbusDataType.Coil:
                        for (int i = 0; i < e.Data.A.Count; i++)
                        {
                            //set DO
                            //e.Data.A[i] already write to 
                            slave.DataStore.CoilDiscretes[e.StartAddress + i + 1] = slavereadcreg(Convert.ToUInt16(e.StartAddress + i + 1)) == 0 ? false : true;
                            //e.StartAddress starts from 0
                            //You can set DO value to hardware here
                        }
                        break;
                }
            }
            catch
            {


            }

        }


        private void Modbus_DataStoreWriteTo(object sender, DataStoreEventArgs e)
        {
            try
            {
                //if (e.ModbusDataType == ModbusDataType.HoldingRegister)
                //{
                //    //for (int i = 0; i < e.Data.B.Count; i++) 
                //    //{
                //    //    Console.WriteLine("[" + i + "] " + e.Data.B[i]);
                //    //}
                //    slavewirtehreg(e.StartAddress, e.Data.B[e.StartAddress]);
                //}
                switch (e.ModbusDataType)
                {
                    case ModbusDataType.HoldingRegister:
                        slavewirtehreg(e.StartAddress, e.Data.B[e.StartAddress]);
                        break;
                    case ModbusDataType.Coil:

                        break;
                }
            }
            catch
            {

            }
        }

        //trigger Modbus_Request_Event
        private void Modbus_Request_Event(object sender, ModbusSlaveRequestEventArgs e)
        {
            //disassemble packet from master
            //byte fc = e.Message.FunctionCode;
            //byte[] data = e.Message.MessageFrame;
            //byte[] byteStartAddress = new byte[] { data[3], data[2] };
            //byte[] byteNum = new byte[] { data[5], data[4] };
            //Int16 StartAddress = BitConverter.ToInt16(byteStartAddress, 0);
            //Int16 NumOfPoint = BitConverter.ToInt16(byteNum, 0);
            //Console.WriteLine(fc.ToString() + "," + StartAddress.ToString() + "," +
            //NumOfPoint.ToString());
            //Console.WriteLine("asdadas");

        }

        static ushort slavereadhreg(ushort address)
        {
            try
            {
                ushort value = 0;
                ushort signalddress = 17;
                ushort baseaddress = 23;
                address = (ushort)(address - 1);
                int listnum = SharedSpace.Data.listValue.Count;
                if (address >= 17)
                {
                    ushort[] s = new ushort[2];
                    float[] f = new float[2];

                    if (address >= 17 && address <= 22)   //信号输出
                    {
                        if (address == 17 || address == 18)
                            f[0] = float.Parse(globaldata.m_dpbuffer.ShowList.showDet.fDetValue.ToString("0.000"));
                        if (address == 19 || address == 20)
                            f[0] = float.Parse(globaldata.m_dpbuffer.ShowList.showDet.iDetValue.ToString("0.000"));
                        if (address == 21 || address == 22)
                            f[0] = float.Parse(globaldata.m_dpbuffer.ShowList.showDet.bDetValue.ToString("0.000"));
                        Buffer.BlockCopy(f, 2, s, 0, 2);
                        Buffer.BlockCopy(f, 0, s, 2, 2);
                        value = s[(address - signalddress) % 2];
                    }
                    else if (address >= 23 && listnum > 0)  //组分输出
                    {
                        int readnum = (address - baseaddress) / 2;
                        if (readnum <= listnum - 1)
                        {
                            f[0] = float.Parse(SharedSpace.Data.listValue[readnum].vale.ToString());
                            Buffer.BlockCopy(f, 2, s, 0, 2);
                            Buffer.BlockCopy(f, 0, s, 2, 2);
                            value = s[(address - baseaddress) % 2];
                            //value = address;
                        }
                        else
                        {
                            value = 0;
                        }
                    }
                    else
                    {
                        value = 0;
                    }
                }
                //分析仪状态
                if (address >= 1 && address < 20)
                {
                    switch (address)
                    {
                        case 1:   //进度
                            {
                                if ((ushort)SharedSpace.Data.typesint == 1 || (ushort)SharedSpace.Data.typesint == 2)
                                {
                                    if (SharedSpace.MControl.dateend != 0 && SharedSpace.MControl.zhouqi != 0)
                                    {
                                        value = (ushort)((globaldata.m_hmibuffer.gcinfo.batruncount * 1.0f) /
                                                          (ushort)(SharedSpace.MControl.dateend * 1.0f /
                                                                    SharedSpace.MControl.zhouqi) * 1000);
                                    }
                                    else
                                    {
                                        value = 0;
                                    }

                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 2: // 0-正在采样(默认)  1-手动  2-定时  3-校准成功  4-校准失败  5-校准成功(正在采样)  6-校准失败(正在采样)
                            {
                                if (!SharedSpace.MControl.SetOut && !SharedSpace.MControl.SetRun)
                                {
                                    if ((ushort)SharedSpace.Data.typesint == 3)
                                        value = 5;
                                    else if ((ushort)SharedSpace.Data.typesint == 4)
                                        value = 6;
                                    else
                                        value = (ushort)SharedSpace.Data.typesint;
                                }
                                else
                                {
                                    value = (ushort)SharedSpace.Data.typesint;
                                }
                            }
                            break;
                        case 3:
                            {
                                value = SharedSpace.Data.change == true ? (ushort)1 : (ushort)0;
                            }
                            break;
                        case 4:
                            {
                                value = globaldata.m_hmibuffer.gcinfo.HMIMac[0];
                            }
                            break;
                        case 5:
                            {
                                value = globaldata.m_hmibuffer.gcinfo.HMIMac[1];
                            }
                            break;
                        case 6:
                            {
                                value = globaldata.m_hmibuffer.gcinfo.HMIMac[2];
                            }
                            break;
                        case 7: //设备联机状态
                            {
                                value = (ushort)(globaldata.m_hmibuffer.gcinfo.hmioffline ? 1 : 0);
                            }
                            break;
                        case 8: //HMI状态
                            {
                                value = globaldata.m_hmibuffer.gcinfo.methodstatus;
                            }
                            break;
                        case 9: //前进样口
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16InjPortFront == 1)
                                {
                                    value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.FPActualTemp * 10);
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 10: //后进样口
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16InjPortBehind == 1)
                                {
                                    value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.BPActualTemp * 10);
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 11: // 柱箱
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16Col == 1)
                                {
                                    value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.ColActualTemp * 10);
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 12: //前检测器
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16InjPortFront == 1)
                                {
                                    if (CProfileDevice.m_DevParam.syspara.u16DetFrontType == 0)
                                    {
                                        value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.fDetActualTemp * 10);
                                    }
                                    else if (CProfileDevice.m_DevParam.syspara.u16DetFrontType == 1)
                                    {
                                        value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.fDetActualTemp * 10);
                                    }
                                    else
                                    {
                                        value = 0;
                                    }
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 13: //中检测器
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16DetInter == 1)
                                {
                                    if (CProfileDevice.m_DevParam.syspara.u16DetInterType == 0)
                                    {
                                        value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.iDetActualTemp * 10);
                                    }
                                    else if (CProfileDevice.m_DevParam.syspara.u16DetInterType == 1)
                                    {
                                        value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.iDetActualTemp * 10);
                                    }
                                    else
                                    {
                                        value = 0;
                                    }
                                }
                                else if (CProfileDevice.m_DevParam.syspara.u16AuxHeater1 == 1)
                                {
                                    value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.AuxActualTemp1 * 10);
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 14: //后检测器
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16DetBehind == 1)
                                {
                                    if (CProfileDevice.m_DevParam.syspara.u16DetBehindType == 0)
                                    {
                                        value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.bDetActualTemp * 10);
                                    }
                                    else if (CProfileDevice.m_DevParam.syspara.u16DetBehindType == 1)
                                    {
                                        value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.bDetActualTemp * 10);
                                    }
                                    else if (CProfileDevice.m_DevParam.syspara.u16AuxHeater2 == 1)
                                    {
                                        value = (ushort)(globaldata.m_dpbuffer.ShowList.showtemp.AuxActualTemp2 * 10);
                                    }
                                    else
                                    {
                                        value = 0;
                                    }
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 15: //前点火信号
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16DetFrontType == 1)
                                {
                                    value = globaldata.m_dpbuffer.ShowList.showDet.fDetStatue;
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                        case 16: //后点火信号
                            {
                                if (CProfileDevice.m_DevParam.syspara.u16DetInterType == 1)
                                {
                                    value = globaldata.m_dpbuffer.ShowList.showDet.fDetStatue;
                                }
                                else
                                {
                                    value = 0;
                                }
                            }
                            break;
                    }
                }
                return value;
            }
            catch (Exception e)
            {
                Console.WriteLine("异常" + e.Message);
                return 0;
            }

        }

        static void slavewirtehreg(ushort address, ushort value)
        {
            if (address == 100 || address == 99 || address == 101)
            {
                if (value == 1)
                {
                    CurveDisPlay.curdisp.SetAutoAdjust();
                }
                else if (value == 0)
                {
                    CurveDisPlay.curdisp.StopAutoAdjust();
                }
            }

            Log.Info("MoudbusSlave Wirte adder:" + address.ToString() + " value:" + value.ToString());
        }

        public static ushort slavereadcreg(ushort address)
        {

            ushort value = 0;
            switch (address)
            {
                case 16:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[0];
                    break;
                case 17:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[1];
                    break;
                case 18:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[2];
                    break;
                case 19:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[3];
                    break;
                case 20:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[4];
                    break;
                case 21:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[5];
                    break;
                case 22:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[6];
                    break;
                case 23:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[7];
                    break;
                case 24:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[8];
                    break;
                case 25:
                    value = globaldata.m_hmibuffer.gcinfo.TenRelay[9];
                    break;
                default:
                    value = 0;
                    break;
            }
            //   Console.WriteLine("MoudbusSlave Read Holding adder is " + CKVocAnalyzer.GlobalCKV.valueparamlist.ToString());
            return value;


        }
    }

}
