using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Beckhoff.ModuleIO;
using MECF.Framework.Common.CommonData.Transporter;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.ToolLayout;
using MECF.Framework.Common.TwinCat;
using CyberX8_Core;
using CyberX8_RT.Devices.AXIS;
using CyberX8_RT.Devices.AXIS.CANOpen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using CyberX8_RT.Devices.BarcodeReader;
using MECF.Framework.Common.IOCore;

namespace CyberX8_RT.Devices.TransPorter
{
    
    public class TransporterCommon : BaseDevice, IDevice
    {
        private enum TransporterCommonOperation
        {
            None=0,
            Lock=1,
            Unlock=2,
            Retract=3,
            Extend=4
        }
        #region 常量
        private const string UNLOCK = "Unlock";
        private const string LOCKED1 = "Locked1";
        private const string LOCKED2 = "Locked2";
        private const string UNLOCKED1 = "Unlocked1";
        private const string UNLOCKED2 = "Unlocked2";
        private const string IMMOBILIZE_ACTIVE = "ImmobilizeActive";
        private const string IMMOBILIZE_ACTIVE2 = "ImmobilizeActive2";
        private const string IMMOBILIZE_RETRACTED1 = "ImmobilizeRetracted1";
        private const string IMMOBILIZE_RETRACTED2 = "ImmobilizeRetracted2";
        private const string IMMOBILIZE_EXTEND1 = "ImmobilizeExtended1";
        private const string IMMOBILIZE_EXTEND2= "ImmobilizeExtended2";
        private const string READY_TO_LOCK1 = "ReadyToLock1";
        private const string READY_TO_LOCK2 = "ReadyToLock2";
        private const string WH_PRESENT1 = "WhPresent1";
        private const string WH_PRESENT2 = "WhPresent2";
        private const string TRANSPORTER_DATA = "TransporterData";

        private const string LOCK = "Lock";
        private const string WSHOLDPRESENT = "WSHoldPresent";
        #endregion

        #region 内部变量
        private TransporterData _transporterData = new TransporterData();
        /// <summary>
        /// 状态
        /// </summary>
        private RState _status;
        /// <summary>
        /// 当前操作
        /// </summary>
        private TransporterCommonOperation _currentOperation;
        /// <summary>
        /// unlock后自动lock时长
        /// </summary>
        private int _unlockTimerLockInterval = 20;
        /// <summary>
        /// unlock时间
        /// </summary>
        private DateTime _unlockDateTime = DateTime.Now;
        #region Routine
        /// <summary>
        /// Retract Routine
        /// </summary>
        private TransporterRetractRoutine _retractRoutine;
        /// <summary>
        /// Extend Routine
        /// </summary>
        private TransporterExtendRoutine _extendRoutine;
        /// <summary>
        /// barcodeReaderName
        /// </summary>
        private string _barcodeReaderName;
        /// <summary>
        /// 条码读取器
        /// </summary>
        private BarcodeReaderController _barcodeReader;
        #endregion

        #endregion

        #region 属性
        /// <summary>
        /// 数据
        /// </summary>
        public TransporterData TransporterData { get { return _transporterData; } }
        #endregion
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="moduleName"></param>
        public TransporterCommon(string moduleName) : base(moduleName, "Common", "Common", "Common")
        {
            TransporterItem transporterItem = TransporterItemManager.Instance.GetTransporterItem(moduleName);
            if(transporterItem != null)
            {
                _barcodeReaderName =transporterItem.BarcodeReader;
            }
        }
        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns></returns>
        public bool Initialize()
        {
            InitializeData();
            SubscribeValueAction();
            InitializeRoutine();
            InitializeOperation();
            return true;
        }
        /// <summary>
        /// 初始化数据
        /// </summary>
        private void InitializeData()
        {
            DATA.Subscribe($"{Module}.{TRANSPORTER_DATA}", () => _transporterData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.BarcodeReader", () => _barcodeReaderName, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.WSPresent1", ()=>_transporterData.WhPresent1, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.WSPresent2", () => _transporterData.WhPresent2, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ImmobilizeActive1", () => _transporterData.ImmobilizeActive, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ImmobilizeActive2", () => _transporterData.ImmobilizeActive2, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ImmobilizeRetracted1", () => _transporterData.ImmobilizeRetracted1, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ImmobilizeRetracted2", () => _transporterData.ImmobilizeRetracted2, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ImmobilizeExtended1", () => _transporterData.ImmobilizeExtended1, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ImmobilizeExtended2", () => _transporterData.ImmobilizeExtended2, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.Locked1", () => _transporterData.Locked1, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.Locked2", () => _transporterData.Locked2, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ReadyToLock1", () => _transporterData.ReadyToLock1, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.ReadyToLock2", () => _transporterData.ReadyToLock2, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.Unlocked1", () => _transporterData.Unlocked1, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.Unlocked2", () => _transporterData.Unlocked2, SubscriptionAttribute.FLAG.IgnoreSaveDB);

            DATA.Subscribe($"{Module}.Locked", () => _transporterData.Lock, SubscriptionAttribute.FLAG.IgnoreSaveDB);
            DATA.Subscribe($"{Module}.WSHoldPresent", () => _transporterData.WSHoldPresent, SubscriptionAttribute.FLAG.IgnoreSaveDB);
        }
        /// <summary>
        /// 订阅变量数值发生变化
        /// </summary>
        private void SubscribeValueAction()
        {
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", UNLOCK, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", LOCKED1, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", LOCKED2, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", UNLOCKED1, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", UNLOCKED2, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", IMMOBILIZE_ACTIVE, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", IMMOBILIZE_ACTIVE2, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", IMMOBILIZE_RETRACTED1, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", IMMOBILIZE_RETRACTED2, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", IMMOBILIZE_EXTEND1, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", IMMOBILIZE_EXTEND2, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", READY_TO_LOCK1, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", READY_TO_LOCK2, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", WH_PRESENT1, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", WH_PRESENT2, UpdateVariableValue);

            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", LOCK, UpdateVariableValue);
            IOModuleManager.Instance.SubscribeModuleVariable($"{Module}", WSHOLDPRESENT, UpdateVariableValue);
        }
        /// <summary>
        /// 初始化操作
        /// </summary>
        private void InitializeOperation()
        {
            OP.Subscribe($"{Module}.Lock", LockOperation);
            OP.Subscribe($"{Module}.Unlock", UnlockOperation);
            OP.Subscribe($"{Module}.Retract", RetractOperation);
            OP.Subscribe($"{Module}.Extend", ExtendOperation);
        }

        /// <summary>
        /// 更新变量数值
        /// </summary>
        /// <param name="variable"></param>
        /// <param name="value"></param>
        private void UpdateVariableValue(string variable, object value)
        {
            PropertyInfo property = TransporterData.GetType().GetProperty(variable);
            if (property != null)
            {
                property.SetValue(TransporterData, value);
            }

            if(TransporterData.Unlock)
            {
                _unlockDateTime = DateTime.Now;
            }
        }
        /// <summary>
        /// 初始化Routine
        /// </summary>
        private void InitializeRoutine()
        {
            _retractRoutine= new TransporterRetractRoutine(Module);
            _extendRoutine=new TransporterExtendRoutine(Module);
        }
        #region 指令 
        /// <summary>
        /// Lock 操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public bool LockOperation(string cmd, object[] args)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{LOCK}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, true);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Unlock 操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public bool UnlockOperation(string cmd, object[] args)
        {
            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{LOCK}");
            if (!string.IsNullOrEmpty(ioName))
            {
                return IOModuleManager.Instance.WriteIoValue(ioName, false);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Retract 操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private bool RetractOperation(string cmd , object[] args)
        {
            JetAxisBase elevatorAxis = DEVICE.GetDevice<JetAxisBase>($"{Module}.Elevator");
            if (elevatorAxis!=null && !elevatorAxis.CurrentStation.Contains("UP"))
            {
                LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{Module}.Elevator is not in 'UP' Postion,Can not do Retract Action");
                return false;
            }
            return StartRoutine(TransporterCommonOperation.Retract, _retractRoutine, null);
        }
        /// <summary>
        /// Extend 操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private bool ExtendOperation(string cmd , object[] args)
        {
            JetAxisBase elevatorAxis = DEVICE.GetDevice<JetAxisBase>($"{Module}.Elevator");
            if (elevatorAxis != null && !elevatorAxis.CurrentStation.Contains("UP"))
            {
                LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{Module}.Elevator is not in 'UP' Postion,Can not do Extend Action");
                return false;
            }
            return StartRoutine(TransporterCommonOperation.Extend, _extendRoutine, null);
        }
        /// <summary>
        /// 启动Routine
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        private bool StartRoutine(TransporterCommonOperation operation,IRoutine routine,object obj)
        {
            if (!JudgeRunningState(operation))
            {
                _currentOperation = operation;
                _status = routine.Start(obj);
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 判定运行状态
        /// </summary>
        /// <returns></returns>
        private bool JudgeRunningState(TransporterCommonOperation operation)
        {
            if (_status == RState.Running)
            {
                LOG.WriteLog(eEvent.ERR_TRANSPORTER,Module, $"{Module} current execute {_currentOperation},cannot {operation}");
                return true;
            }
            return false;
        }
        #endregion
        /// <summary>
        /// 读取条码
        /// </summary>
        /// <returns></returns>
        public string ReaderBarcode()
        {
            _barcodeReader = DEVICE.GetDevice<BarcodeReaderController>(_barcodeReaderName);
            if (_barcodeReader != null)
            {
                return _barcodeReader.ReadBarcode();
            }
            return "";
        }

        /// <summary>
        /// 定时器
        /// </summary>
        /// <returns></returns>
        public bool OnTimer()
        {
            if (_status == RState.Running)
            {
                if (_currentOperation != TransporterCommonOperation.None)
                {
                    IRoutine routine = GetCurrentRoutine(_currentOperation);
                    if (routine != null)
                    {
                        CheckRoutineState(routine, _currentOperation);
                    }
                    else
                    {
                        EndOperation();
                    }
                }
            }

            if (SC.ContainsItem($"Transporter.{Module}.UnlockTimerLock"))
            {
                _unlockTimerLockInterval = SC.GetValue<int>($"Transporter.{Module}.UnlockTimerLock") * 1000;
            }
            if(TransporterData.Unlock)
            {
                if(DateTime.Now.Subtract(_unlockDateTime).TotalMilliseconds>=_unlockTimerLockInterval)
                {
                    string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{UNLOCK}");
                    if (!string.IsNullOrEmpty(ioName))
                    {
                        IOModuleManager.Instance.WriteIoValue(ioName, false);
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// 获取当前操作对应的Routine
        /// </summary>
        /// <param name="currentOperation"></param>
        /// <returns></returns>
        private IRoutine GetCurrentRoutine(TransporterCommonOperation currentOperation)
        {
            switch (currentOperation)
            {
                case TransporterCommonOperation.Retract:
                    return _retractRoutine;
                case TransporterCommonOperation.Extend:
                    return _extendRoutine;
                default:
                    return null;
            }
        }
        /// <summary>
        /// 检验Routine状态
        /// </summary>
        /// <param name="routine"></param>
        /// <param name="currentOperation"></param>
        private void CheckRoutineState(IRoutine routine, TransporterCommonOperation currentOperation)
        {
            RState state = routine.Monitor();
            if (state == RState.End)
            {
                EndOperation();
            }
            else if (state == RState.Failed || state == RState.Timeout)
            {
                LOG.WriteLog(eEvent.ERR_TRANSPORTER, $"{Module}.{Name}", $"{currentOperation} error");
                EndOperation();
            }
        }
        /// <summary>
        /// 结束操作
        /// </summary>
        private void EndOperation()
        {
            _status = RState.End;
            _currentOperation = TransporterCommonOperation.None;
        }

        #region 设备接口
        public void Monitor()
        {
        }

        public void Reset()
        {
        }

        public void Terminate()
        {
        }
        #endregion
    }
}