using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Aitex.Core.RT.Device.Unit;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Sorter.Common;
using MECF.Framework.Common.Communications;
using TSC = Aitex.Sorter.Common;
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.TDK
{
    ///   
    /// 代码说明:
    ///  
    /// 
    public class TDKLoadPort : LoadPort, IE84Provider,IConnection
    {
        public string Address { get; set; }
        public bool IsConnected
        {
            get { return _port.IsOpen(); }
        }
        public bool UnlockKey
        {
            set
            {
            }
        }
 
        public bool Enable
        {
            set
            {
                if (_enableTrigger != null)
                {
                    _enableTrigger.SetTrigger(value, out _);
                }
            }
        }
        public bool FFUIsOK { get; set; }
        private LoadportCassetteState _cassetteState = LoadportCassetteState.None;
        public override LoadportCassetteState CassetteState
        {
            get { return _cassetteState; }
            set
            {
                _cassetteState = value;
            }
        }
 
        public bool Processed { get; set; }
        public bool Communication
        {
            get
            {
                return _port == null ? !_commErr : !_commErr && _port.IsOpen();
            }
        }
        //
        public override bool IsBusy
        {
            get { return _foregroundHandler != null || _handlers.Count > 0 ; }
        }
        
        public override  bool IsMoving
        {
            get { return _foregroundHandler != null && _handlers.Count > 0; }
        }
        public const string delimiter = "\r";
        public const int min_len = 3;       //S00
        private static Object _locker = new Object();
        private AsyncSerial _port;
        private bool _commErr = false;
        private IHandler _eventHandler = null;
        private IHandler _foregroundHandler = null;  //moving
        private Queue _handlers = new Queue();
 
        private IoSensor _sensorEnable = null;
        private IoTrigger _enableTrigger = null;
 
        public TDKLoadPort(string module, string name,  string port, IoSensor sensorEnable, IoTrigger triggerEnable,
            EnumLoadPortType portType =EnumLoadPortType.LoadPort)
            : base(module, name )
        {
            _port = new AsyncSerial(port, 9600, 8);
            _port.OnDataChanged +=  (OnDataChanged);
            _port.OnErrorHappened +=  (OnErrorHandler);
            _eventHandler = new handler(Name);
            _sensorEnable = sensorEnable;
            _enableTrigger = triggerEnable;
            Initalized = false;
            IsMapWaferByLoadPort = portType== EnumLoadPortType.LoadPort;
            PortType = portType;
            IndicatiorLoad = IndicatorState.UNKNOW;
            IndicatiorUnload = IndicatorState.UNKNOW;
            IndicatiorPresence = IndicatorState.UNKNOW;
            IndicatorAlarm = IndicatorState.UNKNOW;
            IndicatiorPlacement = IndicatorState.UNKNOW;
            IndicatiorOpAccess = IndicatorState.UNKNOW;
            IndicatiorStatus1 = IndicatorState.UNKNOW;
            IndicatiorStatus2 = IndicatorState.UNKNOW;
            DoorState = FoupDoorState.Unknown;
            ClampState = FoupClampState.Unknown;
            CassetteState = LoadportCassetteState.Unknown;
            if (!this.QueryState(out string reason))
            {
                EV.PostAlarmLog(module,$"Query state error.{reason}");
            }
            Enable = true;
            Address = port;
        }
        public void SetCassetteState(LoadportCassetteState state)
        {
            _cassetteState = state;
            if (state == LoadportCassetteState.Normal)
            {
                if (!_isPlaced)
                {
                    OnCarrierPlaced();
                }
                if (!_isPresent)
                {
                    OnCarrierPresent();
                }
            }
        }
        public override bool Initialize()
        {
            base.Initialize();
            
            _commErr = true;
            ConnectionManager.Instance.Subscribe($"{Name}", this);
            Connect();
            //if (!RetryInstance.Instance().Execute(
            //    ()=> _port.Open(),
            //    SC.GetValue("System.ComPortRetryDelayTime"),
            //    SC.GetValue("System.ComPortRetryCount"),
            //    true
            //))
            //{
            //    return false;
            //}
            
            return true;
        }
        public override bool Connect()
        {
            _commErr = false;
            Task.Factory.StartNew(() =>
            {
                int count = SC.ContainsItem("System.ComPortRetryCount") ? SC.GetValue("System.ComPortRetryCount") : 3;
                int sleep = SC.ContainsItem("System.ComPortRetryDelayTime") ? SC.GetValue("System.ComPortRetryDelayTime") : 2;
                if (sleep <= 0 || sleep > 10)
                    sleep = 2;
                int retry = 0;
                do
                {
                    if (_port.Open())
                    {
                        //LOG.Write($"Connected with {Module}.{Name} .");
                        EV.PostInfoLog(Module, $"Connected with {Module}.{Name} .");
                        break;
                    }
                    if (count > 0 && retry++ > count)
                    {
                        //LOG.Write($"Retry connect {Module}.{Name} stop retry.");
                        EV.PostAlarmLog(Module, $"Can't connect to {Module}.{Name}.");
                        break;
                    }
                    {
                        Thread.Sleep(sleep * 1000);
                        //LOG.Write($"Retry connect {Module}.{Name} for the {retry + 1} time.");
                    }
                } while (true);
            });
            return true;
        }
        public bool Disconnect()
        {
            return true;
        }
        public override bool IsEnableMapWafer()
        {
            if (IsIdle 
                && _isPresent 
                && _isPlaced 
                && DoorState == FoupDoorState.Open 
                && CassetteState == LoadportCassetteState.Normal
                )
                return true;
            return false;
        }
        public override bool IsEnableTransferWafer()
        {
            return IsEnableTransferWafer(out _);
        }
        public override bool IsEnableTransferWafer(out string reason)
        {
            reason = "";
            if (_isPlaced 
                && _isPresent 
                && _isMapped 
                && IsIdle 
                && DoorState==FoupDoorState.Open 
                && CassetteState==LoadportCassetteState.Normal
                )
                return true;
            return false;
        }
 
        /// 
        ///The Indicator is for EAP/Operator
        /// LOAD READY: LoadPort Ready to receive FOUP
        /// UNLOAD READY: FOUP ready to remove
        /// 
        /// 
        public void OnStateUpdated()
        {
            if (!SC.ContainsItem("Process.OptionLoadportMonitor") || !SC.GetValue("Process.OptionLoadportMonitor"))
                return;
            if (_isPresent && _isPlaced && this.ClampState == FoupClampState.Open) 
            {
                if (IndicatiorUnload != IndicatorState.ON)
                    SetIndicator(Indicator.UNLOAD, IndicatorState.ON);
                if (IndicatiorLoad != IndicatorState.OFF)
                    SetIndicator(Indicator.LOAD, IndicatorState.OFF);
                return;
            }
            if (!_isPresent || !_isPlaced)
            {
                if (IndicatiorUnload != IndicatorState.OFF)
                    SetIndicator(Indicator.UNLOAD, IndicatorState.OFF);
                if (IndicatiorLoad != IndicatorState.ON)
                    SetIndicator(Indicator.LOAD, IndicatorState.ON);
                return;
            }
            if (IndicatiorUnload != IndicatorState.OFF)
                SetIndicator(Indicator.UNLOAD, IndicatorState.OFF);
            if (IndicatiorLoad != IndicatorState.OFF)
                SetIndicator(Indicator.LOAD, IndicatorState.OFF);
        }
        public void OnAccessButtonPushed()
        {
            if (_isPresent && _isPlaced)
            {
            }
        }
 
        public override void Reset()
        {
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            FFUIsOK = true;
            _commErr = false;
            Enable = true;
            Error = false;
            base.Reset();
        }
        public override bool Home(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        
        public override bool ForceHome(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        public override bool FOSBMode(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        
        public override bool FOUPMode(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        public override bool FOSBDock(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        public override bool FOSBUnDock(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        public override bool FOSBDoorOpen(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        
        public override bool FOSBDoorClose(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        public override bool FOSBDoorUp(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        
        public override bool FOSBDoorDown(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name), out reason);
        }
        
        public override bool ClearError(out string reason)
        {
            reason = string.Empty;
            return execute(new handler(Name), out reason);
        }
        public override bool Stop(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                _foregroundHandler = null;
                _handlers.Clear();
            }
            return execute(new handler(Name, MovType.STOP_), out reason);
        }
 
        public override bool Load(out string reason)  //map and loads
        {
            return Move(MovType.CLDMP, out reason);
        }
        public override bool LoadWithoutMap(out string reason)
        {
            return Move(MovType.CLOAD, out reason);
        }
        public override bool Unload(out string reason)
        {
            return Move(MovType.CULOD, out reason);
        }
        public override bool Clamp(out string reason)
        {
            return Move(MovType.PODCL, out reason);
        }
        public override bool Unclamp(out string reason)
        {
            return Move(MovType.PODOP, out reason);
        }
        public override bool Dock(out string reason)
        {
            return Move(MovType.CLDDK, out reason);
        }
        public override bool Undock(out string reason)
        {
            return Move(MovType.CULFC, out reason);  //????
        }
        public override bool OpenDoor(out string reason)
        {
            return Move(MovType.CLMPO, out reason);
        }
        public override bool OpenDoorNoMap(out string reason)
        {
            return Move(MovType.CLDOP, out reason);
        }
        public override bool CloseDoor(out string reason)
        {
            return Move(MovType.CULDK, out reason);
        }
        public override bool SetIndicator(Indicator light, IndicatorState op, out string reason)
        {
            reason = string.Empty;
            return execute(new handler(Name, light, op), out reason);
        }
        public bool SetOnlineMode(out string reason)
        {
            reason = string.Empty;
            return execute(new handler(Name, Mode.ONMGV), out reason);
        }
        public override bool QueryState(out string reason)
        {
            reason = string.Empty;
            return execute(new handler(Name), out reason);
        }
        public override bool QueryIndicator(out string reason)
        {
            reason = string.Empty;
            return execute(new handler(Name), out reason);
        }
        public override bool QueryWaferMap(out string reason)
        {
            reason = string.Empty;
            return execute(new handler(DeviceID), out reason);
        }
        public override bool QueryFOSBMode(out string reason)
        {
            reason = string.Empty;
            return execute(new handler(DeviceID), out reason);
        }
        
        public bool Move(MovType fun, out string reason)
        {
            reason = string.Empty;
            return execute(new handler(Name, fun), out reason);
        }
        //public bool Query(QueryType type, out string reason)
        //{
        //    reason = string.Empty;
        //    return execute(new handler(Name), out reason);
        //}
        public bool SetEvent(EvtType fun, out string reason)
        {
            reason = string.Empty;
            return execute(new handler(Name, fun), out reason);
        }
        public bool OnEvent(out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                if (!execute(new handler(Name), out reason))
                    return false;
                //execute(new handler(Name), out reason);
                //LoadLight();
                //UnloadLight();
                return execute(new handler(Name), out reason);
            }
        }
        private bool execute(IHandler handler, out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                if (_foregroundHandler == null)
                {
                    if (!handler.Execute(ref _port))
                    {
                        reason = "Communication failed, please recovery it.";
                        return false;
                    }
                    _foregroundHandler = handler;
                }
                else
                {
                    //LOG.Info(string.Format("Add command {0}", handler.ToString()));
                    _handlers.Enqueue(handler);
                }
      
            }
            return true;
        }
        private bool execute(out string reason)
        {
            reason = string.Empty;
            lock(_locker)
            {
                if (_handlers.Count > 0)
                {
                    IHandler handler = _handlers.Dequeue();
                    if (!handler.Execute(ref _port))
                    {
                        reason = " communication failed, please recovery it.";
                        //LOG.Error(reason);
                        EV.PostMessage(Name, EventEnum.DefaultWarning, "【Reader】" + reason);
                        return false;
                    }
                    _foregroundHandler = handler;
                }
            }
            return true;
        }
        private void OnDataChanged(string package)
        {
            try
            {
                package = package.ToUpper();
                string[] msgs = Regex.Split(package, delimiter);
                foreach (string msg in msgs)
                {
                    if (msg.Length > min_len)
                    {
                        bool completed = false;
                        string resp = msg.Substring(3, msg.Length - min_len);
                        lock (_locker)
                        {
                            if (_foregroundHandler != null && _foregroundHandler.OnMessage(ref _port, resp, out completed))
                            {
                                string reason = string.Empty;
                                if (!_foregroundHandler.IsBackground)
                                {
                                    _foregroundHandler = null;
                                    execute(out reason);
                                }
                                else
                                {
                                    if (completed)
                                    {
                                       _foregroundHandler = null;
                                       QueryState(out reason);
                                        if (_foregroundHandler is handler)
                                        {
                                            QueryIndicator(out reason);
                                        }
                                    }
                                }
                               
                            }
                            else
                            {
                                _eventHandler.OnMessage(ref _port, resp, out completed);  //process event
                            }
                        }
                    }
                }
            }
            catch (ExcuteFailedException ex)
            {
                EV.PostWarningLog(Module, $"{Name} action failed, "+ex.Message);
                _foregroundHandler = null;
                OnError();
            }
            catch (InvalidPackageException ex)
            {
                EV.PostWarningLog(Module, $"{Name} received unprocessed message, {ex.Message}" );
                OnError();
            }
            catch (Exception ex)
            {
                LOG.WriteExeption($" {Name} has exception:" , ex);
            }
        }
        private void OnErrorHandler(ErrorEventArgs args)
        {
            _commErr = true;
            Initalized = false;
 
            EV.PostAlarmLog(Module, $"{Display} Communication error, {args.Reason}");
            OnError();
         }
        public  void OnCarrierNotPlaced()
        {
            _isPlaced = false; 
            ConfirmRemoveCarrier();
        }
        public  void OnCarrierNotPresent()
        {
            _isPresent = false;
            ConfirmRemoveCarrier();
        }
 
        public  void OnCarrierPlaced()
        {
            _isPlaced = true;
            ConfirmAddCarrier();
        }
        public  void OnCarrierPresent()
        {
            _isPresent = true;
            ConfirmAddCarrier();
        }
        public void OnSwitchKey1()
        {
 
        }
        public void OnSwitchKey2()
        {
 
        }
        public void SetIndicator(Indicator led, IndicatorState state)
        {
            SetIndicator(led, state, out string reason);
        }
        //impment E84 interface
        public bool ReadyForLoad()
        {
            return CassetteState == LoadportCassetteState.Absent;
        }
        public bool ReadyForUnload()
        {
            return CassetteState == LoadportCassetteState.Normal;
        }
        public bool FoupArrirved()
        {
            return CassetteState == LoadportCassetteState.Normal;
        }
        public bool FoupRemoved()
        {
            return CassetteState == LoadportCassetteState.Absent; 
        }
        
    }
}