}//end constructor

        //
        //
        #endregion//Constructors


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


        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        //
        //
        /// <summary>
        /// A new display is made and passed to this hub for management.
        /// Called by an external thread.
        /// </summary>
        /// <param name="aHub"></param>
        public void NewDisplay(ClusterDisplay newDisplay)
        {
            lock (NextClusterDisplayIDLock)
            {   // Get next id number available.
                newDisplay.ID           = m_NextClusterDisplayID;
                newDisplay.prevGuiTurns = currentClusterDisplayNumber;
                m_NextClusterDisplayID += 1;
            }
            newDisplay.FormClosing += new System.Windows.Forms.FormClosingEventHandler(Display_FormClosing);
            DisplayArgs args = new DisplayArgs();

            args.display = newDisplay;
            args.Request = DisplayArgs.DisplayRequest.NewDisplay;
            HubEventEnqueue(args);
        }//NewDisplay().
        }        //ProcessFrontEndRequest().

        //
        //
        //
        //
        // *********************************************************
        // ****             ProcessCreatedForm()                ****
        // *********************************************************
        /// <summary>
        /// A new Form has been created by the GUI thread, and is now ready to
        /// be employed.  We request all controls for this display (based on the type
        /// of display it is).
        /// </summary>
        /// <param name="anEventArg"></param>
        private void ProcessCreatedForm(Utilities.GuiCreator.CreateFormEventArgs anEventArg)
        {
            //
            if (anEventArg.CreatedForm is ClusterDisplay)
            {                                                                                              // We have created a new ClusterDisplay.
                ClusterDisplay display    = (ClusterDisplay)anEventArg.CreatedForm;
                IEngineHub     iengineHub = display.AssocEngineHub;                                        // EngineHub associated with this display.
                display.FormClosing += new System.Windows.Forms.FormClosingEventHandler(ClusterDisplay_FormClosing);
                display.ID           = System.Threading.Interlocked.Increment(ref m_NextClusterDisplayID); // create a unique ID for this display.
                m_ClusterDisplays.Add(display.ID, display);

                // Create quick lookup tables for engine event arg processing.
                // We create a list of display IDs that contain the controls once given the IEngineHub name
                // and IEngineContainerID.
                Dictionary <int, List <int> > clusterIdsToDislayIds = null;
                if (!m_ClusterDisplayIds.TryGetValue(iengineHub.ServiceName, out clusterIdsToDislayIds))
                {   // First form created for this engineHub.  Add entry for it.
                    clusterIdsToDislayIds = new Dictionary <int, List <int> >();
                    m_ClusterDisplayIds.Add(iengineHub.ServiceName, clusterIdsToDislayIds);
                }
                int displayID = display.ID;
                foreach (IEngineContainer iengContainer in display.GetEngineContainers())
                {
                    List <int> clusterIdList;
                    if (!clusterIdsToDislayIds.TryGetValue(iengContainer.EngineContainerID, out clusterIdList))
                    {
                        clusterIdList = new List <int>();
                        clusterIdsToDislayIds.Add(iengContainer.EngineContainerID, clusterIdList);
                    }
                    clusterIdList.Add(displayID);                               // For each list add this displayID.
                }
                Log.NewEntry(LogLevel.Major, "ProcessCreatedForm: ClusterDisplay created. Requesting parameter values.");

                // Request all parameter values for my new display.
                // Since Display exists now, when response comes back, we have this display in the display list.
                foreach (IEngineContainer iEngineContainer in display.GetEngineContainers())
                {
                    string engineHubName = iengineHub.ServiceName;    // name of StrategyHub I am associated with.
                    foreach (EngineEventArgs e in EngineEventArgs.RequestAllParameters(engineHubName, iEngineContainer))
                    {
                        // TODO: Throttle requests we will make to StrategyHubs.
                        //
                        display.AssocEngineHub.HubEventEnqueue(e);
                    }
                }
            }
        }//ProcessCreatedForm()
        }        //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().
        //
        //
        #endregion//Public Methods


        #region HubEvent Handler
        // *****************************************************************
        // ****                 Private HubEvent Methods                ****
        // *****************************************************************
        //
        //
        // ****                     Hub Event Handler               ****
        //
        /// <summary>
        /// Main request handling routine.
        /// Called only by the internal hub thread.
        /// </summary>
        /// <param name="e"></param>
        protected override void HubEventHandler(EventArgs[] eArgList)
        {
            foreach (EventArgs eArg in eArgList) // process each event
            {
                Log.NewEntry(LogLevel.Minor, eArg.ToString());
                Type eArgType = eArg.GetType();
                if (eArgType == typeof(FrontEndHub.DisplayArgs))
                {   // ****************************************
                    // ****         Display Events         ****
                    // ****************************************
                    // These are my internal requests, used to create new GUI displays, etc.
                    FrontEndHub.DisplayArgs e = (FrontEndHub.DisplayArgs)eArg;
                    switch (e.Request)
                    {
                    case DisplayArgs.DisplayRequest.NewDisplay:
                        //
                        // ***          New Display         ***
                        //
                        // When a new display is requested (to be displayed from this hub), a request is pushed
                        // onto the queue and comes here.  this way the new ClusterDisplay can be created and
                        // added to the list without the need to lock the list (only the hub thread ever touches
                        // this list.)
                        IEngineHub            engineHub = e.display.AssocEngineHub; // hub whose elements we want to display
                        List <ClusterDisplay> displayList;                          // displays already associated with element hub
                        if (!m_EngineSubscriptions.TryGetValue(engineHub, out displayList))
                        {                                                           // First time we are creating a display for this hub. There is no existing list.
                            displayList = new List <ClusterDisplay>();              // create new list.
                            m_EngineSubscriptions.Add(engineHub, displayList);
                            engineHub.EngineChanged += new EventHandler(this.HubEventEnqueue);
                        }
                        ClusterDisplay newDisplay = e.display;                                                                          // display created by event creator.
                        displayList.Add(newDisplay);
                        m_ClusterDisplay.Add(newDisplay.ID, newDisplay);                                                                // the ID is made by original caller
                        // Now request a complete list of the controls for engines from hub.
                        engineHub.HubEventEnqueue(Engines.EngineEventArgs.RequestAllControls(newDisplay.ID - newDisplay.prevGuiTurns)); //newDisplay.ID));
                        break;

                    case DisplayArgs.DisplayRequest.RemoveDisplay:
                        //
                        // ***          Remove Display          ***
                        //
                        ClusterDisplay displayToRemove = e.display;
                        if (displayToRemove != null)
                        {       // Remove any book subscriptions
                            List <object> hubsToRemove = new List <object>();
                            foreach (BookHub hub in m_Subscriptions.Keys)
                            {
                                if (m_Subscriptions[hub].Contains(displayToRemove))
                                {
                                    m_Subscriptions[hub].Remove(displayToRemove);
                                    if (m_Subscriptions[hub].Count == 0)
                                    {
                                        hub.InstrumentChanged -= this.HubEventEnqueue;
                                        hubsToRemove.Add(hub);
                                    }
                                }
                            }
                            foreach (object hub in hubsToRemove)
                            {
                                m_Subscriptions.Remove((BookHub)hub);
                            }
                            // Remove engine subscriptions
                            foreach (IEngineHub hub in m_EngineSubscriptions.Keys)
                            {
                                if (m_EngineSubscriptions[hub].Contains(displayToRemove))
                                {
                                    m_EngineSubscriptions[hub].Remove(displayToRemove);
                                    if (m_EngineSubscriptions[hub].Count == 0)
                                    {
                                        hub.EngineChanged -= this.HubEventEnqueue;
                                        hubsToRemove.Add(hub);
                                    }
                                }
                            }
                            foreach (object hub in hubsToRemove)
                            {
                                m_EngineSubscriptions.Remove((IEngineHub)hub);
                            }
                            m_ClusterDisplay[displayToRemove.ID] = null;        // dump my pointer to it.
                        }
                        break;

                    default:
                        //
                        // ***          default error       ***
                        //
                        Log.NewEntry(LogLevel.Error, "Unknown DisplayArg Request.");
                        break;
                    }
                }
                else if (eArgType == typeof(EngineEventArgs))
                {   // *****************************************************
                    // *****            Process Engine Events           ****
                    // *****************************************************
                    EngineEventArgs e = (EngineEventArgs)eArg;
                    // Pass event to all ClusterDisplays subscribed to event-generating hub.
                    //
                    List <ClusterDisplay> clusterDisplayList;
                    if (m_EngineSubscriptions.TryGetValue(e.EngineHubResponding, out clusterDisplayList))
                    {   // at least some displays are subscribed to this hub.
                        for (int i = 0; i < clusterDisplayList.Count; ++i)
                        {
                            ClusterDisplay display = clusterDisplayList[i];
                            //List<IEngineContainer> containers = display.GetEngineContainers();  // get containers in this hub.
                            //Dictionary<int, IEngineContainer> containersDict = display.GetEngineContainersDictionary();
                            //IEngineContainer engineContainer11;
                            if (e.EngineContainerID < 0)
                            {   // EngineContainer ID < 0 => event is meant for all containers in hub.
                                // Such events are passed to all Stratgies or Clusters, etc.
                                if (e.MsgType == EngineEventArgs.EventType.GetControls)
                                {   // Create the cluster controls for this display.
                                    // This request is made by ClusterDisplays (to the Hub they are displaying) after
                                    // they have been created, but not completely initialized.
                                    // Now proceed through our list of ClusterDisplays and only the first uninitialized
                                    // display we find will have the controls inside this eventarg passed to it.
                                    bool isNewDisplay = (e.Status == EngineEventArgs.EventStatus.Confirm) &&
                                                        (!display.IsInitialized);
                                    if (isNewDisplay)
                                    {
                                        display.HubEventEnqueue(e);                                                                                                 // This is a non-asynchronous call, display is initialized immediately.
                                        // Now request all parameter updates for new display.
                                        List <EngineEventArgs> newRequestList = EngineEventArgs.RequestAllParameters((display.ID - display.prevGuiTurns), display); //(i,display);
                                        foreach (EngineEventArgs newRequest in newRequestList)
                                        {
                                            e.EngineHubResponding.HubEventEnqueue(newRequest);
                                        }
                                        break;  // only initialize one display per GetControls event. The first uninitialized display gets initialized.
                                    }
                                }
                                else
                                {                                                                       // Every other non-GetControls event for "all clusters" processed here.
                                    // Right now, there are none of such terms.
                                    List <IEngineContainer> containers = display.GetEngineContainers(); // get containers in this hub.
                                    foreach (IEngineContainer container in containers)
                                    {
                                        container.ProcessEngineEvent(e);
                                    }
                                }
                            }
                            else
                            {                                   // A specific containerID was provided.
                                                                // Pass along this event directly to the specific engineContainer.
                                Dictionary <int, IEngineContainer> containersDict = display.GetEngineContainersDictionary();
                                IEngineContainer engineContainer;
                                if (containersDict.TryGetValue(e.EngineContainerID, out engineContainer))
                                {
                                    engineContainer.ProcessEngineEvent(e);
                                }
                                else
                                {                                       // Failed to find enginecontainer!
                                    Log.NewEntry(LogLevel.Error, "Received event for unknown engineContainerID={0}.", e.EngineContainerID);
                                }
                            }
                            display.RegenerateNow(this, null);   // tells the display to repaint, if needed.
                        }
                    }
                }
                else
                {   //
                    // ****         Unrecognized Event          ****
                    //
                    Log.NewEntry(LogLevel.Error, "Unknown event type: {0}", eArgType.ToString());
                    eArg.GetType();
                }
            } //next event arg
        }     //HubEventHandler()