/// <summary>
        /// Simple handler for the NATS protocol state-machine
        /// </summary>
        /// <param name="segment"></param>
        /// <param name="op"></param>
        private void NotifyOperationHandler(
            ArraySegment <byte> segment,
            int op
            )
        {
            switch (this._workerStage)
            {
            case StageWaitInfo:
                if (op == Parser.INFO_ARG)
                {
                    this._info = this.ProcessInfo(segment, false);

                    // This will check to see if the connection should be
                    // secure. This can be dictated from either end and should
                    // only be called after the INIT protocol has been received.

                    // Check to see if we need to engage TLS
                    // Check for mismatch in setups
                    bool currentIsSecured = this._srvPool.CurrentServer.EndPoint.Secured;
                    if (currentIsSecured && this._info.TlsRequired == false)
                    {
                        throw new NATSSecureConnWantedException();
                    }
                    else if (this._info.TlsRequired && currentIsSecured == false)
                    {
                        throw new NATSSecureConnRequiredException();
                    }

                    // Need to rewrap with bufio
                    if (currentIsSecured)
                    {
                        // makeSecureConn will wrap an existing Conn using TLS
                        this._tcp.MakeTLS();
                    }
                }
                break;

            case StageSendConnectVerbose:
                if (op == Parser.OP_PLUS_OK)
                {
                    this._workerStage = StageSendConnectNormal;
                }
                break;

            case StageSendConnectNormal:
                if (op == Parser.OP_PONG)
                {
                    this._workerStage = StageLogicallyConnected;
                }
                break;

            case StageLogicallyConnected:
                if (op == Parser.OP_PING)
                {
                    this.ProcessPing();
                }
                else if (op == Parser.OP_PONG)
                {
                    this.ProcessPong();
                }
                break;

            default:
                throw new NotSupportedException("worker-stage not supported: " + this._workerStage);
            }
        }
        /// <summary>
        /// The "inner" worker
        /// </summary>
        /// <remarks>
        /// This method can raise any kind of exception, which will be caught by the <see cref="OuterWorker(object)"/>.
        /// </remarks>
        /// <param name="ctx"></param>
        private void InnerWorker(
            WorkerContext ctx
            )
        {
            this._info = null;

            /**
             * Initial connection to a server
             **/
            try
            {
                this._tcp = this._srvPool.ConnectToAServer(
                    this._workerStage == StageServerInitialConnection,
                    ctx.CancToken
                    );

                if (this._tcp == null)
                {
                    throw new Exception();
                }
            }
            catch (OperationCanceledException ex)
            {
                throw ex;
            }
            catch (Exception)
            {
                throw new NATSNoServersException("Unable to connect to a server.");
            }


            /**
             * Waiting for the "INFO" data issued by the server
             **/
            this._workerStage = StageWaitInfo;
            this.ReadThenParseSegment(null, null, ReadTimeout, ctx.CancToken);

            if (this._info == null)
            {
                throw new NATSConnectionException("Protocol exception, INFO not received");
            }


            /**
             * Send "CONNECT" to the server
             **/
            this._workerStage = this._options.Verbose
                ? StageSendConnectVerbose
                : StageSendConnectNormal;

            try
            {
                this._tcp.SocketSendTimeout = 0;
                this._tcp.WriteString(this.ConnectProto());
                this.SendPing();
            }
            catch (Exception ex)
            {
                throw new NATSException("Error sending connect protocol message", ex);
            }

            this.ReadThenParseSegment(
                ex => throw new NATSConnectionException("Connect read error", ex),
                null,
                ReadTimeout,
                ctx.CancToken
                );

            if (this._workerStage != StageLogicallyConnected)
            {
                throw new NATSConnectionException("Connect read protocol error");
            }


            /**
             * Main processing loop
             **/
            this._tcp.SocketReceiveTimeout = ReadTimeout;   //for safety
            this.SetStatus(ConnState.CONNECTED);
            this.PingStart();
            this._owner.RequestReplyManager.Start();

            int readCount = 0;

            while (ctx.CancToken.IsCancellationRequested == false)
            {
                if (this._writePending)
                {
                    //something to send is pending
                    lock (this._writeLocker)
                    {
                        //is PING, maybe?
                        if (this._pingSendPending)
                        {
                            this.SendPing();
                        }

                        //are one or more SUB messages, maybe?
                        if (this._subPending)
                        {
                            for (int i = 0, sublen = this._subQueue.Count; i < sublen; i++)
                            {
                                this._tcp.WriteString(this._subQueue[i]);
                            }
                            this._subQueue.Clear();
                            this._tcp.WriteFlush();
                            this._subPending = false;
                        }

                        this._writePending = false;
                    }
                }
                else if (this._isLogicalStarted)
                {
                    if (readCount == 0)
                    {
                        //no operation was perfomed: no data in, no data out.
                        //the cycle would be too tight, then.
                        //give the OS a breathe of fresh air...
                        Thread.Sleep(1);
                    }
                }
                else
                {
                    //the initial NATS handshake with the server is complete:
                    //if the start was async, then consider its task as terminated
                    this._isLogicalStarted = true;
                    ctx.TaskCompletion?.SetResult(null);
                }

                //listen to incoming data
                readCount = this.ReadThenParseSegment(
                    this.ProcessOpError,
                    this.ProcessOpError,
                    0,
                    ctx.CancToken
                    );
            }
        }