using System;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts
{
    public class OpenStageLoadPort : LoadPort
    {
        public override bool IsWaferProtrude
        {
            get { return _diWaferProtrude != null && _diWaferProtrude.Value; }
            
        }
        private DIAccessor _diPresent;
        private DIAccessor _diWaferProtrude;

        private RD_TRIG _trigPresentAbsent = new RD_TRIG();
        private RD_TRIG _trigPresentAbsentDely = new RD_TRIG();
        
        private R_TRIG _trigWaferProtrude = new R_TRIG();
        
        DeviceTimer _deviceTimer = new DeviceTimer();
        private int _queryPeriod = 0;    //ms
        private bool _isStillThere = false; 
        public override LoadportCassetteState CassetteState
        {
            get
            {
                if (!_diPresent.Value)
                {
                    return LoadportCassetteState.Absent;
                }

                if (!_diWaferProtrude.Value)
                {
                    return LoadportCassetteState.Normal;
                } 

                return LoadportCassetteState.Unknown;
            }
        }

        public void SetPrensentAbsentDelay(int ms)
        {
            _queryPeriod = ms;
        }

        public OpenStageLoadPort(string module, string name, DIAccessor diPresent, DIAccessor diNoWaferProtrude) : base(
            module, name)
        {
            if (diPresent == null)
                throw new ArgumentException("DI present cannot be null", "diPresent");

            if (diNoWaferProtrude == null)
                throw new ArgumentException("DI NoWaferProtrude cannot be null", "diNoWaferProtrude");

            if (string.IsNullOrEmpty(name))
                throw new ArgumentException("name cannot be null or empty", "name");

            _diPresent = diPresent;
            _diWaferProtrude = diNoWaferProtrude;

            IsMapWaferByLoadPort = false;
            PortType = EnumLoadPortType.OpenStage;
            Initalized = true;
        }
        
        public override  void Monitor()
        {
            base.Monitor();

            //place foup
            _trigPresentAbsent.CLK = _diPresent.Value;
            if (_queryPeriod == 0)
            {
                if (_trigPresentAbsent.R)
                {
                    SetPresent(true);
                    SetPlaced(true);
                    
                }

                //remove foup
                if (_trigPresentAbsent.T)
                {
                    SetPresent(false);
                    SetPlaced(false);
                    
                }
            }
            else
            {
                if (_trigPresentAbsent.R)
                {
                    _deviceTimer.Start(_queryPeriod);
                }

                if (_diPresent.Value && _deviceTimer.IsTimeout() && !_isStillThere)
                {
                    SetPresent(true);
                    SetPlaced(true);
                    
                    _isStillThere = true;
                    _deviceTimer.Stop();
                }

                //remove foup
                if (_trigPresentAbsent.T)
                {
                    _deviceTimer.Start(_queryPeriod);
                }
                
                if (!_diPresent.Value && _deviceTimer.IsTimeout() && _isStillThere)
                {
                    SetPlaced(false);
                    SetPresent(false);
                    _isStillThere = false;
                    _deviceTimer.Stop();
                }

            }
//            _trigWaferProtrude.CLK = _diPresent.Value && _diWaferProtrude.Value;
//            if (_trigWaferProtrude.Q)
//            {
//                EV.PostAlarmLog(Module, $"{Module}.{Name} Found wafer protrude");
//            }

        }


        public override void Reset()
        {
            base.Reset();

            _trigWaferProtrude.RST = true;
        }

        public override bool IsEnableMapWafer()
        {
            return _diPresent.Value && !_diWaferProtrude.Value;
        }

        public override bool IsEnableTransferWafer()
        {
            return IsEnableTransferWafer(out _);
        }

        public override  bool IsEnableTransferWafer(out string reason)
        {
            if (!_diPresent.Value)
            {
                reason = "no FOUP placed";
                return false;
            }

            if (_diWaferProtrude.Value)
            {
                reason = "Found wafer protrude";
                return false;
            }

            if (!_isMapped)
            {
                reason = "FOUP not mapped";
                return false;
            }

            reason = "";
            return true;
        }

        public override bool Unload(out string reason)
        {
            reason = "";

            _isMapped = false;

            OnUnloaded();

            return true;
        }

    }

    public class OpenStageLoadPortCRRC : LoadPort
    {
        public override FoupDoorState DoorState
        {
            get
            {                
                return FoupDoorState.Open;
            }
        }
        
        private DIAccessor _diPresent;
        private DIAccessor _diWaferProtrude;

        public DIAccessor DIinfoPadA;
        public DIAccessor DIinfoPadB;
        public DIAccessor DIinfoPadC;
        public DIAccessor DIinfoPadD;

        private DOAccessor _doCst1;
        private DOAccessor _doCst2;
        private DOAccessor _doCst3;
        private DOAccessor _doCst4;
        private DOAccessor _doPlacement;
        public DOAccessor _doAlarm;

        private int InfoPadIndex;    
        private RD_TRIG _trigPresentAbsent = new RD_TRIG();
        private RD_TRIG _trigPresentAbsentDely = new RD_TRIG();

        private R_TRIG _trigWaferProtrude = new R_TRIG();

        DeviceTimer _deviceTimer = new DeviceTimer();
        private int _queryPeriod = 0;    //ms
        //private bool _isStillThere = false;

        private bool _isVirtualMode = false;

        public override LoadportCassetteState CassetteState
        {         


            get
            {
                if (_diPresent == null) return LoadportCassetteState.Absent;
                if (_diPresent.Value)
                {
                    return LoadportCassetteState.Absent;
                }
                return LoadportCassetteState.Normal;
                //if (_diWaferProtrude.Value)
                //{
                //    return LoadportCassetteState.Normal;
                //}

                //return LoadportCassetteState.Unknown;
            }
        }

        public void SetPrensentAbsentDelay(int ms)
        {
            _queryPeriod = ms;
        }

        public OpenStageLoadPortCRRC(string module, string name, DIAccessor diPresent, DIAccessor diNoWaferProtrude,DIAccessor[] inforpad, DOAccessor[] indicators ) : base(
            module, name)
        {
            if (diPresent == null)
                throw new ArgumentException("DI present cannot be null", "diPresent");

            if (diNoWaferProtrude == null)
                throw new ArgumentException("DI NoWaferProtrude cannot be null", "diNoWaferProtrude");

            if (string.IsNullOrEmpty(name))
                throw new ArgumentException("name cannot be null or empty", "name");

            _diPresent = diPresent;
            _diWaferProtrude = diNoWaferProtrude;

            DIinfoPadA = inforpad[0];
            DIinfoPadB = inforpad[1];
            DIinfoPadC = inforpad[2];
            DIinfoPadD = inforpad[3];

            _doCst1 = indicators[0];
            _doCst2 = indicators[1];
            _doCst3 = indicators[2];
            _doCst4 = indicators[3];
            _doPlacement = indicators[4];
            _doAlarm = indicators[5];

            IsMapWaferByLoadPort = false;
            PortType = EnumLoadPortType.OpenStage;

            Initalized = true;
            IsBusy = false;
            Error = false;

            InfoPadIndex = SC.ContainsItem($"CarrierInfo.{Name}CarrierIndex") ? SC.GetValue<int>($"CarrierInfo.{name}CarrierIndex") : -1;
            InfoPadCarrierType = SC.ContainsItem($"CarrierInfo.CarrierName{InfoPadIndex}") ?
                        SC.GetStringValue($"CarrierInfo.CarrierName{InfoPadIndex}") : "Unknown";
            EV.Subscribe(new EventItem("Event", $"{name}ProtrudeError", $"{Name} trigger protrude error", EventLevel.Alarm, Aitex.Core.RT.Event.EventType.EventUI_Notify));

        }


        public OpenStageLoadPortCRRC(string module, string name) : base(module, name)
        {
            _isVirtualMode = true;


            IsMapWaferByLoadPort = false;
            PortType = EnumLoadPortType.OpenStage;

            Initalized = true;
            IsBusy = false;
            Error = false;
            EV.Subscribe(new EventItem("Event", $"{name}ProtrudeError", $"{Name} trigger protrude error", EventLevel.Alarm, Aitex.Core.RT.Event.EventType.EventUI_Notify));


        }
        private int _lampflashCount = 0;

        public override void Monitor()
        {
            if (_isVirtualMode) return;
            int infoindex = ((DIinfoPadA == null || !DIinfoPadA.Value) ? 0 : 8) + ((DIinfoPadB == null || !DIinfoPadB.Value) ? 0 : 4) +
                ((DIinfoPadC == null || !DIinfoPadC.Value) ? 0 : 2) + ((DIinfoPadD == null || !DIinfoPadD.Value) ? 0 : 1);

            IsInfoPadAOn = DIinfoPadA == null ? false : DIinfoPadA.Value;
            IsInfoPadBOn = DIinfoPadB == null ? false : DIinfoPadB.Value;
            IsInfoPadCOn = DIinfoPadC == null ? false : DIinfoPadC.Value;
            IsInfoPadDOn = DIinfoPadD == null ? false : DIinfoPadD.Value;

            if (infoindex != InfoPadIndex && InfoPadIndex !=-1)
            {
                SC.SetItemValue($"CarrierInfo.{Name}CarrierIndex", infoindex);
                InfoPadIndex = infoindex;
                InfoPadCarrierType = SC.ContainsItem($"CarrierInfo.CarrierName{infoindex}") ?
                    SC.GetStringValue($"CarrierInfo.CarrierName{infoindex}") : "Unknown";
            }
            IsWaferProtrude = _diWaferProtrude != null ? !_diWaferProtrude.Value : false;
            if (!IsWaferProtrude) TrigWaferProtrude.CLK = false;
            //if (IsMonitorProtrude) TrigWaferProtrude.CLK = IsWaferProtrude;
            if (TrigWaferProtrude.Q)
            {
                EV.Notify($"{Name}ProtrudeError");
                TrigWaferProtrude.CLK = true;
            }

            if (IsPlacement && !IsComplete)
            {
                _doPlacement.Value = true;
            }
            if(IsPlacement && IsComplete && _lampflashCount++>5)
            {
                _lampflashCount = 0;
                _doPlacement.Value = !_doPlacement.Value;
            }
            if(!IsPlacement)
            {
                //MapError = false;
                ReadCarrierIDError = false;
                _doPlacement.Value = false;
            }

            switch (infoindex)
            {
                case 1:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = true;
                    //_doPlacement.Value = true;
                    break;

                case 0:
                    _doCst1.Value = true;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
                case 2:
                    _doCst1.Value = false;
                    _doCst2.Value = true;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
                case 9:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = true;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
                case 15:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = false;
                    break;
                case 14:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = false;
                    break;
                default:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
            }
            if(MapError || ReadCarrierIDError|| (!_diWaferProtrude.Value && !IsMapped))
            {
                _doAlarm.Value = true;
            }
            else 
                _doAlarm.Value = false;

            



            base.Monitor();

            //place foup
            //place foup
            //_trigPresentAbsent.CLK = !_diPresent.Value;

            monitorSignalDelay(_diPresent.Value, ref _trigPresentAbsent, ref _presentmonitorCount, 30);

            if (_trigPresentAbsent.R)
            {
                SetPresent(true);
                SetPlaced(true);
                _trigPresentAbsent.CLK = true;


            }

            //remove foup
            if (_trigPresentAbsent.T)
            {
                SetPresent(false);
                SetPlaced(false);
                _trigPresentAbsent.CLK = false;

            }




        }

        private int _presentmonitorCount;

        private void monitorSignalDelay(bool inputvalue, ref RD_TRIG trigger, ref int count, int trigcount)
        {
            if (inputvalue)
            {
                trigger.CLK = false;
                count = 0;
            }
            else if (count > trigcount)
            {
                trigger.CLK = true;
                count = 0;
            }
            else count++;

        }


        public override void Reset()
        {
            base.Reset();

            _trigWaferProtrude.RST = true;
        }

        public override bool IsEnableMapWafer()
        {
            return !_diPresent.Value && _diWaferProtrude.Value;
        }

        public override bool IsEnableTransferWafer()
        {
            return IsEnableTransferWafer(out _);
        }

        public override bool IsEnableTransferWafer(out string reason)
        {
            if (_diPresent.Value)
            {
                reason = "no FOUP placed";
                return false;
            }

            if (!_diWaferProtrude.Value)
            {
                reason = "Found wafer protrude";
                return false;
            }

            if (!_isMapped)
            {
                reason = "FOUP not mapped";
                return false;
            }

            reason = "";
            return true;
        }

        public override bool Unload(out string reason)
        {
            reason = "";

            _isMapped = false;

            OnUnloaded();

            return true;
        }
        public override bool ReadRfId(out string reason)
        {
            reason = "";

            OP.DoOperation("ReadCarrierId", new object[] { Name });
            return true;
        }

        public override bool FALoad(out string reason)
        {
            reason = "";
            if(!IsEnableMapWafer())
            {
                reason = "Not ready to map wafer";
                return false;
            }
            OP.DoOperation("MapWafer", new object[] { Name });
            return true;
        }

    }

    public class OpenStageLoadPortCRRC02 : LoadPort
    {
        public override FoupDoorState DoorState
        {
            get
            {
                return FoupDoorState.Open;
            }
        }

        private DIAccessor _diPresent;
        private DIAccessor _diWaferProtrude;

        public DIAccessor DIinfoPadA;
        public DIAccessor DIinfoPadB;
        public DIAccessor DIinfoPadC;
        public DIAccessor DIinfoPadD;

        private DOAccessor _doCst1;
        private DOAccessor _doCst2;
        private DOAccessor _doCst3;
        private DOAccessor _doCst4;
        private DOAccessor _doPlacement;
        public DOAccessor _doAlarm;

        private int InfoPadIndex;
        private RD_TRIG _trigPresentAbsent = new RD_TRIG();
        private RD_TRIG _trigPresentAbsentDely = new RD_TRIG();

        private R_TRIG _trigWaferProtrude = new R_TRIG();

        DeviceTimer _deviceTimer = new DeviceTimer();
        private int _queryPeriod = 0;    //ms
        //private bool _isStillThere = false;

        private bool _isVirtualMode = false;

        public override LoadportCassetteState CassetteState
        {


            get
            {
                if (_diPresent == null) return LoadportCassetteState.Absent;
                if (_diPresent.Value)
                {
                    return LoadportCassetteState.Absent;
                }
                return LoadportCassetteState.Normal;
                //if (_diWaferProtrude.Value)
                //{
                //    return LoadportCassetteState.Normal;
                //}

                //return LoadportCassetteState.Unknown;
            }
        }

        public void SetPrensentAbsentDelay(int ms)
        {
            _queryPeriod = ms;
        }

        public OpenStageLoadPortCRRC02(string module, string name, DIAccessor diPresent, DIAccessor diNoWaferProtrude, DIAccessor[] inforpad, DOAccessor[] indicators) : base(
            module, name)
        {
            if (diPresent == null)
                throw new ArgumentException("DI present cannot be null", "diPresent");

            if (diNoWaferProtrude == null)
                throw new ArgumentException("DI NoWaferProtrude cannot be null", "diNoWaferProtrude");

            if (string.IsNullOrEmpty(name))
                throw new ArgumentException("name cannot be null or empty", "name");

            _diPresent = diPresent;
            _diWaferProtrude = diNoWaferProtrude;

            DIinfoPadA = inforpad[0];
            DIinfoPadB = inforpad[1];
            DIinfoPadC = inforpad[2];
            DIinfoPadD = inforpad[3];

            _doCst1 = indicators[0];
            _doCst2 = indicators[1];
            _doCst3 = indicators[2];
            _doCst4 = indicators[3];
            _doPlacement = indicators[4];
            _doAlarm = indicators[5];

            IsMapWaferByLoadPort = false;
            PortType = EnumLoadPortType.OpenStage;

            Initalized = true;
            IsBusy = false;
            Error = false;

            InfoPadIndex = SC.ContainsItem($"CarrierInfo.{Name}CarrierIndex") ? SC.GetValue<int>($"CarrierInfo.{name}CarrierIndex") : -1;
            InfoPadCarrierType = SC.ContainsItem($"CarrierInfo.CarrierName{InfoPadIndex}") ?
                        SC.GetStringValue($"CarrierInfo.CarrierName{InfoPadIndex}") : "Unknown";
        }


        public OpenStageLoadPortCRRC02(string module, string name) : base(module, name)
        {
            _isVirtualMode = true;


            IsMapWaferByLoadPort = false;
            PortType = EnumLoadPortType.OpenStage;

            Initalized = true;
            IsBusy = false;
            Error = false;


        }
        private int _lampflashCount = 0;

        public override void Monitor()
        {
            if (_isVirtualMode) return;
            int infoindex = ((DIinfoPadA == null || !DIinfoPadA.Value) ? 0 : 8) + ((DIinfoPadB == null || !DIinfoPadB.Value) ? 0 : 4) +
                ((DIinfoPadC == null || !DIinfoPadC.Value) ? 0 : 2) + ((DIinfoPadD == null || !DIinfoPadD.Value) ? 0 : 1);

            IsInfoPadAOn = DIinfoPadA == null ? false : DIinfoPadA.Value;
            IsInfoPadBOn = DIinfoPadB == null ? false : DIinfoPadB.Value;
            IsInfoPadCOn = DIinfoPadC == null ? false : DIinfoPadC.Value;
            IsInfoPadDOn = DIinfoPadD == null ? false : DIinfoPadD.Value;


            if (infoindex != InfoPadIndex && InfoPadIndex != -1)
            {
                SC.SetItemValue($"CarrierInfo.{Name}CarrierIndex", infoindex);
                InfoPadIndex = infoindex;
                InfoPadCarrierType = SC.ContainsItem($"CarrierInfo.CarrierName{infoindex}") ?
                    SC.GetStringValue($"CarrierInfo.CarrierName{infoindex}") : "Unknown";
            }
            
            if (IsPlacement && !IsComplete)
            {
                _doPlacement.Value = true;
            }
            if (IsPlacement && IsComplete && _lampflashCount++ > 5)
            {
                _lampflashCount = 0;
                _doPlacement.Value = !_doPlacement.Value;
            }
            if (!IsPlacement)
            {
                //MapError = false;
                ReadCarrierIDError = false;
                _doPlacement.Value = false;
            }

            switch (infoindex)
            {
                case 1:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;

                case 0:
                    _doCst1.Value = true;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
                case 2:
                    _doCst1.Value = false;
                    _doCst2.Value = true;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
                case 8:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = true;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
                case 15:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = false;
                    break;
                case 14:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = false;
                    break;
                default:
                    _doCst1.Value = false;
                    _doCst2.Value = false;
                    _doCst3.Value = false;
                    _doCst4.Value = false;
                    //_doPlacement.Value = true;
                    break;
            }
            if (MapError || ReadCarrierIDError || (!_diWaferProtrude.Value && !IsMapped))
            {
                _doAlarm.Value = true;
            }
            else
                _doAlarm.Value = false;

            IsWaferProtrude = _diWaferProtrude != null ? !_diWaferProtrude.Value : false;

            base.Monitor();

            //place foup
            //_trigPresentAbsent.CLK = !_diPresent.Value;

            monitorSignalDelay(_diPresent.Value, ref _trigPresentAbsent, ref _presentmonitorCount, 30);

            if (_trigPresentAbsent.R)
            {
                SetPresent(true);
                SetPlaced(true);
                DockState = FoupDockState.Docked;
                _trigPresentAbsent.CLK = true;


            }

            //remove foup
            if (_trigPresentAbsent.T)
            {
                SetPresent(false);
                SetPlaced(false);
                _trigPresentAbsent.CLK = false;

            }

          


        }

        private int _presentmonitorCount;

        private void monitorSignalDelay(bool inputvalue, ref RD_TRIG trigger, ref int count, int trigcount)
        {
            if (inputvalue)
            {
                trigger.CLK = false;
                count = 0;
            }
            else if (count > trigcount)
            {
                trigger.CLK = true;
                count = 0;
            }
            else count++;
            
        }
        public override bool FALoad(out string reason)
        {
            reason = "";
            if (!IsEnableMapWafer())
            {
                reason = "Not ready to map wafer";
                return false;
            }
            OP.DoOperation("MapWafer", new object[] { Name });
            return true;
        }

        public override void Reset()
        {
            base.Reset();

            _trigWaferProtrude.RST = true;
        }

        public override bool IsEnableMapWafer()
        {
            return !_diPresent.Value && _diWaferProtrude.Value;
        }

        public override bool IsEnableTransferWafer()
        {
            return IsEnableTransferWafer(out _);
        }

        public override bool IsEnableTransferWafer(out string reason)
        {
            if (_diPresent.Value)
            {
                reason = "no FOUP placed";
                return false;
            }

            if (!_diWaferProtrude.Value)
            {
                reason = "Found wafer protrude";
                return false;
            }

            if (!_isMapped)
            {
                reason = "FOUP not mapped";
                return false;
            }

            reason = "";
            return true;
        }
        public override bool Load(out string reason)
        {
            reason = "";
            OP.DoOperation("MapWafer", new object[] { Name });
            return true;
        }

        public override bool Unload(out string reason)
        {
            reason = "";

            _isMapped = false;

            OnUnloaded();

            return true;
        }
        public override bool ReadRfId(out string reason)
        {
            reason = "";

            OP.DoOperation("ReadCarrierId", new object[] { Name});
            return true;
        }

    }

    



}
