//
        // *****************************************************
        // ****             Request Stop()                  ****
        // *****************************************************
        public override void RequestStop()
        {
            FrontEndRequest request = new FrontEndRequest();

            request.Type = FrontEndRequest.Request.Stop;
            this.HubEventEnqueue(request);
        }
        }// TryRequestDisplay()

        //
        //
        //
        //
        //
        // *****************************************************
        // ****             Request Stop()                  ****
        // *****************************************************
        public override void Start()
        {
            FrontEndRequest request = new FrontEndRequest();

            request.Type = FrontEndRequest.Request.Start;
            this.HubEventEnqueue(request);
            base.Start();
        }
        }//end constructor

        //
        //
        //
        #endregion//Constructors


        #region no Properties
        // *****************************************************************
        // ****                     Properties                          ****
        // *****************************************************************
        //
        //
        #endregion//Properties


        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        //
        //
        // *****************************************
        // ****			AddEngineHub()			****
        // *****************************************
        /// <summary>
        /// Submit a request to connect to a specific EngineHub.
        /// Currently, only one engineHub is serviced - but this may change.
        /// Called by external thread.
        /// </summary>
        /// <param name="engineHub">EngineHub to be monitored.</param>
        public void AddEngineHub(string engineHub)
        {
            FrontEndRequest request = new FrontEndRequest();

            request.Type       = FrontEndRequest.Request.AddService;
            request.ObjectList = new List <object>();
            request.ObjectList.Add(engineHub);
            this.HubEventEnqueue(request);
        }        //end AddEngineHub().
        //
        #endregion//HubEvent processing


        #region External Event Handlers
        // *****************************************************************
        // ****                     Event Handlers                      ****
        // *****************************************************************
        //
        //
        // ****				ClusterDisplay_FormClosing()			****
        //
        /// <summary>
        /// Called when the user closes a Display.  I will request it to be
        /// removed from my list.
        /// Called by an external thread.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="eventArgs"></param>
        private void ClusterDisplay_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs eventArgs)
        {
            if (sender.GetType() == typeof(ClusterDisplay))
            {
                FrontEndRequest request = new FrontEndRequest();
                request.Type       = FrontEndRequest.Request.RemoveDisplay;
                request.ObjectList = new List <object>();
                request.ObjectList.Add(sender);
                HubEventEnqueue(request);
            }
        }        //ClusterDisplay_FormClosing().
        }        //end AddEngineHub().

        //
        //
        // *****************************************
        // ****         Request Display()       ****
        // *****************************************
        /// <summary>
        /// User request creation of new display.  The request
        /// generates a call to get the GuiTemplates, and then
        /// automatically opens the form when completed.
        /// TODO:
        ///     1) Allow user to choose which hub to create display for.
        ///     2) Allow user to choose which Clusters are added, etc.
        /// </summary>
        public bool TryRequestDisplay(string engineHubName = null)
        {
            // Create the request
            FrontEndRequest request = new FrontEndRequest();

            request.Type       = FrontEndRequest.Request.AddDisplay;
            request.ObjectList = new List <object>();
            request.ObjectList.Add(engineHubName);
            this.HubEventEnqueue(request);
            return(true);
        }// TryRequestDisplay()
        }        //ProcessEngineEvents()

        //
        //
        //
        // *****************************************************************
        // ****					Process FrontEndRequest					****
        // *****************************************************************
        /// <summary>
        /// These are my internal requests, used to create new GUI displays, etc.
        /// </summary>
        /// <param name="request"></param>
        private void ProcessFrontEndRequest(FrontEndRequest request)
        {
            EngineEventArgs e;

            Log.NewEntry(LogLevel.Minor, "FrontEndRequest {0}", request.ToString());
            switch (request.Type)
            {
            case FrontEndRequest.Request.Start:
                // ************************************
                // ***          Start               ***
                // ************************************
                m_ServiceState = ServiceStates.Running;                 // We are ready to run.
                OnServiceStateChanged();
                break;

            case FrontEndRequest.Request.Stop:
                // ************************************
                // ***          Stop                ***
                // ************************************
                if (m_ServiceState != ServiceStates.Stopping)
                {                                            // Shut down displays
                    m_ServiceState = ServiceStates.Stopping; // Trying to stop.
                    OnServiceStateChanged();
                    // Tell displays to shut down.
                    foreach (ClusterDisplay display in m_ClusterDisplays.Values)
                    {
                        if (display != null && (!display.IsDisposed))
                        {
                            try
                            {
                                display.Invoke((System.Threading.ThreadStart) delegate() { display.Close(); });
                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                }
                // Verify we can stop.
                if (m_ClusterDisplays.Count == 0)
                {       // All displays are removed and shutdown.  We can exit now.
                    m_ServiceState = ServiceStates.Stopped;
                    OnServiceStateChanged();
                    base.Stop();
                }
                else
                {
                    Log.NewEntry(LogLevel.Major, "Shutting down. {0} displays remaining.", m_ClusterDisplays.Count);
                    m_PendingRequests.Enqueue(request);
                }
                break;

            case FrontEndRequest.Request.AddService:
                // ************************************
                // ***          Add Service         ***
                // ************************************
                // This is called internally, each time a new service is added
                // to the application.  We attempt to get information about it.
                if (request.ObjectList == null)
                {
                    return;
                }
                for (int i = 0; i < request.ObjectList.Count; ++i)
                {
                    string serviceName = (string)request.ObjectList[i];
                    bool   isGoodToAdd = true;
                    // First check whether this type of engine is we want to ignore.
                    foreach (string pattern in m_IgnoreEngineNamePatterns)
                    {
                        if (serviceName.Contains(pattern))
                        {
                            isGoodToAdd = false;
                            break;
                        }
                    }
                    if (isGoodToAdd == false)
                    {
                        return;
                    }
                    IService iService;
                    if (m_AppServices.TryGetService(serviceName, out iService) && iService is IEngineHub)
                    {       // We have discovered a new EngineHub
                        if (!m_RemoteEngineHubs.ContainsKey(serviceName))
                        {   // This new engineHub isunknown to us.
                            IEngineHub iEngine = (IEngineHub)iService;
                            m_RemoteEngineHubs.Add(serviceName, iEngine);
                            Log.NewEntry(LogLevel.Major, "Adding new EngineHub {0}.  Requesting all controls.", serviceName);
                            iEngine.EngineChanged += new EventHandler(this.HubEventEnqueue);
                            e = EngineEventArgs.RequestAllControls(serviceName);
                            iEngine.HubEventEnqueue(e);
                        }
                    }
                }
                break;

            case FrontEndRequest.Request.AddDisplay:
                // ************************************
                // ***          Add Display         ***
                // ************************************
                // When a new display is requested, we search for the GuiTemplates already
                // stored for that new display, create the display and hand them to the display.
                List <string> engineHubNames = new List <string>();
                if (request.ObjectList == null || (request.ObjectList.Count == 1 && request.ObjectList[0] == null))
                {
                    engineHubNames.AddRange(m_RemoteEngineHubs.Keys);
                }
                else
                {
                    foreach (object o in request.ObjectList)
                    {
                        if (o is string)
                        {
                            engineHubNames.Add((string)o);
                        }
                    }
                }
                // Open displays for each hub name provided.
                foreach (string engineName in engineHubNames)
                {
                    Dictionary <int, GuiTemplates.EngineContainerGui> engineHubTemplates = null;
                    IEngineHub iEngineHub = null;
                    if (m_RemoteEngineHubs.TryGetValue(engineName, out iEngineHub) && m_EngineHubTemplates.TryGetValue(engineName, out engineHubTemplates))
                    {
                        Log.NewEntry(LogLevel.Major, "AddDisplay requesting new ClusterDisplay for {0}.", engineName);
                        List <GuiTemplates.EngineContainerGui> templates = new List <GuiTemplates.EngineContainerGui>(engineHubTemplates.Values);
                        Utilities.GuiCreator creator = Utilities.GuiCreator.Create(typeof(ClusterDisplay), this, iEngineHub, templates);
                        creator.FormCreated += new EventHandler(this.HubEventEnqueue);          // push created form on to my usual queue.
                        creator.Start();
                    }
                    else
                    {
                        Log.NewEntry(LogLevel.Major, "AddDisplay request rejected for {0}.  No templates found.", engineName);
                    }
                }
                break;

            case FrontEndRequest.Request.RemoveDisplay:
                // ************************************
                // ***			Remove Display		***
                // ************************************
                ClusterDisplay display2 = (ClusterDisplay)request.ObjectList[0];
                int            n        = display2.ID;
                if (m_ClusterDisplays.ContainsKey(n))
                {
                    m_ClusterDisplays.Remove(n);
                    Log.NewEntry(LogLevel.Major, "RemoveDisplay id {1}. Remaining {0}.", m_ClusterDisplays.Count, n);
                }
                break;

            default:
                Log.NewEntry(LogLevel.Warning, "Unknown request.");
                break;
            }    //requestType switch
        }        //ProcessFrontEndRequest().