}//ProcessQuery()

        //
        private void ProcessWriteQuery(Queries.QueryBase query, MySqlConnection mySqlConnection)
        {
            try
            {
                string cmdString = query.GetQuery(m_Database);
                Log.NewEntry(LogLevel.Minor, "ProcessQuery: {0}", cmdString);
                if (string.IsNullOrEmpty(cmdString))
                {
                    Log.NewEntry(LogLevel.Major, "ProcessQuery: Query provided is empty.");
                    query.Status = Queries.QueryStatus.Failed;
                    OnQueryResponse((EventArgs)query);
                }
                MySqlCommand cmd   = new MySqlCommand(cmdString, mySqlConnection);
                int          nRows = cmd.ExecuteNonQuery();

                query.Status = Queries.QueryStatus.Completed;
            }
            catch (Exception e)
            {
                Log.NewEntry(LogLevel.Major, "ProcessQuery: {1} exception: {0}", e.Message, query);
                query.ErrorMessage = e.Message;
                query.Status       = Queries.QueryStatus.Failed;
            }
            //
            // This is complete.  Push onto the queue.
            //
            this.HubEventEnqueue(query);
        }//ProcessQuery()
        }// Start()

        //
        //
        // *****************************************
        // ****         SubmitAsync()           ****
        // *****************************************
        /// <summary>
        /// This is the asynchronous query.  The requesting thread is
        /// immediately released after pushing the query request onto the
        /// hub queue, and call back is made with a QueryResponse event.
        /// The results as placed withing the query object, so the calling
        /// thread should not keep it.
        /// </summary>
        /// <param name="request"></param>
        public void SubmitAsync(Queries.QueryBase request)
        {
            if (!((int)m_ServiceState >= (int)ServiceStates.Stopping))
            {   // Regardless of the type of query (read or write), the request
                // is simply pushed onto the queue.
                this.HubEventEnqueue((EventArgs)request);
            }
            else
            {
                request.Status       = Queries.QueryStatus.Failed;
                request.ErrorMessage = "DatabaseReaderWriter shutting down.";
                OnQueryResponse((EventArgs)request);
            }
        }//SubmitAsync()
        }//SubmitAsync()

        //
        //
        //
        //
        // *****************************************
        // ****         SubmitSync()           ****
        // *****************************************
        /// <summary>
        /// Here, the query is made synchronously and the requesting
        /// thread waits until the query is completed, the results are
        /// added to the query and returned to the calling thread.
        /// No event is triggered in this case.
        ///
        /// NOTE: This only works correctly with read queries. Write queries are always queued.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool SubmitSync(Queries.QueryBase request)
        {
            bool isSuccessful = false;

            if ((int)m_ServiceState >= (int)ServiceStates.Stopping)
            {
                request.Status       = Queries.QueryStatus.Failed;
                request.ErrorMessage = "DatabaseReaderWriter shutting down.";
                return(false);
            }
            //
            if (request.IsRead)
            {
                // This request is a query, which will have data returned to it.
                // All such requests will be done be the main thread for this hub.
                // (This keeps all query work spaces lock free for the main thread, but the
                // caller will need to wait a bit more.)
                // Now, create a waithandle to block the calling thread until data is ready.
                EventWaitHandle wh = null;
                if (!m_WaitHandleFactory.TryDequeue(out wh))
                {
                    wh = new EventWaitHandle(false, EventResetMode.AutoReset);
                }
                m_WaitHandles.TryAdd(request.QueryID, wh);              // leave my phone number here, with the query I am waiting for.

                this.HubEventEnqueue((EventArgs)request);               // submit request

                wh.WaitOne();                                           // wait for callback here.

                EventWaitHandle wh2;                                    // Try to recycle my wait handle.
                if (m_WaitHandles.TryRemove(request.QueryID, out wh2))  // They can been removed by other threads in bad cases; e.g., ShutdownNow()
                {
                    m_WaitHandleFactory.Enqueue(wh2);                   // Usually, we get our own wait handle (same as wh above), except during shutdowns, etc.
                }
                isSuccessful = (request.Status != Queries.QueryStatus.Failed);
            }
            else
            {   // This is a write, which the thread can do for himself, if he likes.
            }
            // Exit
            return(isSuccessful);
        }//SubmitAsync()
        }//HubEventHandler()

        //
        //
        // *************************************************
        // ****         ProcessQuery(iQuery)            ****
        // *************************************************
        private void ProcessReadQuery(Queries.QueryBase query)
        {
            MySqlConnection mySqlConnection = null;

            // Try to connect
            if (!m_Database.IsTryToConnect(ref mySqlConnection))
            {   // Failed to connect.
                Log.NewEntry(LogLevel.Major, "ProcessQuery: Failed to connect to {0}.", m_Database);
                query.Status = Queries.QueryStatus.Failed;
                OnQueryResponse((EventArgs)query);
            }

            //
            MySqlDataReader reader = null;

            try
            {
                string cmdString = query.GetQuery(m_Database);
                Log.NewEntry(LogLevel.Minor, "ProcessQuery: {0}", cmdString);
                if (string.IsNullOrEmpty(cmdString))
                {
                    Log.NewEntry(LogLevel.Major, "ProcessQuery: Query provided is empty.");
                    query.Status = Queries.QueryStatus.Failed;
                    OnQueryResponse((EventArgs)query);
                }
                MySqlCommand cmd = new MySqlCommand(cmdString, mySqlConnection);

                reader = cmd.ExecuteReader();
                int           fieldCount = reader.FieldCount;
                List <string> fieldNames = new List <string>();     // place to store column names
                List <object> values     = new List <object>();     // place to store values.  Count will be (fieldCount * nRows)
                for (int i = 0; i < fieldCount; ++i)
                {
                    fieldNames.Add(reader.GetName(i));
                }
                while (reader.Read())
                {     // Reading the next row
                    for (int i = 0; i < fieldCount; ++i)
                    { // Read the ith column in this row.
                        if (reader.IsDBNull(i))
                        {
                            values.Add(null);
                            continue;
                        }
                        Type type = reader.GetFieldType(i);
                        if (type == typeof(int))
                        {
                            values.Add(reader.GetInt32(i));
                        }
                        else if (type == typeof(double))
                        {
                            values.Add(reader.GetDouble(i));
                        }
                        else
                        {
                            object o = reader.GetValue(i);
                            values.Add(o);
                        }
                    }//next ith column.
                }
                // Give the data to the query.
                query.Status = query.AcceptData(m_Database, values, fieldNames);
            }
            catch (Exception e)
            {
                Log.NewEntry(LogLevel.Major, "ProcessQuery: {1} exception: {0}", e.Message, query);
                query.ErrorMessage = e.Message;
                query.Status       = Queries.QueryStatus.Failed;
            }
            if (reader != null && reader.IsClosed == false)
            {
                try
                {
                    reader.Close();
                }
                catch (Exception e)
                {
                    Log.NewEntry(LogLevel.Major, "ProcessQuery: Closing reader {1} exception: {0}", e.Message, query);
                }
            }
            if (mySqlConnection != null)
            {
                mySqlConnection.Close();
            }

            //
            // This is complete.  Push onto the queue.
            //
            this.HubEventEnqueue(query);
        }//ProcessQuery()
        }// RequestStop()

        //
        //
        //
        //
        //
        //
        //
        #endregion//Public Methods


        #region Private Hub Event Handler Methods
        // *****************************************************************
        // ****                     Private Methods                     ****
        // *****************************************************************
        //
        //
        //
        //
        // *************************************************
        // ****             HubEvent Handler()          ****
        // *************************************************
        /// <summary>
        /// This is the main processing routine.
        /// </summary>
        /// <param name="eventArgsList"></param>
        protected override void HubEventHandler(EventArgs[] eventArgsList)
        {
            if (m_ServiceState == ServiceStates.Unstarted || m_ServiceState == ServiceStates.Started)
            {
                m_ServiceState = ServiceStates.Running;
                OnServiceStateChanged(ServiceStates.Unstarted, ServiceStates.Started);
                OnServiceStateChanged(ServiceStates.Started, ServiceStates.Running);
            }
            //
            //
            //
            foreach (EventArgs eventArg in eventArgsList)
            {
                if (eventArg == null || eventArg == EventArgs.Empty)
                {
                    continue;
                }
                if (eventArg is Queries.QueryBase)
                {
                    Queries.QueryBase query = (Queries.QueryBase)eventArg;
                    if (query.QueryID == 6)
                    {
                    }
                    if (query.Status == Queries.QueryStatus.New)
                    {   // This is a new query request, for either read or write.
                        // We will process this query here.
                        if (query.IsRead)
                        {   // If the user has requested a "query" then he probably
                            // expects to receive an answer, and so this we try to carry out immediately.
                            ProcessReadQuery(query);
                        }
                        else
                        {   // User wants to write data.
                            m_WriteQueryQueue.Enqueue(query);
                        }
                    }
                    else
                    {   // This is a query that we have already processed.
                        // It has been pushed back onto the queue to be returned to the caller.
                        EventWaitHandle wh = null;
                        if (m_WaitHandles.TryRemove(query.QueryID, out wh))
                        {                                    // If this queryID has a wait handle, then the creator has made a synchronized
                            // call and is waiting for the response at the wait handle.
                            wh.Set();                        // Wake the caller now (he has a copy of the query).
                            m_WaitHandleFactory.Enqueue(wh); // No need to trigger an event in this case, recycle the wait handle.
                        }
                        else
                        {
                            OnQueryResponse((EventArgs)query);  // Here, the caller has made async call.  So we must trigger event for him.
                        }
                    }
                }
                else if (eventArg.GetType() == typeof(RequestEventArgs))
                {
                    RequestEventArgs request = (RequestEventArgs)eventArg;
                    if (request.Request == RequestCode.BeginShutdown)
                    {
                        OnServiceStateChanged(m_ServiceState, ServiceStates.Stopping);
                        m_ServiceState = ServiceStates.Stopping;

                        // Purge all write queues now.

                        // If all things are completed, then shutdown completely now.
                        // Otherwise, we will have to check after each periodic update to see when all work
                        // has been completed.
                        bool isReadyToStop = true;
                        if (isReadyToStop)
                        {
                            m_ServiceState = ServiceStates.Stopped;
                            OnServiceStateChanged(ServiceStates.Stopping, ServiceStates.Stopped);
                            base.Stop();
                        }
                    }
                }
            }
        }//HubEventHandler()