/// <summary>
        ///
        /// </summary>
        /// <param name="timeoutMilliSecs"></param>
        public void Suspend(int timeoutMilliSecs = 0)
        {
            if (EngineStatus == EngineStatusEnum.NonState           // not started yet
                | EngineStatus == EngineStatusEnum.PausedState      // already suspended
                | ShouldCancelAction(EngineStatusEnum.PausedState)) // or client has cancelled.
            {
                return;
            }

            _agentCmdSlag = new AgentCommandSlag()
            {
                StatusRequest = EngineStatusEnum.PausedState,
                TimeOut       = timeoutMilliSecs == 0 ? -1 : timeoutMilliSecs
            };
            _intervalDelayEvent.Set();
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="timeOut"></param>
        public void Shutdown(int timeOut = 0)
        {
            if (EngineStatus == EngineStatusEnum.NonState
                | ShouldCancelAction(EngineStatusEnum.NonState))
            {
                return;
            }

            _agentCmdSlag = new AgentCommandSlag()
            {
                StatusRequest = EngineStatusEnum.NonState,
                TimeOut       = timeOut
            };

            _intervalDelayEvent.Set();
            _pauseEvent.Set();
        }
        /// <summary>
        ///
        /// </summary>
        protected void ServiceActionEngine()
        {
            void ExecutePause()
            {
                if (_intervalDelayEvent.WaitOne(IntervalDelay))
                {
                    if (EngineStatus == EngineStatusEnum.NonState)
                    {
                        OnReadyState?.Invoke(this, new EventArgs());
                        _pauseEvent.WaitOne(Timeout.Infinite);

                        EngineStatus = EngineStatusEnum.RunningState;
                        OnEngineStatusChanged?.Invoke(this, new EngineStatusChangedEventArgs(EngineStatus));
                    }

                    if (_agentCmdSlag != null)
                    {
                        switch (_agentCmdSlag.StatusRequest)
                        {
                        case EngineStatusEnum.PausedState:
                            EngineStatus = EngineStatusEnum.PausedState;
                            OnEngineStatusChanged?.Invoke(this, new EngineStatusChangedEventArgs(EngineStatus));

                            _pauseEvent.WaitOne(
                                _agentCmdSlag.TimeOut < 0 ? Timeout.Infinite : _agentCmdSlag.TimeOut);

                            EngineStatus = EngineStatusEnum.RunningState;
                            break;

                        case EngineStatusEnum.NonState:
                            _initialized   = false;
                            _firstTimeTick = false;

                            _stopEvent.Set();
                            _intervalDelayEvent = new AutoResetEvent(true);
                            _pauseEvent         = new AutoResetEvent(false);

                            ServiceActionOnShutdown(_agentCmdSlag.TimeOut);
                            EngineStatus = EngineStatusEnum.NonState;

                            break;
                        }

                        _agentCmdSlag = null;
                        OnEngineStatusChanged?.Invoke(this, new EngineStatusChangedEventArgs(EngineStatus));
                    }
                    Thread.Sleep(1);
                }
            }

            lock (_locker)
            {
                do
                {
                    if (_firstTimeTick)
                    {
                        _firstTimeTick = false;
                        ExecutePause();
                        continue;
                    }

                    _running = true;
                    ServiceActionCallback();
                    ExecutePause();
                }while (!_stopEvent.WaitOne(0));
                // <- If millisecondsTimeout is zero, the method does not block.
                // It will test the state of the wait handle and returns immediately.
                _running = false;
            }
        }