/// <summary>
        /// method called from the ConnectThread. Called when telnet startup has been
        /// completed. Telnet client is now ready to process workstation messages and
        /// render them to the canvas.
        /// </summary>
        /// <param name="obj"></param>
        private void MainWindow_TelnetStartupComplete(bool obj, TypeTelnetDevice?TypeDevice)
        {
            // send message to FromThread telling it the connection is complete and the
            // device type.
            {
                var message = new TelnetDeviceAttrMessage(TypeDevice.Value);
                this.FromThread.PostInputMessage(message);
            }

            // start the master screen content thread.
            {
                var    job = new ThreadStart(this.MasterThread.EntryPoint);
                Thread t   = new Thread(job);
                t.IsBackground = true;
                t.Name         = "MasterThread";
                t.Start();
            }

            // start the printer thread.
            if (TypeDevice.Value == TypeTelnetDevice.Printer)
            {
                var    job = new ThreadStart(this.PrinterThread.EntryPoint);
                Thread t   = new Thread(job);
                t.IsBackground = true;
                t.Name         = "PrinterThread";
                t.Start();
            }

            // start the paint thread. This thread reads WorkstationCommand blocks that are
            // created by the FromThread and paints them to the ItemCanvas.
            {
                var    job = new ThreadStart(this.PaintThread.EntryPoint);
                Thread t   = new Thread(job);
                t.IsBackground = true;
                t.Name         = "PaintThread";
                t.Start();
            }

            // start the match thread. This thread matches the screenContent against the
            // ScreenDefn screen definitions.  The screen defn contains hover scripts,
            // screen enhancements, etc.
            {
                var    job = new ThreadStart(this.MatchThread.EntryPoint);
                Thread t   = new Thread(job);
                t.IsBackground = true;
                t.Name         = "MatchThread";
                t.Start();

                // the model can send alert messages to the threads. set ref to the threads.
                this.Model.MatchThread = this.MatchThread;

                // send the screenDefnList to the match thread.
                var screenDefnList = new ScreenDefnList(this.Model.ScreenDefnObservableList);
                var assignMessage  = new AssignScreenDefnListMessage(screenDefnList);
                this.MatchThread.PostInputMessage(assignMessage);
            }

            // start the capture thread. This thread capture screen contents according
            // to a screen defn. Captured data is stored to database, stream file or
            // clipboard.
            {
                var    job = new ThreadStart(this.CaptureThread.EntryPoint);
                Thread t   = new Thread(job);
                t.IsBackground = true;
                t.Name         = "CaptureThread";
                t.Start();

                // the model can send alert messages to the threads. set ref to the threads.
                this.Model.CaptureThread = this.CaptureThread;
            }

            // todo: make this two method calls.
            //       FindSelectCanvas( ). then SetCanvasFocus( ).
            //       also, move SetCanvasFocus into Canvas class. probably make a
            //       Canvas class extension method. SetCompleteFocus. But try to make
            //       ItemCanvas to have Canvas as a base class.
            FindCanvasSetFocus();
        }
        /// <summary>
        /// parse from current byte forward in the InputArray. Will either parse a
        /// telnet command or a workstation command.
        /// Route what was parsed to either the FromQueue or the MasterThread. Send to
        /// the FromQueue if still receiving telnet commands. Otherwise, send to the
        /// MasterThread.
        /// </summary>
        /// <param name="InputArray"></param>
        /// <param name="WipCmdList"></param>
        /// <returns></returns>
        private Tuple <WorkstationCommandList, bool> ParseAndPostInputArray(
            InputByteArray InputArray, WorkstationCommandList WipCmdList)
        {
            WorkstationCommandList wipCmdList = null;
            bool gotSomething = false;

            if (WipCmdList == null)
            {
                var telCmd = InputArray.NextTelnetCommand();
                if (telCmd != null)
                {
                    this.TelnetQueue.Enqueue(telCmd);
                    gotSomething = true;
                }
            }

            if (gotSomething == false)
            {
                // peek at the input stream from server. Classify the data that is next
                // to receive.
                var typeData = ServerDataStream.PeekServerCommand(InputArray);
                if (typeData != null)
                {
                    var rv = Process5250.ParseWorkstationCommandList(
                        InputArray, this.SessionSettings);

                    var dsh = rv.Item1;
                    var workstationCmdList = rv.Item2;
                    var gotEOR             = rv.Item3;
                    var needMoreBytes      = rv.Item4;

                    // update connectionComplete flag and typeDevice depending on the stream
                    // code of the datastream header.
                    if ((this.ConnectionComplete == false) && (dsh != null) && (dsh.StreamCode != null))
                    {
                        this.ConnectionComplete = true;
                        if (dsh.StreamCode.Value == DataStreamCode.Terminal)
                        {
                            this.TypeDevice = TypeTelnetDevice.Terminal;
                        }
                        else
                        {
                            this.TypeDevice = TypeTelnetDevice.Printer;
                        }

                        // post message to telnet queue so that the ConnectionThread on the
                        // other end will know to shutdown.
                        var message = new TelnetDeviceAttrMessage(this.TypeDevice.Value);
                        this.TelnetQueue.Enqueue(message);
                    }

                    // got data stream header.
                    if (dsh != null)
                    {
                        if (this.ConnectionComplete == false)
                        {
                            this.TelnetQueue.Enqueue(dsh);
                        }
                        else
                        {
                            var message = new DataStreamHeaderMessage(dsh);
                            PostToProcessQueue(message);
                        }
                        gotSomething = true;
                    }

                    if (workstationCmdList != null)
                    {
                        gotSomething = true;
                    }

                    // accum the workstationCmdList
                    if (WipCmdList == null)
                    {
                        wipCmdList = workstationCmdList;
                    }
                    else
                    {
                        wipCmdList = WipCmdList;
                        wipCmdList.AddRange(workstationCmdList);
                    }

                    // got EOR.  store the now completed workstationCmdList.
                    if ((gotEOR == true) && (wipCmdList != null))
                    {
                        var msg = new WorkstationCommandListMessage(wipCmdList);
                        PostToProcessQueue(msg);
                        gotSomething = true;
                        wipCmdList   = null;
                    }
                }
            }

            return(new Tuple <WorkstationCommandList, bool>(wipCmdList, gotSomething));
        }