using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Beckhoff.Station;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Layout;
using CyberX8_Core;
using CyberX8_RT.Devices.AXIS;
using System;
using Aitex.Core.RT.Device;
using MECF.Framework.Common.ToolLayout;
using Aitex.Core.Util;
using CyberX8_RT.Modules.Transporter;
using CyberX8_RT.Modules;

namespace CyberX8_RT.Devices.TransPorter
{
    public class LoaderTransPorterGantryAxisInterLock : IAxisInterLock
    {
        #region 常量
        private const int TRANSPORTER_BOX_LENGTH = 85;
        #endregion
        #region 内部变量
        private JetAxisBase _axis;
        #endregion
        #region 属性
        /// <summary>
        /// 模块名称
        /// </summary>
        public string Module { get { return _axis.Module; } }
        /// <summary>
        /// 子模块名称
        /// </summary>
        public string Name { get { return _axis.Name; } }
        #endregion
        /// <summary>
        /// 栣函数
        /// </summary>
        /// <param name="moduleName"></param>
        /// <param name="name"></param>
        public LoaderTransPorterGantryAxisInterLock(JetAxisBase axis)
        {
            _axis = axis;
            OP.Subscribe($"{Module}.{Name}.{MotionOperation.SaveWithModifyLayout}", SaveWithModifyLayoutOperation);
        }


        /// <summary>
        /// GotoPosition条件检验
        /// </summary>
        /// <param name="station"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public bool CheckGotoPosition(string station)
        {
            if (!AxisManager.Instance.CheckModuleAxisSwitchOn(Module, Name))
            {
                return false;
            }

            //ProcessTransporter Home
            if (ModuleHelper.IsInstalled(ModuleName.Transporter1))
            {
                TransporterEntity processTransporterEntity = Singleton<RouteManager>.Instance.GetModule<TransporterEntity>(ModuleName.Transporter1.ToString());
                if (processTransporterEntity == null)
                {
                    LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{ModuleName.Transporter1.ToString()} entity is null");
                    return false;
                }
                if (!processTransporterEntity.IsHomed)
                {
                    LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{ModuleName.Transporter1.ToString()} is not home, Cannot execute GotoSavedPosition");
                    return false;
                }
            }
            //LoaderTransporter Home
            if (ModuleHelper.IsInstalled(ModuleName.Transporter2))
            {
                TransporterEntity loaderTransporterEntity = Singleton<RouteManager>.Instance.GetModule<TransporterEntity>(ModuleName.Transporter2.ToString());
                if (loaderTransporterEntity == null)
                {
                    LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{ModuleName.Transporter2.ToString()} entity is null");
                    return false;
                }
                if (!loaderTransporterEntity.IsHomed)
                {
                    LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{ModuleName.Transporter2.ToString()} is not home, Cannot execute GotoSavedPosition");
                    return false;
                }
            }
            //LoaderTransporter Elevator is not run
            JetAxisBase elevatorAxis = DEVICE.GetDevice<JetAxisBase>($"{Module}.Elevator");
            if (elevatorAxis == null)
            {
                LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{Module} Elevator Axis is null");
                return false;
            }
            if (elevatorAxis.Status == CyberX8_Core.RState.Running)
            {
                LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"{Module} Elevator Axis is Run");
                return false;
            }
            //LoaderTransporter Elevator 在UP位
            double elevatorPosition = elevatorAxis.MotionData.MotorPosition;
            if (!elevatorAxis.CheckPositionIsInStation(elevatorPosition, "UP"))
            { 
                LOG.WriteLog(eEvent.ERR_AXIS, Module, $"Elevator {elevatorPosition} is not in UP");
                return false ;
            }
            return true;
        }
        /// <summary>
        /// 保存操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private bool SaveWithModifyLayoutOperation(string cmd, object[] args)
        {
            string str = $"{Module}.{Name}.{args[0]}";
            bool result = _axis.SaveOperation(cmd, new object[] { str, args[1] });
            if (result)
            {
                string cellId = args[0].ToString();
                string cellName=CellItemManager.Instance.GetModuleNameByCellId(cellId);
                if (!string.IsNullOrEmpty(cellName))
                {
                    ProcessLayoutCellItem item = ProcessLayoutManager.Instance.GetProcessLayoutCellItemByName(cellId);
                    if (item == null)
                    {
                        return true;
                    }
                    int transporterLayoutHorizontalDistance = SC.GetValue<int>("Transporter.TransporterLayoutHorizontalDistance");
                    int loaderPosition = SC.GetValue<int>("Transporter.TransporterLayoutLoaderPosition");
                    int biasDistanceBetweenLoaderAndProcess = SC.GetValue<int>("Transporter.BiasDistanceBetweenLoaderAndProcess");
                    BeckhoffStationAxis loaderTransporterAxis = BeckhoffStationLocationManager.Instance.GetStationAxis(ModuleName.Transporter2.ToString(), "Gantry");
                    BeckhoffStationAxis processTransporterAxis = BeckhoffStationLocationManager.Instance.GetStationAxis(ModuleName.Transporter1.ToString(), "Gantry");
                    var calculateResult = CalculateTransporterHorizontal(loaderTransporterAxis, processTransporterAxis);
                    double distance = calculateResult.max -biasDistanceBetweenLoaderAndProcess - calculateResult.min;
                    double _ratio = distance / transporterLayoutHorizontalDistance;
                    int cellPosition = (int)Math.Round((loaderPosition + (_axis.MotionData.MotorPosition - calculateResult.min) / _ratio), 0);
                    item.Left = cellPosition;
                    if(item.Type=="Cell")
                    {
                        item.Left -= (item.Width/2-5);
                    }
                    try
                    {
                        ProcessLayoutManager.Instance.SaveProcessLayout();
                    }
                    catch (Exception ex)
                    {
                        LOG.WriteLog(eEvent.ERR_TRANSPORTER, Module, $"Save Layout exception {ex.Message}");
                    }
                }
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 计算Tansporter水平最大值最小值
        /// </summary>
        /// <param name="loaderTransporterAxis"></param>
        /// <param name="processTransporterAxis"></param>
        /// <returns></returns>
        private (double max, double min) CalculateTransporterHorizontal(BeckhoffStationAxis loaderTransporterAxis, BeckhoffStationAxis processTransporterAxis)
        {
            double max = 0;
            double min = 0;
            foreach (Station item in loaderTransporterAxis.Stations)
            {
                double position = double.Parse(item.Position);
                if (position > max)
                {
                    max = position;
                }
                if (position < min)
                {
                    min = position;
                }
            }
            foreach (Station item in processTransporterAxis.Stations)
            {
                double position = double.Parse(item.Position);
                if (position > max)
                {
                    max = position;
                }
                if (position < min)
                {
                    min = position;
                }
            }
            return (max, min);
        }

    }
}