using Aitex.Core.RT.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Configuration;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Aitex.Core.Common;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using MECF.Framework.Common.Equipment;
using MECF.Framework.RT.Core.Equipments;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.TDK;
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts
{
    public enum IndicatorType
    {
        Load,
        Unload,
        Presence,
        Placement,
        Alarm,
        Access,
        Status1,
        Status2,
    }
    public interface IE87CallBack
    {
        void CarrierArrive();
        void CarrerRemove(string carrierID);
        void CarrierIDReadSuccess(string carrierID);
        void CarrierIDReadFail();
        void MappingComplete(string carrierID, string slotmap);
        void LoadStart();
        void LoadportError(string errorcode);
        void LoadComplete();
        void UnLoadStart();
        void UnloadComplete();
        void OnLPHomed();
        void OnE84HandoffStart(bool isload);
        void OnE84HandoffComplete(bool isload);
    }
    public abstract class LoadPort : BaseDevice, IDevice
    {
        public IndicatorState IndicatiorLoad { get; set; }
        public IndicatorState IndicatiorUnload { get; set; }
        public IndicatorState IndicatiorPresence { get; set; }
        public IndicatorState IndicatorAlarm { get; set; }
        public IndicatorState IndicatiorPlacement { get; set; }
        public IndicatorState IndicatiorOpAccess { get; set; }
        public IndicatorState IndicatiorStatus1 { get; set; }
        public IndicatorState IndicatiorStatus2 { get; set; }
        public virtual FoupClampState ClampState { get; set; }
        public virtual FoupDoorState DoorState { get; set; }
        public virtual CasstleType  CasstleType { get; set; }
        public string SlotMap
        {
            get { return GetSlotMap(); }
        }
        public virtual bool IsBusy { get; set; }
        public virtual bool IsIdle { get; set; }
        public virtual bool IsMoving { get; set; }
        public virtual LoadportCassetteState CassetteState
        {
            get;
            set;
        }
        public bool IsMapWaferByLoadPort { get; set; }
        public EnumLoadPortType PortType { get; set; }
        public bool Initalized { get; set; }
        public bool IsPresent
        {
            get { return _isPresent; }
        }
        public bool IsPlacement
        {
            get { return _isPlaced; }
        }
        public bool IsMapped
        {
            get { return _isMapped; }
        }
        public bool Error { get; set; }
        public string ErrorCode { get; set; }
        
        /// 
        /// 是否处于FOSB模式
        /// 
        public bool IsFOSBMode { get; set; }    
        
        public DeviceState State
        {
            get
            {
                if (!Initalized)
                {
                    return DeviceState.Unknown;
                }
                if (Error)
                {
                    return DeviceState.Error;
                }
                if (IsBusy)
                    return DeviceState.Busy;
                return DeviceState.Idle;
            }
        }
        public string CarrierId
        {
            get { return _carrierId; }
        }
        public string RfId
        {
            get { return _rfid; }
        }
        protected bool _isPresent;
        protected bool _isPlaced;
        protected string _carrierId;
        protected string _rfid;
        protected bool _isMapped;
        private ModuleName _module;
        private ModuleStateEnum _state;
        private List> _waferId = new List>();
        private static bool _isIndependentCEID = SC.ContainsItem("Fa.IndependentCEIDForLp")?SC.GetValue("Fa.IndependentCEIDForLp"):false;
        public string PortId
        {
            get { return (_lpIndex+1).ToString(); }
        }
        public string PortCategory
        {
            get
            {
                if (SC.GetConfigItem(PortLabelScNames[_lpIndex]) == null)
                    return "";
                return SC.GetStringValue(PortLabelScNames[_lpIndex]) ;
            }
        }
        string[] PortStateVariableNames = new[]
        {
            "CARRIER_PORT1_STATE", "CARRIER_PORT2_STATE", "CARRIER_PORT3_STATE",
            "CARRIER_PORT4_STATE", "CARRIER_PORT5_STATE", "CARRIER_PORT6_STATE", "CARRIER_PORT7_STATE",
            "CARRIER_PORT8_STATE", "CARRIER_PORT9_STATE", "CARRIER_PORT10_STATE"
        };
        ModuleName[] PortModuleNames = new[]
        {
            ModuleName.LP1,ModuleName.LP2,ModuleName.LP3,ModuleName.LP4,ModuleName.LP5,
            ModuleName.LP6,ModuleName.LP7,ModuleName.LP8,ModuleName.LP9,ModuleName.LP10,
        };
        string[] PortSlotMapVariableNames = new[]
        {
            "CARRIER_PORT1_CURRENT_SLOTMAP", "CARRIER_PORT2_CURRENT_SLOTMAP", "CARRIER_PORT3_CURRENT_SLOTMAP",
            "CARRIER_PORT4_CURRENT_SLOTMAP", "CARRIER_PORT5_CURRENT_SLOTMAP", "CARRIER_PORT6_CURRENT_SLOTMAP", "CARRIER_PORT7_CURRENT_SLOTMAP",
            "CARRIER_PORT8_CURRENT_SLOTMAP", "CARRIER_PORT9_CURRENT_SLOTMAP", "CARRIER_PORT10_CURRENT_SLOTMAP"
        };
        string[] PortWaferIdVariableNames = new[]
        {
            "CARRIER_PORT1_CURRENT_WAFERID", "CARRIER_PORT2_CURRENT_WAFERID", "CARRIER_PORT3_CURRENT_WAFERID",
            "CARRIER_PORT4_CURRENT_WAFERID", "CARRIER_PORT5_CURRENT_WAFERID", "CARRIER_PORT6_CURRENT_WAFERID", "CARRIER_PORT7_CURRENT_WAFERID",
            "CARRIER_PORT8_CURRENT_WAFERID", "CARRIER_PORT9_CURRENT_WAFERID", "CARRIER_PORT10_CURRENT_WAFERID"
        };
        private string[] PortLabelScNames = new[]
        {
            "LoadPort.LoadPort1CarrierLabel","LoadPort.LoadPort2CarrierLabel","LoadPort.LoadPort3CarrierLabel","LoadPort.LoadPort4CarrierLabel",
            "LoadPort.LoadPort5CarrierLabel","LoadPort.LoadPort6CarrierLabel","LoadPort.LoadPort7CarrierLabel","LoadPort.LoadPort8CarrierLabel",
            "LoadPort.LoadPort9CarrierLabel","LoadPort.LoadPort10CarrierLabel",
        };
        private int _lpIndex = -1;
        private string EventCarrierArrived= "CARRIER_ARRIVED";
        private string EventCarrierIdRead= "CARRIER_ID_READ";
        private string EventCarrierIdReadFailed = "CARRIER_ID_READ_FAILED";
        private string EventCarrierIdWrite = "CARRIER_ID_WRITE";
        private string EventCarrierIdWriteFailed = "CARRIER_ID_WRITE_FAILED";
        private string EventSlotMapAvailable= "SLOT_MAP_AVAILABLE";
        private string EventCarrierRemoved = "CARRIER_REMOVED";
        private string EventCarrierUnloaded = "CARRIER_UNLOADED";
        private string EventCarrierloaded = "CARRIR_DOCK_COMPLETE";
        private string PORT_ID = "PORT_ID";
        private string CAR_ID = "CAR_ID";
        private string SLOT_MAP = "SLOT_MAP";
        private string PORT_CTGRY = "PORT_CTGRY";
        private string RF_ID = "RF_ID";
        private string EventRfIdRead = "RF_ID_READ";
        private string EventRfIdReadFailed = "RF_ID_READ_FAILED";
        private string EventRfIdWrite = "RF_ID_WRITE";
#pragma warning disable 414
        private string EventRfIdWriteFailed = "RF_ID_WRITE_FAILED";
#pragma warning restore 414
        private string AlarmCarrierPortError = "CarrierPortError";
        public LoadPort(string module, string name):base(module, name, name, "")
        {
            for (int i = 0; i < 25; i++)
            {
                _waferId.Add(new List()
                {
                    i.ToString("D2"),"","",""
                });
            }
 
                if (!Enum.TryParse(name, out ModuleName m))
                    Enum.TryParse(module, out m);
                _module = m;
 
            _lpIndex = Array.IndexOf(PortModuleNames, _module);
            DoorState = FoupDoorState.Unknown;
            System.Diagnostics.Trace.Assert(_lpIndex != -1);
        }
        public virtual bool Initialize()
        {
            WaferManager.Instance.SubscribeLocation(_module, 25);
            CarrierManager.Instance.SubscribeLocation(_module.ToString());
 
            DATA.Subscribe(Name, "IsPresent", ()=>_isPresent);
            DATA.Subscribe(Name, "IsPlaced", () => _isPlaced);
            DATA.Subscribe(Name, "ModuleState", () => _state.ToString());
            DATA.Subscribe(Name, "CarrierId", () => _carrierId);
            DATA.Subscribe(Name, "IsMapped", () => _isMapped);
            DATA.Subscribe($"{Name}.LoadportState", () => State);
            DATA.Subscribe($"{Name}.LoadportBusy", () => IsBusy);
            DATA.Subscribe($"{Name}.LoadportError", () => ErrorCode);
            DATA.Subscribe($"{Name}.CassetteState", () => CassetteState);
            DATA.Subscribe($"{Name}.FoupClampState", () => ClampState);
            DATA.Subscribe($"{Name}.FoupDoorState", () => DoorState);
            DATA.Subscribe($"{Name}.SlotMap", () => SlotMap);
            DATA.Subscribe($"{Name}.IndicatiorLoad", () => IndicatiorLoad);
            DATA.Subscribe($"{Name}.IndicatiorUnload", () => IndicatiorUnload);
            DATA.Subscribe($"{Name}.IndicatiorPresence", () => IndicatiorPresence);
            DATA.Subscribe($"{Name}.IndicatiorPlacement", () => IndicatiorPlacement);
            DATA.Subscribe($"{Name}.IndicatiorAlarm", () => IndicatorAlarm);
            DATA.Subscribe($"{Name}.IndicatiorOpAccess", () => IndicatiorOpAccess);
            DATA.Subscribe($"{Name}.IndicatiorStatus1", () => IndicatiorStatus1);
            DATA.Subscribe($"{Name}.IndicatiorStatus2", () => IndicatiorStatus2);
            DATA.Subscribe($"{Name}.CasstleType", () => CasstleType);
            DATA.Subscribe(PortStateVariableNames[_lpIndex], () => (_isPlaced && _isPresent) ? "1" : "0");
            DATA.Subscribe(PortSlotMapVariableNames[_lpIndex], () => SlotMap);
            DATA.Subscribe(PortWaferIdVariableNames[_lpIndex], UpdatedWaferIdList);
            if (_isIndependentCEID)
            {
                
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventCarrierArrived}", "Carrier arrived"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventCarrierRemoved}", "Carrier removed"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventCarrierIdRead}", "Carrier ID read"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventCarrierIdReadFailed}", "Carrier ID read failed"));
                EV.Subscribe(new EventItem("Event", $"{_module}_CAR_ID_WRITE_SUCCESSFULLY", "Carrier ID write"));
                EV.Subscribe(new EventItem("Event", $"{_module}_CAR_ID_WRITE_FAIL", "Carrier ID write failed"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventSlotMapAvailable}", "Slot map available"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventCarrierUnloaded}", "Carrier unloaded"));
                EV.Subscribe(new EventItem("Event", $"{_module}_CARRIR_LOAD_COMPLETE", "Carrier loaded"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventRfIdRead}", "Carrier RFID read"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventRfIdReadFailed}", "Carrier RFID read failed"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{EventRfIdWrite}", "Carrier RFID write"));
                EV.Subscribe(new EventItem("Event", $"{_module}_{AlarmCarrierPortError}", "Carrier Port error", EventLevel.Alarm, EventType.HostNotification));
            }
            else
            {
                EV.Subscribe(new EventItem("Event", EventCarrierArrived, "Carrier arrived"));
                EV.Subscribe(new EventItem("Event", EventCarrierRemoved, "Carrier removed"));
                EV.Subscribe(new EventItem("Event", EventCarrierIdRead, "Carrier ID read"));
                EV.Subscribe(new EventItem("Event", EventCarrierIdReadFailed, "Carrier ID read failed"));
                EV.Subscribe(new EventItem("Event", EventCarrierIdWrite, "Carrier ID write"));
                EV.Subscribe(new EventItem("Event", EventCarrierIdWriteFailed, "Carrier ID write failed"));
                EV.Subscribe(new EventItem("Event", EventSlotMapAvailable, "Slot map available"));
                EV.Subscribe(new EventItem("Event", EventCarrierUnloaded, "Carrier unloaded"));
                EV.Subscribe(new EventItem("Event", EventCarrierloaded, "Carrier loaded"));
                EV.Subscribe(new EventItem("Event", EventRfIdRead, "Carrier RFID read"));
                EV.Subscribe(new EventItem("Event", EventRfIdReadFailed, "Carrier RFID read failed"));
                EV.Subscribe(new EventItem("Event", EventRfIdWrite, "Carrier RFID write"));
                EV.Subscribe(new EventItem("Event", AlarmCarrierPortError, "Carrier Port error", EventLevel.Alarm, EventType.HostNotification));
            }
            IsIdle = true;
            _state = ModuleStateEnum.Idle;
            RegisterOperation();
            return true;
        }
        public virtual bool Connect()
        {
            return true;
        }
        private void RegisterOperation()
        {
            OP.Subscribe($"{Name}.LoadportHome", (string cmd, object[] param) =>
            {
                if (!Home(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not start home, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start home");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportReset", (string cmd, object[] param) =>
            {
                if (!ClearError(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not reset, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start reset");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportStop", (string cmd, object[] param) =>
            {
                if (!Stop(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not stop, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} stop");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportLoad", (string cmd, object[] param) =>
            {
                if (!Load(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not load, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start load");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportLoadWithoutMap", (string cmd, object[] param) =>
            {
                if (!LoadWithoutMap(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not load without map, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start load without map");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportLoadWithMap", (string cmd, object[] param) =>
            {
                if (!Load(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not load with map, {reason}");
                    return false;
                }
                if (!QueryWaferMap(out reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not map, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start load with map");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportUnload", (string cmd, object[] param) =>
            {
                if (!Unload(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not unload, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start unload");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportClamp", (string cmd, object[] param) =>
            {
                if (!Clamp(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not clamp, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start clamp");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportUnclamp", (string cmd, object[] param) =>
            {
                if (!Unclamp(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not unclamp, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start unclamp");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportOpenDoor", (string cmd, object[] param) =>
            {
                if (!OpenDoor(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not open door, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start open door");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportOpenDoorNoMap", (string cmd, object[] param) =>
            {
                if (!OpenDoorNoMap(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not open door, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start open door");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportCloseDoor", (string cmd, object[] param) =>
            {
                if (!CloseDoor(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not close door, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start close door");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportDock", (string cmd, object[] param) =>
            {
                if (!Dock(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not dock, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start dock");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportUndock", (string cmd, object[] param) =>
            {
                if (!Undock(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not undock, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start undock");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportQueryState", (string cmd, object[] param) =>
            {
                if (!QueryState(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not query state, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start query state");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportQueryLED", (string cmd, object[] param) =>
            {
                if (!QueryIndicator(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not query led state, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start query led state");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportSetLED", (string cmd, object[] param) =>
            {
                int light = (int) param[0];
                int state = (int) param[1];
                if (!SetIndicator((Indicator) light, (IndicatorState) state, out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not set led state, {reason}");
                    return true;
                }
                EV.PostInfoLog(Module, $"{Name} start set led state");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportMap", (string cmd, object[] param) =>
            {
                if (!QueryWaferMap(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not map, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start map");
                return true;
            });
            
            OP.Subscribe($"{Name}.SetCassetteType", (string cmd, object[] param) =>
            {
                if (!SetCassetteType(param,out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not set type, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} cassette type have set to {CasstleType}");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportForceHome", (string cmd, object[] param) =>
            {
                if (!ForceHome(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not start force home, {reason}");
                    return false;
                }
                EV.PostInfoLog(Module, $"{Name} start force home");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportFOSBMode", (string cmd, object[] param) =>
            {
                if (!FOSBMode(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not change to FOSB mode, {reason}");
                    return false;
                }
                IsFOSBMode = true;
                EV.PostInfoLog(Module, $"{Name} changed to FOSB mode");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportFOUPMode", (string cmd, object[] param) =>
            {
                if (!FOUPMode(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not change to FOSB mode, {reason}");
                    return false;
                }
                IsFOSBMode = true;
                EV.PostInfoLog(Module, $"{Name} changed to FOSB mode");
                return true;
            });
            OP.Subscribe($"{Name}.LoadportQueryFOSBMode", (string cmd, object[] param) =>
            {
                if (!QueryFOSBMode(out string reason))
                {
                    EV.PostWarningLog(Module, $"{Name} can not change to FOUP mode, {reason}");
                    return false;
                }
                IsFOSBMode = false;
                EV.PostInfoLog(Module, $"{Name} changed to FOSB mode");
                return true;
            });
            
        }
        private bool SetCassetteType(object[] param,out string reason)
        {
            reason = "";
            if (param.Length != 1)
            {
                reason = "Invalid setting parameter.";
                return false;
            }
            CasstleType = (CasstleType)int.Parse(param[0].ToString());
            return true;
        }
        public virtual bool Load(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool LoadWithoutMap(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool QueryWaferMap(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool QueryFOSBMode(out string reason)
        {
            reason = "";
            return true;
        }
        /// 
        /// FOSB模式下的Dock指令
        /// 
        /// 
        /// 
        public virtual bool FOSBDock(out string reason)
        {
            reason = "";
            return true;
        }
        
        /// 
        /// FOSB模式下的FOSBUnDock指令
        /// 
        /// 
        /// 
        public virtual bool FOSBUnDock(out string reason)
        {
            reason = "";
            return true;
        }
        
        /// 
        /// FOSB模式下的开门指令
        /// 
        /// 
        /// 
        public virtual bool FOSBDoorOpen(out string reason)
        {
            reason = "";
            return true;
        }
        
        /// 
        /// FOSB模式下的关门指令
        /// 
        /// 
        /// 
        public virtual bool FOSBDoorClose(out string reason)
        {
            reason = "";
            return true;
        }
        /// 
        /// FOSB模式下的门下移指令
        /// 
        /// 
        /// 
        public virtual bool FOSBDoorDown(out string reason)
        {
            reason = "";
            return true;
        }
        /// 
        /// FOSB模式下的门上移指令
        /// 
        /// 
        /// 
        public virtual bool FOSBDoorUp(out string reason)
        {
            reason = "";
            return true;
        }
        
        public bool SetIndicator(IndicatorType light, IndicatorState state)
        {
            switch (light)
            {
                case IndicatorType.Load:
                    SetIndicator(Indicator.LOAD, state, out string _);
                    break;
                case IndicatorType.Unload:
                    SetIndicator(Indicator.UNLOAD, state, out string _);
                    break;
                case IndicatorType.Access:
                    SetIndicator(Indicator.OPACCESS, state, out string _);
                    break;
                case IndicatorType.Alarm:
                    SetIndicator(Indicator.ALARM, state, out string _);
                    break;
                case IndicatorType.Presence:
                    SetIndicator(Indicator.PRESENCE, state, out string _);
                    break;
                case IndicatorType.Placement:
                    SetIndicator(Indicator.PLACEMENT, state, out string _);
                    break;
                case IndicatorType.Status1:
                    SetIndicator(Indicator.STATUS1, state, out string _);
                    break;
                case IndicatorType.Status2:
                    SetIndicator(Indicator.STATUS2, state, out string _);
                    break;
                default:
                    EV.PostWarningLog(Module, $"Not supported indicator {light}");
                    return false;
            }
            return true;
        }
        public virtual bool SetIndicator(Indicator light, IndicatorState state, out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool QueryIndicator(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool QueryState(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool Undock(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool Dock(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool CloseDoor(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool OpenDoor(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool OpenDoorNoMap(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool OpenDoorAndMap(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool Unclamp(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool Clamp(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool Unload(out string reason)
        {
            reason = "";
            return true;
        }
 
        public virtual bool Stop(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool ClearError(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual bool Home(out string reason )
        {
            reason = "";
            return true;
        }
 
        public virtual bool ForceHome(out string reason )
        {
            reason = "";
            return true;
        }
        public virtual bool FOSBMode(out string reason)
        {
            reason = "";
            return true;
        }
        
        public virtual bool FOUPMode(out string reason)
        {
            reason = "";
            return true;
        }
        public virtual  void Monitor()
        {
             
        }
        public virtual void Reset()
        {
            
        }
        public virtual void Terminate()
        {
             
        }
        private List> UpdatedWaferIdList()
        {
            WaferInfo[] wafers = WaferManager.Instance.GetWafers(_module);
            for (int i = 0; i < wafers.Length; i++)
            {
                _waferId[i][1] = wafers[i].LaserMarker;
                _waferId[i][2] = wafers[i].T7Code;
                _waferId[i][3] = wafers[i].WaferID;
            }
            return _waferId;
        }
        public abstract bool IsEnableMapWafer();
        public abstract bool IsEnableTransferWafer();
        public abstract bool IsEnableTransferWafer(out string reason);
        public virtual bool IsEnableLoad()
        {
            return _isPresent && _isPlaced;
        }
        protected void ConfirmAddCarrier()
        {
            if (_isPresent && _isPlaced)
            {
                CarrierManager.Instance.CreateCarrier(Name);
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory
                    };
                    EV.Notify($"{_module}_{EventCarrierArrived}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    EV.Notify(EventCarrierArrived, dvid );
                }
            }
        }
        protected void ConfirmRemoveCarrier()
        {
            if (!_isPresent && !_isPlaced)
            {
                for (int i = 0; i < 25; i++)
                {
                    WaferManager.Instance.DeleteWafer(ModuleHelper.Converter(Name), 0,25);
                }
                CarrierManager.Instance.DeleteCarrier(Name);
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{CAR_ID}_{_module}"] = _carrierId ?? ""
                    };
                    EV.Notify($"{_module}_{EventCarrierRemoved}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    dvid[CAR_ID] = _carrierId ?? "";
                    EV.Notify(EventCarrierRemoved, dvid);
                }
                
                
                
                _isMapped = false;
                _carrierId = "";
            }
        }
        public void OnSlotMapRead(string slotMap)
        {
            for (int i = 0; i < 25; i++)
            {
                // No wafer: "0", Wafer: "1", Crossed:"2", Undefined: "?", Overlapping wafers: "W"
                WaferInfo wafer = null;
                switch (slotMap[i])
                {
                    case '0':
                        WaferManager.Instance.DeleteWafer(_module, i);
                        CarrierManager.Instance.UnregisterCarrierWafer(Name, i);
                        break;
                    case '1':
                        wafer = WaferManager.Instance.CreateWafer(_module, i, WaferStatus.Normal);
                        CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
                        break;
                    case '2':
                        wafer = WaferManager.Instance.CreateWafer(_module, i, WaferStatus.Crossed);
                        CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
                        //NotifyWaferError(Name, i, WaferStatus.Crossed);
                        break;
                    case 'W':
                        wafer = WaferManager.Instance.CreateWafer(_module, i, WaferStatus.Double);
                        CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
                        //NotifyWaferError(Name, i, WaferStatus.Double);
                        break;
                    case '?':
                        wafer = WaferManager.Instance.CreateWafer(_module, i, WaferStatus.Unknown);
                        CarrierManager.Instance.RegisterCarrierWafer(Name, i, wafer);
                        //NotifyWaferError(Name, i, WaferStatus.Unknown);
                        break;
                }
            }
            if (_isIndependentCEID)
            {
                var dvid1 = new SerializableDictionary
                {
                    [$"{SLOT_MAP}_{_module}"] = SlotMap,
                    [$"{PORT_ID}_{_module}"] = PortId,
                    [$"{PORT_CTGRY}_{_module}"] = PortCategory,
                    [$"{CAR_ID}_{_module}"] = _carrierId ?? ""
                };
                EV.Notify($"{_module}_{EventSlotMapAvailable}", dvid1);
            }
            else
            {
                SerializableDictionary dvid = new SerializableDictionary();
 
                dvid[SLOT_MAP] = SlotMap;
                dvid[PORT_ID] = PortId;
                dvid[PORT_CTGRY] = PortCategory;
                dvid[CAR_ID] =  CarrierId == null ? "" : CarrierId;
                EV.Notify(EventSlotMapAvailable, dvid);
            }
            _isMapped = true;
        }
 
        private string GetSlotMap()
        {
            WaferInfo[] wafers = WaferManager.Instance.GetWafers(ModuleHelper.Converter(Name) );
            string slot = "";
            for (int i = 0; i < 25; i++)
            {
                slot += wafers[i].IsEmpty? "0" : "1";
            }
            return slot;
        }
        /// 
        /// 获取LP中空缺Slot
        /// 
        /// 返回一个list, 顺序为从下到上.(0-25)
        public List GetEmptySlot()
        {
            List slot = new List();
            if (IsMapped)
            {
                WaferInfo[] wafers = WaferManager.Instance.GetWafers(ModuleHelper.Converter(Name));
                for (int i = 0; i < 25 ; i++)
                {
                    if(wafers[i].IsEmpty)
                        slot.Add(i);
                }
                return slot;
            }
            else
            {
                return null;
            }
            
        }
        public void OnCarrierIdRead(ModuleName module, string name, string carrierId)
        {
            if (_isPlaced && _isPresent)
            {
                _carrierId = carrierId;
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{CAR_ID}_{_module}"] = _carrierId ?? "",
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory
                    };
                    EV.Notify($"{_module}_{EventCarrierIdRead}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[CAR_ID] = carrierId ?? "";
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    EV.Notify(EventCarrierIdRead, dvid); 
                }
                CarrierManager.Instance.UpdateCarrierId(Name, carrierId);
            }
            else
            {
                EV.PostWarningLog(Module, $"No FOUP found, carrier id {carrierId} not saved");
            }
        }
        public void OnCarrierIdWrite(ModuleName module, string name, string carrierId)
        {
            if (_isPlaced && _isPresent)
            {
                //_carrierId = carrierId;
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{CAR_ID}_{_module}"] = carrierId ?? "",
                        [$"{PORT_ID}_{_module}"] = PortId
                    };
                    EV.Notify($"{_module}_CAR_ID_WRITE_SUCCESSFULLY", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[CAR_ID] = carrierId ?? "";
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    EV.Notify(EventCarrierIdWrite, dvid);
                }
            }
            else
            {
                EV.PostWarningLog(Module, $"No FOUP found, carrier id {carrierId} not saved");
            }
        }
        public void OnCarrierIdReadFailed(ModuleName module, string name)
        {
            if (_isPlaced && _isPresent)
            {
                _carrierId = "";
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{PORT_ID}_{_module}"] = PortId, 
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory
                    };
                    EV.Notify($"{_module}_{EventCarrierIdReadFailed}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    EV.Notify(EventCarrierIdReadFailed, dvid);
                }
                
                
            }
            else
            {
                EV.PostWarningLog(Module, "No FOUP found, carrier id read is not valid");
            }
        }
        public void OnCarrierIdWriteFailed(ModuleName module, string name)
        {
            if (_isPlaced && _isPresent)
            {
                //_carrierId = "";
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory,
                        [$"{CAR_ID}_{_module}"] = _carrierId ?? ""
                    
                    };
                    EV.Notify($"{_module}_CAR_ID_WRITE_FAIL", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    EV.Notify(EventCarrierIdWriteFailed, dvid);
                }
            }
            else
            {
                EV.PostWarningLog(Module, "No FOUP found, carrier id not valid");
            }
        }
        public void OnCarrierIdRead(ModuleName module, string carrierId)
        {
            OnCarrierIdRead(module, "", carrierId);
        }
        public void OnCarrierIdReadFailed(ModuleName module)
        {
            OnCarrierIdReadFailed(module, "");
        }
        public void OnCarrierIdWrite(ModuleName module, string carrierId)
        {
            OnCarrierIdWrite(module, "", carrierId);
        }
        
        public void OnCarrierIdWriteFailed(ModuleName module)
        {
            OnCarrierIdWriteFailed(module, "");
        }
        public void OnRfIdRead(ModuleName module, string rfid)
        {
            if (_isPlaced && _isPresent)
            {
                _rfid = rfid;
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{CAR_ID}_{_module}"] = _carrierId ?? "",
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory,
                        [$"{RF_ID}_{_module}"] = rfid ?? ""
                    };
                    EV.Notify($"{_module}_{EventRfIdRead}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[CAR_ID] = _carrierId ?? "";
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    dvid[RF_ID] = rfid ?? "";
                    EV.Notify(EventRfIdRead, dvid);
                }
                
                CarrierManager.Instance.UpdateRfId(Name, rfid);
            }
            else
            {
                EV.PostWarningLog(Module, "No FOUP found, rf id read not valid");
            }
        }
        public void OnRfIdReadFailed(ModuleName module)
        {
            if (_isPlaced && _isPresent)
            {
                _rfid = "";
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{CAR_ID}_{_module}"] = _carrierId ?? "",
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory
                    };
                    EV.Notify($"{_module}_{EventRfIdReadFailed}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[CAR_ID] = _carrierId ?? "";
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    EV.Notify(EventRfIdReadFailed, dvid);
                }
            }
            else
            {
                EV.PostWarningLog(Module, "No FOUP found, rf id read is not valid");
            }
        }
        public void OnRfIdWrite(ModuleName module, string rfid)
        {
            if (_isPlaced && _isPresent)
            {
                _rfid = rfid;
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{CAR_ID}_{_module}"] = _carrierId ?? "",
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory,
                        [$"{RF_ID}_{_module}"] = rfid ?? ""
                    };
                    EV.Notify($"{_module}_{EventRfIdWrite}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[CAR_ID] = _carrierId ?? "";
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    dvid[RF_ID] = rfid ?? "";
                    EV.Notify(EventRfIdWrite, dvid);
                }
                CarrierManager.Instance.UpdateRfId(Name, rfid);
            }
            else
            {
                EV.PostWarningLog(Module, "No FOUP found, rf id write not valid");
            }
        }
        public void OnRfIdWriteFailed(ModuleName module )
        {
            if (_isPlaced && _isPresent)
            {
                _rfid = "";
                if (_isIndependentCEID)
                {
                    var dvid1 = new SerializableDictionary
                    {
                        [$"{CAR_ID}_{_module}"] = _carrierId ?? "",
                        [$"{PORT_ID}_{_module}"] = PortId,
                        [$"{PORT_CTGRY}_{_module}"] = PortCategory,
                        [$"{RF_ID}_{_module}"] = ""
                    };
                    EV.Notify($"{_module}_{EventRfIdWrite}", dvid1);
                }
                else
                {
                    SerializableDictionary dvid = new SerializableDictionary();
                    dvid[CAR_ID] = _carrierId ?? "";
                    dvid[PORT_ID] = PortId;
                    dvid[PORT_CTGRY] = PortCategory;
                    dvid[RF_ID] = "";
                    //EV.PostWarningLog(Module, "Write RFID failed.");
                    EV.Notify(EventRfIdWrite, dvid);
                }
            }
            else
            {
                EV.PostWarningLog(Module, "No FOUP found, rf id write not valid");
            }
        }
        public void OnLoaded()
        {
            if (_isIndependentCEID)
            {
                var dvid1 = new SerializableDictionary
                {
                    [$"{CAR_ID}_{_module}"] = _carrierId ?? "",
                    [$"{PORT_ID}_{_module}"] = PortId
                };
                EV.Notify($"{_module}_CARRIR_LOAD_COMPLETE", dvid1);
            }
            else
            {
                var dvid = new SerializableDictionary
                {
                    [CAR_ID] = _carrierId ?? "", 
                    [PORT_ID] = PortId
                };
                EV.Notify(EventCarrierloaded, dvid);
            }
        }
        public void OnUnloaded()
        {
            if (_isIndependentCEID)
            {
                var dvid1 = new SerializableDictionary
                {
                    [$"{PORT_CTGRY}_{_module}"] = PortCategory,
                    [$"{PORT_ID}_{_module}"] = PortId,
                    [$"{CAR_ID}_{_module}"] = _carrierId ?? "",
                    [$"{SLOT_MAP}_{_module}"] = SlotMap,
                    [$"LOT_ID_{_module}"] = CarrierManager.Instance.GetLotIdByLoadPort(_module.ToString())
                
                };
                EV.Notify($"{_module}_{EventCarrierUnloaded}", dvid1);
            }
            else
            {
                var dvid = new SerializableDictionary();
                dvid[PORT_CTGRY] = PortCategory;
                dvid[PORT_ID] = PortId;
                dvid[CAR_ID] = _carrierId ?? "";
                EV.Notify(EventCarrierUnloaded, dvid);
            }
            
            
            for (int i = 0; i < 25; i++)
            {
                WaferManager.Instance.DeleteWafer(ModuleHelper.Converter(Name), 0, 25);
            }
            
            _isMapped = false;
        }
        public void OnHomed()
        {
            for (int i = 0; i < 25; i++)
            {
                WaferManager.Instance.DeleteWafer(ModuleHelper.Converter(Name), 0, 25);
            }
            _isMapped = false;
        }
        public void OnCloseDoor()
        {
            for (int i = 0; i < 25; i++)
            {
                WaferManager.Instance.DeleteWafer(ModuleHelper.Converter(Name), 0, 25);
            }
            _isMapped = false;
        }
        public void OnError()
        {
            EV.Notify(AlarmCarrierPortError);
            EV.Notify($"{_module}_{AlarmCarrierPortError}");
        }
 
        protected void SetPresent(bool isPresent)
        {
            _isPresent = isPresent;
            if (_isPresent)
            {
                ConfirmAddCarrier();
            }
            else
            {
                ConfirmRemoveCarrier();
            }
        }
        protected void SetPlaced(bool isPlaced)
        {
            _isPlaced = isPlaced;
            if (_isPlaced)
            {
                ConfirmAddCarrier();
            }
            else
            {
                ConfirmRemoveCarrier();
            }
        }
 
    }
}