using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using DocumentFormat.OpenXml.InkML;
using MECF.Framework.Common.CommonData.PowerSupplier;
using MECF.Framework.Common.Communications;
using MECF.Framework.Common.Net;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MECF.Framework.Common.Device.PowerSupplier
{
    public class PowerSupplierSerialPortModbusDevice 
    {
        #region 常量 
        private const short CURRENT_SETTING_ADDRESS = 0x0101;
        private const short OUTPUT_CONTROL_ADDRESS = 0x0110;
        private const short STEP_PERIOD_ADDRESS = 0x1400;
        private const short STEP_PERIOD_START_ADDRESS = 0x1640;
        private const short VOLTAGE_OUTPUT_ADDRESS = 0x0201;
        private const short POWER_CONTROL_ADDRESS = 0x0113;
        private const short POWER_RUN_MODEL_ADDRESS = 0x0111;
        /// 
        /// 电源状态(00-cv输出,01-cc输出)
        /// 
        private const short POWER_STATUS_ADDRESS = 0x0200;
        private const string SET_POINT = "SetPoint";
        private const string CURRENT = "Current";
        private const string VOLTAGE = "Voltage";
        private const string ENABLED = "Enabled";
        private const string POWER_STATUS = "PowerStatus";
        private const string POWER_CONTROL = "PowerControl";
        private const string POWER_RUN_MODEL = "PowerRunModel";
        /// 
        /// 步阶数据数量
        /// 
        private const int STEP_PERIOD_LENGTH = 6;
        #endregion
        #region 内部变量
        private string _name;
        private ConcurrentQueue _commandQueue=new ConcurrentQueue();
        private SerialPort _serialPort;
        private bool _connected;
        private object _locker = new object();
        private int _lockTimeout = 1000;
        private PowerSupplierMessage _netMessage = new PowerSupplierMessage();
        private object _sendLocker = new object();
        private object _receiveLocker = new object();
        private int _receiveTimeout = 1000;
        private int _sendTimeout = 1000;
        /// 
        /// 错误
        /// 
        private string _errmsg;
        /// 
        /// 离线时间
        /// 
        private DateTime _offlineDateTime = DateTime.Now;
        /// 
        /// 是否重连
        /// 
        private bool _reconnect = false;
        /// 
        /// 首次连接成功
        /// 
        private bool _isFirstConnected = false;
        #endregion
        #region 属性
        public bool Connected { get { return _connected; } }
        #endregion
        /// 
        /// 构造函数
        /// 
        /// 
        /// 
        public PowerSupplierSerialPortModbusDevice(string name, string portName, int baudRate = 9600, StopBits stopBits = StopBits.One, int dataBits = 8, Parity parity = Parity.None, bool reconnect = false) 
        {
            _name = name;
            _serialPort = new SerialPort();
            _serialPort.BaudRate = baudRate;
            _serialPort.StopBits = stopBits;
            _serialPort.DataBits = dataBits;
            _serialPort.Parity = parity;
            _serialPort.PortName = portName;
            _serialPort.ReadTimeout = _receiveTimeout;
            _serialPort.WriteTimeout = _sendTimeout;
            _serialPort.ErrorReceived += SerialPort_ErrorReceived;
            _reconnect = reconnect;
            PeriodicJob periodicJob = new PeriodicJob(20, OnTimer, $"{name}.ModbusDevice.Thread", true);
        }
        /// 
        /// 出现错误
        /// 
        /// 
        /// 
        private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            LOG.WriteLog(eEvent.ERR_POWERSUPPLIER, _name, e.EventType.ToString());
        }
        /// 
        /// 定时器
        /// 
        /// 
        private bool OnTimer()
        {
            if (!_connected)
            {
                if (DateTime.Now.Subtract(_offlineDateTime).TotalSeconds >= 5 && _commandQueue.Count != 0)
                {
                    ClearSendQueue();
                }
                if (_reconnect&&_isFirstConnected)
                {
                    Start();
                }
                return true;
            }
            if (_commandQueue.Count!=0)
            {
                if(_commandQueue.TryDequeue(out PowerSupplierCommand command))
                {
                    if (_connected)
                    {
                        if (command.CommandCode == 0x03)
                        {
                            ApplyDataOperation(command);
                        }
                    }
                }
            }
            return true; 
        }
        /// 
        /// 清空发送队列
        /// 
        private void ClearSendQueue()
        {
            try
            {
                while (_commandQueue.Count != 0)
                {
                    _commandQueue.TryDequeue(out var result);
                }
            }
            catch
            {
            }
        }
        /// 
        /// 连接
        /// 
        /// 
        public bool Start()
        {
            if (!_connected)
            {
                try
                {
                    _serialPort.Open();
                    LOG.WriteLog(eEvent.INFO_LINMOT, _name, $"connect port[{_serialPort.PortName}] success");
                    _connected = true;
                    if(!_isFirstConnected)
                    { 
                        _isFirstConnected = true;
                    }
                    return true;
                }
                catch (Exception ex)
                {                   
                    return false;
                }
            }
            return true;
        }
        /// 
        /// 设置通道输出开关控制
        /// 
        /// 
        /// 
        /// 
        public void SetChannelOutputSwitchControl(byte channel, bool enabled)
        {
            if (Connected)
            {
                PowerSupplierCommand command = new PowerSupplierCommand();
                command.Channel = channel;
                command.CommandCode = 0x06;
                command.Address = (ushort)(OUTPUT_CONTROL_ADDRESS);
                command.Datas = new ushort[] { enabled ? (ushort)01 : (ushort)00 };
                SetOperation(command);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 设置电源控制
        /// 
        /// 
        /// 
        /// 
        public void SetChannelPowerControl(byte channel,byte remoteControl)
        {
            if (Connected)
            {
                PowerSupplierCommand command = new PowerSupplierCommand();
                command.Channel = channel;
                command.CommandCode = 0x06;
                command.Address = (ushort)(POWER_CONTROL_ADDRESS);
                command.Datas = new ushort[] { remoteControl };
                SetOperation(command);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 设置电源运行模式
        /// 
        /// 
        /// 
        /// 
        public void SetChannelPowerRunmodelControl(byte channel,byte model)
        {
            if (Connected)
            {
                PowerSupplierCommand command = new PowerSupplierCommand();
                command.Channel = channel;
                command.CommandCode = 0x06;
                command.Address = (ushort)(POWER_RUN_MODEL_ADDRESS);
                command.Datas = new ushort[] { model };
                SetOperation(command);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 设置步阶数据
        /// 
        /// 
        /// 
        public bool SetStepPeriod(byte channel,List stepDatas,int scale)
        {
            if(Connected)
            {
                PowerSupplierCommand command = new PowerSupplierCommand();
                command.Channel = channel;
                command.CommandCode = 0x10;
                command.Address = (ushort)STEP_PERIOD_ADDRESS;
                command.RegisterCount =(ushort)(STEP_PERIOD_LENGTH * stepDatas.Count);
                command.Datas = new ushort[STEP_PERIOD_LENGTH * stepDatas.Count];
                for(int i = 0;i
        /// 启动步阶
        /// 
        /// 
        /// 
        /// 
        /// 
        public bool StartStepPeriod(byte channel,ushort startStep,ushort endStep,ushort cycle)
        {
            if (Connected)
            {
                PowerSupplierCommand command = new PowerSupplierCommand();
                command.Channel = channel;
                command.CommandCode = 0x10;
                command.Address = (ushort)STEP_PERIOD_START_ADDRESS;
                command.RegisterCount = 3;
                command.Datas = new ushort[3] { startStep,endStep,cycle };
                return SetOperation(command);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
            return false;
        }
        /// 
        /// 设置电流
        /// 
        /// 
        /// 
        /// 
        public void SetCurrentValue(byte channel,ushort currentValue)
        {
            if (Connected)
            {
                PowerSupplierCommand command = new PowerSupplierCommand();
                command.Channel = channel;
                command.CommandCode = 0x06;
                command.Address = (ushort)(CURRENT_SETTING_ADDRESS);
                command.Datas = new ushort[] { currentValue };
                SetOperation(command);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 设置电源状态
        /// 
        /// 
        /// 
        /// 
        public void SetChannelPowerStatus(byte channel, byte powerStatus)
        {
            if (Connected)
            {
                PowerSupplierCommand command = new PowerSupplierCommand();
                command.Channel = channel;
                command.CommandCode = 0x06;
                command.Address = (ushort)(POWER_STATUS_ADDRESS);
                command.Datas = new ushort[] { powerStatus };
                SetOperation(command);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 获取通道输出开关控制
        /// 
        /// 
        /// 
        public void GetChannelOutput(byte channel)
        {
            if (Connected)
            {
                PowerSupplierCommand applyCommand = new PowerSupplierCommand();
                applyCommand.Channel = channel;
                applyCommand.CommandCode = 0x03;
                applyCommand.Address = (ushort)(OUTPUT_CONTROL_ADDRESS);
                applyCommand.RegisterCount = 1;
                applyCommand.Variables.Add(ENABLED,(0,1));
                _commandQueue.Enqueue(applyCommand);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 获取通道电源控制
        /// 
        /// 
        /// 
        public void GetChannelPowerControl(byte channel)
        {
            if (Connected)
            {
                PowerSupplierCommand applyCommand = new PowerSupplierCommand();
                applyCommand.Channel = channel;
                applyCommand.CommandCode = 0x03;
                applyCommand.Address = (ushort)(POWER_CONTROL_ADDRESS);
                applyCommand.RegisterCount = 1;
                applyCommand.Variables.Add(POWER_CONTROL, (0, 1));
                _commandQueue.Enqueue(applyCommand);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 获取通道电流设置数值
        /// 
        /// 
        /// 
        public void GetChannelCurrentSetting(byte channel)
        {
            if (Connected)
            {
                PowerSupplierCommand applyCommand = new PowerSupplierCommand();
                applyCommand.Channel = channel;
                applyCommand.CommandCode = 0x03;
                applyCommand.Address = (ushort)(CURRENT_SETTING_ADDRESS);
                applyCommand.RegisterCount = 1;
                applyCommand.Variables.Add(SET_POINT,(0,1));
                _commandQueue.Enqueue(applyCommand);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 获取电源状态设置数值
        /// 
        /// 
        /// 
        public void GetChannelPowerStatus(byte channel)
        {
            if (Connected)
            {
                PowerSupplierCommand applyCommand = new PowerSupplierCommand();
                applyCommand.Channel = channel;
                applyCommand.CommandCode = 0x03;
                applyCommand.Address = (ushort)(POWER_STATUS_ADDRESS);
                applyCommand.RegisterCount = 1;
                applyCommand.Variables.Add(POWER_STATUS, (0,1));
                _commandQueue.Enqueue(applyCommand);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 获取电源运行模式
        /// 
        /// 
        /// 
        public void GetChannelPowerRunModel(byte channel)
        {
            if (Connected)
            {
                PowerSupplierCommand applyCommand = new PowerSupplierCommand();
                applyCommand.Channel = channel;
                applyCommand.CommandCode = 0x03;
                applyCommand.Address = (ushort)(POWER_RUN_MODEL_ADDRESS);
                applyCommand.RegisterCount = 1;
                applyCommand.Variables.Add(POWER_RUN_MODEL, (0, 1));
                _commandQueue.Enqueue(applyCommand);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 申请电压和电流数值
        /// 
        /// 
        /// 
        public void GetChannelVoltageAndCurrent(byte channel)
        {
            if (Connected)
            {
                PowerSupplierCommand applyCommand = new PowerSupplierCommand();
                applyCommand.Channel = channel;
                applyCommand.CommandCode = 0x03;
                applyCommand.Address = (ushort)(VOLTAGE_OUTPUT_ADDRESS);
                applyCommand.RegisterCount = 4;
                applyCommand.Variables.Add(VOLTAGE,(0,2));
                applyCommand.Variables.Add(CURRENT,(2,2));
                _commandQueue.Enqueue(applyCommand);
            }
            else
            {
                WriteErrorMsg($"{_name} is not connected");
            }
        }
        /// 
        /// 设置操作
        /// 
        /// 
        /// 
        private bool SetOperation(PowerSupplierCommand command)
        {
            NetResult netResult = SetData(command);
            if (!netResult.IsSuccess)
            {
                LOG.WriteLog(eEvent.ERR_POWERSUPPLIER, _name, $"write value {command.Datas[0]} failed,{netResult.Message}");
                return false;
            }
            return true;
        }
        /// 
        /// 设置数据
        /// 
        /// 
        /// 
        /// 
        public NetResult SetData(PowerSupplierCommand data)
        {
            if (Monitor.TryEnter(_locker, _lockTimeout))
            {
                NetResult result = ReadFromServer(data);
                if (!result.IsSuccess)
                {
                    Monitor.Exit(_locker);
                    return NetResult.CreateFailedResult(result.ErrorCode, result.Message);
                }
                bool confirmResult = _netMessage.ConfirmResponseResult();
                if (!confirmResult)
                {
                    Monitor.Exit(_locker);
                    return NetResult.CreateFailedResult(_netMessage.ErrorCode, _netMessage.ErrorMsg);
                }
                Monitor.Exit(_locker);
                return NetResult.CreateSuccessResult();
            }
            else
            {
                return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
            }
        }
        /// 
        /// 从服务端读取数据
        /// 
        /// 
        /// 
        /// 
        private NetResult ReadFromServer(PowerSupplierCommand data)
        {
            byte[] buffer = _netMessage.Code(data);
            NetResult sendResult = Send(buffer);
            if (!sendResult.IsSuccess)
            {
                return NetResult.CreateFailedResult(sendResult.ErrorCode, sendResult.Message);
            }
            _netMessage.SendBytes = buffer;
            _netMessage.SetProtocolHeadBytesLength();
            NetResult headerResult = Receive(_netMessage.ProtocolHeadBytesLength);
            if (!headerResult.IsSuccess)
            {
                return NetResult.CreateFailedResult(headerResult.ErrorCode, headerResult.Message);
            }
            _netMessage.HeadBytes = headerResult.Data;
            if (!_netMessage.CheckHeadBytesLegal())
            {
                return NetResult.CreateFailedResult(NetErrorCode.InvalidHeader);
            }
            NetResult contentResult = Receive(_netMessage.GetContentLengthByHeadBytes());
            if (!contentResult.IsSuccess)
            {
                return NetResult.CreateFailedResult(contentResult.ErrorCode, contentResult.Message);
            }
            _netMessage.ContentBytes = contentResult.Data;
            bool dataValid = _netMessage.CheckDataLegal();
            if (!dataValid)
            {
                return NetResult.CreateFailedResult(_netMessage.ErrorCode, _netMessage.ErrorMsg);
            }
            return NetResult.CreateSuccessResult();
        }
        /// 
        /// 申请数据操作
        /// 
        /// 
        private void ApplyDataOperation(PowerSupplierCommand command)
        {
            NetResult netResult = ApplyData(command);
            if (!netResult.IsSuccess)
            {
                List keys = command.Variables.Keys.ToList();
                string str = String.Join(" ", keys);
                WriteErrorMsg($"apply {str} error");
                return;
            }
            if(netResult.Data.Datas!=null)
            {
                Dictionary dictionary = command.Variables;
                List keys = dictionary.Keys.ToList();
                foreach(string item in keys)
                {
                    var result = dictionary[item];
                    if(item==ENABLED)
                    {
                        PowerSupplierDeviceConfigManager.Instance.UpdateModuleVariable(_name, command.Channel, ENABLED, netResult.Data.Datas[result.Item1] == 0x01);
                    }
                    else
                    {
                        if(result.Item2==1)
                        {
                            PowerSupplierDeviceConfigManager.Instance.UpdateModuleVariable(_name, command.Channel, item, netResult.Data.Datas[result.Item1]);
                        }
                        else if(result.Item2==2)
                        {
                            int value = netResult.Data.Datas[result.Item1] * 255 + netResult.Data.Datas[result.Item1+1];
                            PowerSupplierDeviceConfigManager.Instance.UpdateModuleVariable(_name, command.Channel, item, value);
                        }
                    }
                }
            }
        }
        /// 
        /// 申请数据
        /// 
        /// 申请指令类型
        /// 指令对象
        /// 返回数据对象
        public NetResult ApplyData(PowerSupplierCommand data)
        {
            if (Monitor.TryEnter(_locker, _lockTimeout))
            {
                NetResult result = ReadFromServer(data);
                if (!result.IsSuccess)
                {
                    Monitor.Exit(_locker);
                    return NetResult.CreateFailedResult(result.ErrorCode, result.Message);
                }
                Monitor.Exit(_locker);
                return NetResult.CreateSuccessResult(_netMessage.Decode());
            }
            else
            {
                return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
            }
        }
        /// 
        /// 发送数据
        /// 
        /// 
        /// 
        public NetResult Send(byte[] data)
        {
            if (!Connected)
            {
                return NetResult.CreateFailedResult(NetErrorCode.NetOffline);
            }
            //清除缓存数据
            ClearPreData();
            //进入发送
            if (Monitor.TryEnter(_sendLocker, _sendTimeout))
            {
                if (_serialPort == null)
                {
                    return NetResult.CreateFailedResult(NetErrorCode.NullSocketObject);
                }
                try
                {
                    _serialPort.Write(data,0,data.Length);
                    Monitor.Exit(_sendLocker);
                    return NetResult.CreateSuccessResult();
                }
                catch (Exception ex)
                {
                    Monitor.Exit(_sendLocker);
                    WriteErrorMsg(ex.Message);
                    return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
                }
            }
            else
            {
                return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
            }
        }
        /// 
        /// 接收数据
        /// 
        /// 
        /// 
        public NetResult Receive(int length)
        {
            if (!Connected)
            {
                return NetResult.CreateFailedResult(NetErrorCode.NetOffline);
            }
            if (Monitor.TryEnter(_receiveLocker, _receiveTimeout))
            {
                if (_serialPort == null)
                {
                    return NetResult.CreateFailedResult(NetErrorCode.NullSocketObject);
                }
                try
                {
                    byte[] buffer = new byte[length];
                    DateTime dt = DateTime.Now;
                    while(true)
                    {
                        if(_serialPort.BytesToRead>=length)
                        {
                            _serialPort.Read(buffer, 0, length);
                            break;
                        }
                        if(DateTime.Now.Subtract(dt).TotalMilliseconds>=_receiveTimeout)
                        {
                            Monitor.Exit(_receiveLocker);
                            return NetResult.CreateFailedResult(NetErrorCode.ReceiveTimeout);
                        }
                    }
                    Monitor.Exit(_receiveLocker);
                    return NetResult.CreateSuccessResult(buffer);
                }
                catch (SocketException ex)
                {
                    Monitor.Exit(_receiveLocker);
                    return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
                }
                catch (Exception ex)
                {
                    Monitor.Exit(_receiveLocker);
                    return NetResult.CreateFailedResult((int)NetErrorCode.InnerException, ex.Message);
                }
            }
            else
            {
                return NetResult.CreateFailedResult(NetErrorCode.GetLockTimeout);
            }
        }
        /// 
        /// 清除先前的数据
        /// 
        public void ClearPreData()
        {
            if (!Connected)
            {
                return;
            }
            if (Monitor.TryEnter(_receiveLocker, _receiveTimeout))
            {
                try
                {
                    while (_serialPort.BytesToRead != 0)
                    {
                        byte[] buffer = new byte[_serialPort.BytesToRead];
                        _serialPort.Read(buffer,0, buffer.Length);
                    }
                    Monitor.Exit(_receiveLocker);
                }
                catch (SocketException ex)
                {
                    Monitor.Exit(_receiveLocker);
                }
                catch (Exception ex)
                {
                    Monitor.Exit(_receiveLocker);
                }
            }
        }
        /// 
        /// 记录错误信息
        /// 
        /// 
        private void WriteErrorMsg(string msg, bool disConnected = true)
        {
            if (disConnected)
            {
                _connected = false;
                _offlineDateTime = DateTime.Now;
            }
            if (_errmsg != msg)
            {
                _errmsg = msg;
                LOG.WriteLog(eEvent.ERR_POWERSUPPLIER, _name, msg);
            }
        }
    }
}