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.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MECF.Framework.Common.Device.PowerSupplier
{
    public class PowerSupplierModbusDevice : JetMessageTcpClient<PowerSupplierTcpModbusMessage, PowerSupplierCommand>
    {
        #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;
        /// <summary>
        /// 电源状态(00-cv输出,01-cc输出)
        /// </summary>
        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";
        /// <summary>
        /// 步阶数据数量
        /// </summary>
        private const int STEP_PERIOD_LENGTH = 6;
        #endregion
        #region 内部变量
        private string _name;
        private string _lastErrorMsg = "";
        #endregion
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public PowerSupplierModbusDevice(string name,string ip, int port) : base(ip, port)
        {
            ReceiveTimeout = 1000;
            SendTimeout = 1000;
            ReconnectInterval = 3000;
            ConnectTimeout = 1000;
            _name = name;
        }
        /// <summary>
        /// 连接
        /// </summary>
        /// <returns></returns>
        public void Start()
        {
            Connect();
        }
        /// <summary>
        /// 设置通道输出开关控制
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="currentValue"></param>
        /// <returns></returns>
        public bool SetChannelOutputSwitchControl(byte channel, bool enabled)
        {
            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 };
            return SetOperation(command);
        }

        /// <summary>
        /// 设置电源控制
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="currentValue"></param>
        /// <returns></returns>
        public bool SetChannelPowerControl(byte channel,byte remoteControl)
        {
            PowerSupplierCommand command = new PowerSupplierCommand();
            command.Channel = channel;
            command.CommandCode = 0x06;
            command.Address = (ushort)(POWER_CONTROL_ADDRESS);
            command.Datas = new ushort[] { remoteControl };
            return SetOperation(command);
        }
        /// <summary>
        /// 设置电源运行模式
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="currentValue"></param>
        /// <returns></returns>
        public bool SetChannelPowerRunmodelControl(byte channel,byte model)
        {
            PowerSupplierCommand command = new PowerSupplierCommand();
            command.Channel = channel;
            command.CommandCode = 0x06;
            command.Address = (ushort)(POWER_RUN_MODEL_ADDRESS);
            command.Datas = new ushort[] { model };
            return SetOperation(command);
        }
        /// <summary>
        /// 设置步阶数据
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="stepDatas"></param>
        public bool SetStepPeriod(byte channel,List<PowerSupplierStepPeriodData> stepDatas,int scale)
        {
            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<stepDatas.Count;i++)
            {
                PowerSupplierStepPeriodData data = stepDatas[i];
                command.Datas[0 + STEP_PERIOD_LENGTH * i] = (ushort)6000;
                command.Datas[1 + STEP_PERIOD_LENGTH * i] = (ushort)Math.Round(stepDatas[i].Current*scale,0);
                command.Datas[2 + STEP_PERIOD_LENGTH * i] = stepDatas[i].Hour;
                command.Datas[3+STEP_PERIOD_LENGTH*i]= stepDatas[i].Minute;
                command.Datas[4+STEP_PERIOD_LENGTH*i]= stepDatas[i].Second;
                command.Datas[5 + STEP_PERIOD_LENGTH * i] = stepDatas[i].Microsecond;
            }
            return SetOperation(command);            
        }
        /// <summary>
        /// 启动步阶
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="startStep"></param>
        /// <param name="endStep"></param>
        /// <param name="cycle"></param>
        public bool StartStepPeriod(byte channel,ushort startStep,ushort endStep,ushort cycle)
        {
            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);
        }

        /// <summary>
        /// 设置电流
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="currentValue"></param>
        /// <returns></returns>
        public bool SetCurrentValue(byte channel,ushort currentValue)
        {
            PowerSupplierCommand command = new PowerSupplierCommand();
            command.Channel = channel;
            command.CommandCode = 0x06;
            command.Address = (ushort)(CURRENT_SETTING_ADDRESS);
            command.Datas = new ushort[] { currentValue };
            return SetOperation(command);
        }

        /// <summary>
        /// 设置电源状态
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="currentValue"></param>
        /// <returns></returns>
        public bool SetChannelPowerStatus(byte channel, byte powerStatus)
        {
            PowerSupplierCommand command = new PowerSupplierCommand();
            command.Channel = channel;
            command.CommandCode = 0x06;
            command.Address = (ushort)(POWER_STATUS_ADDRESS);
            command.Datas = new ushort[] { powerStatus };
            return SetOperation(command);
        }
        /// <summary>
        /// 获取通道输出开关控制
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public void GetChannelOutput(byte channel)
        {
            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));
            ApplyDataOperation(applyCommand);
        }
        /// <summary>
        /// 获取通道电源控制
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public void GetChannelPowerControl(byte channel)
        {
            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));
            ApplyDataOperation(applyCommand);
        }
        /// <summary>
        /// 获取通道电流设置数值
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public void GetChannelCurrentSetting(byte channel)
        {
            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));
            ApplyDataOperation(applyCommand);
        }

        /// <summary>
        /// 获取电源状态设置数值
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public void GetChannelPowerStatus(byte channel)
        {
            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));
            ApplyDataOperation(applyCommand);
        }

        /// <summary>
        /// 获取电源运行模式
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public void GetChannelPowerRunModel(byte channel)
        {
            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));
            ApplyDataOperation(applyCommand);
        }
        /// <summary>
        /// 申请电压和电流数值
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public void GetChannelVoltageAndCurrent(byte channel)
        {
            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));
            ApplyDataOperation(applyCommand);
        }
        /// <summary>
        /// 设置操作
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        private bool SetOperation(PowerSupplierCommand command)
        {
            if (Connected)
            {
                NetResult netResult = SetData(command);
                if (!netResult.IsSuccess)
                {
                    WriteErrMsg($"write write {command.Address.ToString("X2")} value {command.Datas[0]} failed,{netResult.Message}");
                    return false;
                }
                return true;
            }
            else
            {
                NetResult netResult = Connect();
                if(netResult.IsSuccess)
                {
                    netResult = SetData(command);
                    if (!netResult.IsSuccess)
                    {
                        WriteErrMsg($"write {command.Address.ToString("X2")} value {command.Datas[0]} failed,{netResult.Message}");
                        return false;
                    }
                    return true;
                }
                else
                {
                    WriteErrMsg("connect failed");
                    return false;
                }
            }
        }
        /// <summary>
        /// 申请数据操作
        /// </summary>
        /// <param name="command"></param>
        private void ApplyDataOperation(PowerSupplierCommand command)
        {
            if (!Connected)
            {
                NetResult connectResult = Connect();
                if (!connectResult.IsSuccess)
                {
                    WriteErrMsg("connect failed");
                    return;
                }
            }
            NetResult<PowerSupplierCommand> netResult = ApplyData(command);
            if (!netResult.IsSuccess)
            {
                WriteErrMsg($"apply {command.Address.ToString("X2")} failed,{netResult.Message}");
                return;
            }
            if(netResult.Data.Datas!=null)
            {
                Dictionary<string, (int,int)> dictionary = command.Variables;
                List<string> 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] * 0xFFFF + netResult.Data.Datas[result.Item1+1];
                            PowerSupplierDeviceConfigManager.Instance.UpdateModuleVariable(_name, command.Channel, item, value);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 写错误日志
        /// </summary>
        /// <param name="msg"></param>
        private void WriteErrMsg(string msg)
        {
            if (msg!=_lastErrorMsg)
            {
                _lastErrorMsg = msg;

                LOG.WriteLog(eEvent.ERR_POWERSUPPLIER, _name, msg);
            }
        }
    }
}