using System;
using System.Text.RegularExpressions;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using Aitex.Core.RT.Device;
using MECF.Framework.Common.Communications;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot.NX100.AL;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot.SR100.AL;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot
{
  
    public class Aligner : BaseDevice, IDevice,IConnection
    {
        public string Address
        {
            get { return _addr; }
        }

        public virtual bool IsConnected
        {
            get { return _socket.IsConnected; }
        }

        public virtual bool Disconnect()
        {
            return true;
        }
        public virtual bool Connect()
        {
            return true;
        }
        public const string delimiter = "\r";

        public int LastErrorCode { get; set; }
        public int Status { get; set; }
        public int ErrorCode { get; set; }


        public int ElapseTime { get; set; }

        public int Notch { get;  set; }

        public bool Initalized { get; set; }


        public bool Communication
        {
            get
            {
                return !_commErr;
            }
        }


        public virtual bool Busy
        {
            get { return _backgroundHandler != null || _foregroundHandler != null; }
        }
        public virtual bool Moving
        {
            get { return _backgroundHandler != null; }
        }

        public virtual bool Error
        {
            get
            {
                return ErrorCode >= Convert.ToInt32("2EB0",16)|| _commErr;
            }
        }

        //public string ErrorMessage
        //{
        //    get
        //    {
        //        return _factory.GetError(LastErrorCode);
        //    }
        //}

        public DeviceState State
        {
            get
            {
                if (!Initalized)
                {
                    return DeviceState.Unknown;
                }
                if (Error)
                {
                    return DeviceState.Error;
                }

                if (Busy)
                    return DeviceState.Busy;

                return DeviceState.Idle;
            }
        }

        public virtual bool WaferOnAligner
        {   
            get
            {
                return (Status & ((int)StateBit.WaferOnGrip | (int)StateBit.WaferOnCCD)) > 0; 
            } 
        }

        public bool StateWaferHold { get; set; }

        private static Object _locker = new Object();
        private AsyncSocket _socket;


        private IHandler _eventHandler = null;
        private IHandler _backgroundHandler = null;  //moving
        private IHandler _foregroundHandler = null;  //current handler

        private IAlignerHandlerFactory _factory = null;

        private bool _commErr = false;
        //private bool _exceuteErr = false;
        private string _addr;


        private DeviceTimer _timerQuery = new DeviceTimer();
        //private int _queryPeriod = 5000;    //ms
        //private bool _queryState = true;

        private RobotType _type = RobotType.SR100;

        private string AlarmAlignerMotionError = "AlignerMotionError";
        public Aligner(string module, string name, string display, string deviceId, string address, RobotType type = RobotType.SR100)
            : base(module, name, display, deviceId)
        {
            _addr = address;
            if (!string.IsNullOrEmpty(_addr))
            {
                _socket = new AsyncSocket(address);
                _socket.OnDataChanged += new AsyncSocket.MessageHandler(OnDataChanged);
                _socket.OnErrorHappened += new AsyncSocket.ErrorHandler(OnErrorHandler);
            }
            _type = type;           

            Initalized = false;
            _commErr = false;

            WaferManager.Instance.SubscribeLocation(name, 1);
        }

        public virtual bool Initialize()
        {
            switch (_type)
            {
                case RobotType.NX100:
                    _factory = new NX100AlignerHandlerFactory(this);
                    break;
                default:
                    _factory = new SR100AlignerHandlerFactory(this);
                    break;
            }
            _eventHandler = _factory.Event();

            ConnectionManager.Instance.Subscribe(Name, this);

            if(!string.IsNullOrEmpty(_addr))
                _socket.Connect(this._addr);

            DEVICE.Register(String.Format("{0}.{1}", Name, "Init"), (out string reason, int time, object[] param) =>
            {
                bool ret = Init(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Init");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerInit"), (out string reason, int time, object[] param) =>
            {
                bool ret = Init(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Init");
                    return true;
                }

                return false;
            });

            DEVICE.Register(String.Format("{0}.{1}", Name, "Home"), (out string reason, int time, object[] param) =>
            {
                bool ret = Home(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Home");
                    return true;
                }

                return false;
            });

            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerHome"), (out string reason, int time, object[] param) =>
            {
                bool ret = Home(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Home");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "Reset"), (out string reason, int time, object[] param) =>
            {
                bool ret = Clear(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Reset Error");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerReset"), (out string reason, int time, object[] param) =>
            {
                bool ret = Clear(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Reset Error");
                    return true;
                }

                return false;
            });

            DEVICE.Register(String.Format("{0}.{1}", Name, "Grip"), (out string reason, int time, object[] param) =>
            {
                bool ret = Grip(0,out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Hold Wafer");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerGrip"), (out string reason, int time, object[] param) =>
            {
                bool ret = Grip(0, out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Hold Wafer");
                    return true;
                }

                return false;
            });

            DEVICE.Register(String.Format("{0}.{1}", Name, "Release"), (out string reason, int time, object[] param) =>
            {
                bool ret = Release(0, out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Release Wafer");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerRelease"), (out string reason, int time, object[] param) =>
            {
                bool ret = Release(0, out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Release Wafer");
                    return true;
                }

                return false;
            });



            DEVICE.Register(String.Format("{0}.{1}", Name, "LiftUp"), (out string reason, int time, object[] param) =>
            {
                bool ret = LiftUp(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Lifter Up");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerLiftUp"), (out string reason, int time, object[] param) =>
            {
                bool ret = LiftUp(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Lifter Up");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "LiftDown"), (out string reason, int time, object[] param) =>
            {
                bool ret = LiftDown(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Lifter Down");
                    return true;
                }

                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerLiftDown"), (out string reason, int time, object[] param) =>
            {
                bool ret = LiftDown(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Lifter Down");
                    return true;
                }

                return false;
            });


            DEVICE.Register(String.Format("{0}.{1}", Name, "Stop"), (out string reason, int time, object[] param) =>
            {
                bool ret = Stop(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Stop Align");
                    return true;
                }
                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerStop"), (out string reason, int time, object[] param) =>
            {
                bool ret = Stop(out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "Stop Align");
                    return true;
                }
                return false;
            });


            DEVICE.Register(String.Format("{0}.{1}", Name, "Align"), (out string reason, int time, object[] param) =>
            {
                double angle = double.Parse((string)param[0]);
                bool ret = Align(angle, out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "PreAlign");
                    return true;
                }
                return false;
            });
            DEVICE.Register(String.Format("{0}.{1}", Name, "AlignerAlign"), (out string reason, int time, object[] param) =>
            {
                double angle = double.Parse((string)param[0]);
                bool ret = Align(angle, out reason);
                if (ret)
                {
                    reason = string.Format("{0} {1}", Name, "PreAlign");
                    return true;
                }
                return false;
            });

            DATA.Subscribe($"{Name}.State", () => State);
            DATA.Subscribe($"{Name}.AlignerState", () => State.ToString());

            DATA.Subscribe($"{Name}.Busy", () => Busy);

            DATA.Subscribe($"{Name}.ErrorCode", () => ErrorCode);

            DATA.Subscribe($"{Name}.Error", () => Error);

            DATA.Subscribe($"{Name}.ElapseTime", () => ElapseTime);

            DATA.Subscribe($"{Name}.Notch", () => Notch);

            DATA.Subscribe($"{Name}.WaferOnAligner", () => WaferOnAligner);

//            string str = string.Empty;
            EV.Subscribe(new EventItem(0,"Event", AlarmAlignerMotionError, "Aligner error", EventLevel.Alarm, Aitex.Core.RT.Event.EventType.HostNotification));

//            _timerQuery.Start(_queryPeriod);

            return true;
        }

        public virtual void Terminate()
        {
            _socket.Dispose();
        }

        public virtual void Reset()
        {
            lock (_locker)
            {
                _foregroundHandler = null;
                _backgroundHandler = null;
            }
            
            //_exceuteErr = false;
            if (_commErr)
            {
                _commErr = false;
                _socket.Connect(this._addr);
            }
        }


        #region Command
        public virtual bool Init(out string reason)
        {
            reason = string.Empty;
            return execute(_factory.Init(), out reason);
        }
        public virtual bool Home(out string reason)
        {
            reason = string.Empty;
            return execute(_factory.Home(), out reason);
        }

        public virtual bool Clear(out string reason)
        {
            reason = string.Empty;
            return execute(_factory.Clear(), out reason);
        }

        public virtual bool Grip(Hand hand, out string reason)
        {
            reason = string.Empty;
            return execute(_factory.Grip(hand), out reason);
        }

        public virtual bool Release(Hand hand, out string reason)
        {
            reason = string.Empty;
            return execute(_factory.Release(hand), out reason);
        }


        public virtual bool LiftUp(out string reason)
        {
            reason = string.Empty;
            return execute(_factory.LiftUp(), out reason);
        }

        public virtual bool LiftDown(out string reason)
        {
            reason = string.Empty;
            return execute(_factory.LiftDown(), out reason);
        }
        public virtual bool MoveToReady(out string reason)
        {
            reason = string.Empty;
            return execute(_factory.MoveToReadyPostion(), out reason);
        }


        public virtual bool Stop(out string reason)
        {
            reason = string.Empty;

            lock (_locker)
            {
                _foregroundHandler = null;
                _backgroundHandler = null;
            }
            return execute(_factory.Stop(), out reason);
        }

        public virtual bool Align(double angle, out string reason)
        {
            reason = string.Empty;
            return execute(_factory.Align(angle), out reason);
        }


        public virtual bool QueryState(out string reason)
        {
            reason = string.Empty;
            return execute(_factory.QueryState(), out reason);
        }

        #endregion


        private bool execute(IHandler handler, out string reason)
        {
            reason = string.Empty;
            lock (_locker)
            {
                if (_foregroundHandler != null)
                {
                    reason = "System busy, please wait or reset system.";
                    EV.PostMessage(Name, EventEnum.DefaultWarning, string.Format("{0} {1} {2}", this.DeviceID, handler.ToString(), reason));

                    return false;
                }

                if (_backgroundHandler != null && handler.IsBackground)
                {
                    reason = "System busy，one background command is running, please wait or reset system.";
                    EV.PostMessage(Name, EventEnum.DefaultWarning, string.Format("{0} {1} {2}", this.DeviceID, handler.ToString(), reason));
                    return false;
                }
                handler.Unit = (int)RobotUnit.Aligner;
                if(!handler.Execute(ref _socket))
                {
                    reason = "Communication error,please check it.";
                    return false;
                }

                if (handler.IsBackground)
                    _backgroundHandler = handler;
                else
                    _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 > 0)
                    {
                        bool completed = false;
                        string resp = msg;

                        lock (_locker)
                        {
                            if (_foregroundHandler != null && _foregroundHandler.OnMessage(ref _socket, resp, out completed))
                            {
                                 _foregroundHandler = null;
                            }
                            else if (_backgroundHandler != null && _backgroundHandler.OnMessage(ref _socket, resp, out completed))
                            {
                                if (completed)
                                {
                                    string reason = string.Empty;
                                    QueryState(out reason);
                                    _backgroundHandler = null;
                                }
                            }
                            else
                            {
                                if (_eventHandler != null)
                                {
                                    if (_eventHandler.OnMessage(ref _socket, resp, out completed))
                                    {
                                        if (completed)
                                        {
                                            EV.PostMessage("Aligner", EventEnum.DefaultWarning, string.Format(" has error. {0:X}", ErrorCode));
                                            OnError(string.Format(" has error. {0:X}", ErrorCode));//_exceuteErr = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (ExcuteFailedException e)
            {
                EV.PostMessage("Aligner", EventEnum.DefaultWarning, string.Format("executed failed. {0}", e.Message));
                OnError(string.Format("executed failed. {0}", e.Message));
            }
            catch (InvalidPackageException e)
            {
                EV.PostMessage("Aligner", EventEnum.DefaultWarning, string.Format("receive invalid package. {0}", e.Message));
                OnError(string.Format("receive invalid package. {0}", e.Message));
            }
            catch (System.Exception ex)
            {
                _commErr = true;
                LOG.Write("Aligner failed：" + ex.ToString());
            }
        }

        private void OnErrorHandler(ErrorEventArgs args)
        {
            Initalized = false;
            _commErr = true;

            EV.PostMessage(Module, EventEnum.CommunicationError, Display, args.Reason);

            OnError("Communciation Error");

            //LOG.Error(string.Format("{0} Communication failed, {1}", Name, args.Reason));
        }

        //private bool checkslot(int min, int max, int slot)
        //{
        //    return slot >= min && slot < max;
        //}

        private void OnError(string errortext)
        {
            EV.Notify(AlarmAlignerMotionError,new SerializableDictionary<string, object> {
                {"AlarmText",errortext }
            });
        }
    }
}

  