}// TryToAddChild()

        //
        //
        public bool TryGetNextUnsuccessfulChild(out RequestEventArg currentChild)
        {
            currentChild = null;
            if (m_Children == null || m_Children.Count == 0)
            {
                return(false);
            }
            int n = 0;

            while (n < m_Children.Count && currentChild == null)    // its the first event that is not "sucessful"
            {
                RequestEventArg child = (RequestEventArg)m_Children[n];
                if (child.Status != RequestStatus.Success)          // look for first child that is not completed!
                {
                    currentChild = child;                           // If found, he is the current working task
                }
                n++;
            }
            if (currentChild == null)
            {
                currentChild = m_Children[m_Children.Count - 1];      // return last child at least.
            }
            // Exit.
            return(true);
        }//TryGetCurrentChild()
        //
        //
        private void OnRequestCompleted(RequestEventArg completedRequest)
        {
            Log.NewEntry(LogLevel.Minor, "OnRequestCompleted: {0}", completedRequest);

            if (m_WorkingRequests.Contains(completedRequest))
            {
                Log.NewEntry(LogLevel.Minor, "OnRequestCompleted: Removing from Working queue/", completedRequest);
                m_WorkingRequests.Remove(completedRequest);
            }

            if (RequestCompleted != null)
            {
                RequestCompleted(this, completedRequest);
            }
        }
 public bool TryToAddChild(RequestEventArg newChild)
 {
     if (this.Type != RequestType.MultipleSequentialRequests)
     {
         return(false);
     }
     else
     {
         if (m_Children == null)
         {
             m_Children = new List <RequestEventArg>();
         }
         if (m_Children.Contains(newChild))
         {
             return(false);
         }
         m_Children.Add(newChild);
         newChild.m_Parent = this;
     }
     return(true);
 }// TryToAddChild()
        //
        //
        #endregion//Constructors


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



        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        //
        //
        public bool Request(RequestEventArg newRequest)
        {
            return(this.HubEventEnqueue(newRequest));
        }
        }// HubEventHandler()

        //
        //
        // *****************************************************
        // ****             ProcessRequest()                ****
        // *****************************************************
        /// <summary>
        /// Processes job requests from user.
        /// </summary>
        private void ProcessRequest(RequestEventArg eventArg)
        {
            bool triggerRequestCompletedEvent = false;

            //
            // Multiple Sequential Requests
            //
            if (eventArg.Type == RequestType.MultipleSequentialRequests)        // this contains one or more child tasks to complete.
            {
                RequestEventArg currentWorkingRequest = null;                   // the child-request that we are currently working on.
                if (eventArg.TryGetNextUnsuccessfulChild(out currentWorkingRequest))
                {
                    eventArg.Status = RequestStatus.ContinueWorking;            // set parent as "working"
                    if (currentWorkingRequest.Status == RequestStatus.Success)  // Usually, the "current" child is not finished successfully,
                    {                                                           // but if its the last child, then it signals the end of the task.
                        eventArg.Status = RequestStatus.Success;                // Mark parent for success...
                        triggerRequestCompletedEvent = true;
                    }
                    else if (currentWorkingRequest.Status == RequestStatus.Failed)  // the last non-successful child says its failed...
                    {
                        eventArg.Status = RequestStatus.Failed;                     // done. Failed request
                        triggerRequestCompletedEvent = true;
                    }
                    else
                    {
                        Log.BeginEntry(LogLevel.Minor, "ProcessRequest: MultipleSequentialRequests {0}", eventArg);
                        Log.AppendEntry(" ----> {0}", currentWorkingRequest);        // output the current child to work.
                        Log.EndEntry();

                        ProcessRequest(currentWorkingRequest);                      // continue trying to work this task.

                        // TODO: fix this.  If the currentWorkingREquest is complete, we might consider processing the
                        // next request immediately, or not based on its allowed starting time.
                        if (!m_WorkingRequests.Contains(eventArg))                  // make sure that we will revist this parent event again...
                        {
                            Log.NewEntry(LogLevel.Minor, "ProcessRequest: MultipleSequentialRequests. Adding to waiting queue.");
                            m_WorkingRequests.Add(eventArg);
                        }
                        else
                        {
                            Log.NewEntry(LogLevel.Minor, "ProcessRequest: MultipleSequentialRequests. Already in waiting queue.");
                        }
                    }
                }
            }
            //
            // Monitor Copy New Files
            //
            else if (eventArg.Type == RequestType.MonitorCopyNewFiles)
            {
                Log.BeginEntry(LogLevel.Minor, "ProcessRequest: {0}", eventArg);
                List <string> localFileNamesCopied;                                // names of files discovered on FTP site.
                if (m_FtpReader.TryCopyNewRemoteFilesToLocal(m_StatementPath, out localFileNamesCopied))
                {                                                                  // Success making FTP connection!
                    if (localFileNamesCopied.Count > 0)                            // we consider a success that the files we waiting for are there now.
                    {
                        eventArg.Status = RequestStatus.Success;                   // update request state
                        eventArg.Data   = new List <object>(localFileNamesCopied); // update data
                        RequestEventArg parentRequest;
                        if (eventArg.TryGetParent(out parentRequest))
                        {
                            this.HubEventEnqueue(parentRequest);                // strobe the parent to attempt next task...
                        }
                        else
                        {
                            triggerRequestCompletedEvent = true;                       // otherwise, we are done, trigger event.
                        }
                    }
                    else
                    {   // There were no new files yet.
                        // Test that we dont already have a latest file... this would happen only if we ran
                        // the code twice in one day... perform some check here.
                        if (DateTime.Now.CompareTo(eventArg.GiveUpTime) > 0)
                        {
                            eventArg.Status = RequestStatus.Failed;
                            RequestEventArg parentRequest;
                            if (eventArg.TryGetParent(out parentRequest))
                            {
                                this.HubEventEnqueue(parentRequest);                // strobe the parent to attempt next task...
                            }
                            else
                            {
                                triggerRequestCompletedEvent = true;                       // otherwise, we are done, trigger event.
                            }
                        }
                        else
                        {
                            eventArg.Status = RequestStatus.ContinueWorking;        // We will try this again.
                            if (!eventArg.IsChild && !m_WorkingRequests.Contains(eventArg))
                            {
                                m_WorkingRequests.Add(eventArg);
                            }
                        }
                    }// if there are new files
                }
                else
                {   // Failed to event connect properly to FTP
                    Log.AppendEntry(" FTP Connection failed.");
                    if (DateTime.Now.CompareTo(eventArg.GiveUpTime) > 0)
                    {
                        eventArg.Status = RequestStatus.Failed;
                        RequestEventArg parentRequest;
                        if (eventArg.TryGetParent(out parentRequest))
                        {
                            this.HubEventEnqueue(parentRequest);                // strobe the parent to attempt next task...
                        }
                        else
                        {
                            triggerRequestCompletedEvent = true;                       // otherwise, we are done, trigger event.
                        }
                    }
                    else
                    {
                        eventArg.Status = RequestStatus.ContinueWorking;        // We will try this again.
                        if (!eventArg.IsChild && !m_WorkingRequests.Contains(eventArg))
                        {
                            m_WorkingRequests.Add(eventArg);
                        }
                    }
                }
                Log.EndEntry();
            }
            //
            // Reconcile Statement
            //
            else if (eventArg.Type == RequestType.ReconcileStatement)
            {
                bool isSuccessful = true;                                       // track our success in reconciling.


                //
                // Read statement
                //
                RCG.StatementReader statement;
                DateTime            settlementDateTime;
                settlementDateTime = new DateTime(2013, 04, 8, 16, 15, 0);                                                              // DEBUG
                TryReadRCGStatement(settlementDateTime, out statement);                                                                 // read RCG statements - date is settlement date.
                string statementFileName = statement.FilePathForPosition.Substring(statement.FilePathForPosition.LastIndexOf('_') + 1); // keep everything after "_"
                int    n = statementFileName.LastIndexOf('.');
                statementFileName = statementFileName.Substring(0, n);

                DateTime statementTimeStamp;
                if (!DateTime.TryParseExact(statementFileName, "yyyyMMdd", System.Globalization.DateTimeFormatInfo.CurrentInfo, System.Globalization.DateTimeStyles.None, out statementTimeStamp))
                {   // Failed to interpret date on file!
                    isSuccessful = false;
                }

                //
                // Read drops
                //
                if (isSuccessful)
                {
                    StringBuilder report      = new StringBuilder();                  // Full report
                    StringBuilder currentItem = new StringBuilder();
                    foreach (string acctNumber in statement.m_PortfolioPosition.Keys) // for each account number found in the statement...
                    {
                        string baseFileName = string.Format("FillBooks_828{0}", acctNumber);
                        BookReaders.EventPlayer eventPlayer = new BookReaders.EventPlayer(m_DropPath, baseFileName, settlementDateTime);
                        if (eventPlayer.SeriesList.Count == 0)                                           // No information about this account.
                        {
                            continue;                                                                    // next account
                        }
                        report.AppendFormat("Acct# {0}\n", acctNumber);                                  // RCG acct numbers from statement are missing first 3 chars.
                        const string fmt = "    {0,-32}{1,8}\t{2,-24}\n";
                        foreach (string rcgInstrDescr in statement.m_PortfolioPosition[acctNumber].Keys) // loop thru instrDescriptions - items in statement
                        {
                            currentItem.Clear();                                                         // clear this line.

                            Misty.Lib.Products.InstrumentName rcgInstrumentName;
                            Misty.Lib.Products.Product        mistyProduct;
                            if (statement.m_InstrDescrToInstrName.TryGetValue(rcgInstrDescr, out rcgInstrumentName))
                            {
                                int ourQty = 0;                         // qty computed from drop files
                                if (statement.m_RcgToBreProduct.TryGetValue(rcgInstrumentName.Product, out mistyProduct))
                                {
                                    Misty.Lib.Products.InstrumentName mistyInstrumentName = new Misty.Lib.Products.InstrumentName(mistyProduct, rcgInstrumentName.SeriesName);
                                    BookReaders.EventSeries           series;
                                    if (eventPlayer.SeriesList.TryGetValue(mistyInstrumentName, out series))
                                    {
                                        Misty.Lib.OrderHubs.Fill fill;
                                        if (series.TryGetStateAt(settlementDateTime, out fill))
                                        {
                                            ourQty = fill.Qty;
                                            currentItem.AppendFormat(fmt, mistyInstrumentName, ourQty, fill.LocalTime);
                                        }
                                        else
                                        {
                                        }
                                    }
                                }
                                else
                                {   // Unknown product mapping between RCG and TT!
                                    currentItem.AppendFormat(fmt, "unknown", "-", "-");
                                }

                                //
                                // Statement qty
                                //
                                int statementQty = 0;                   // qty from statement
                                List <Misty.Lib.OrderHubs.Fill> fills = statement.m_PortfolioPosition[acctNumber][rcgInstrDescr];
                                foreach (Misty.Lib.OrderHubs.Fill aFill in fills)
                                {
                                    statementQty += aFill.Qty;
                                }
                                currentItem.AppendFormat(fmt, rcgInstrDescr, statementQty, statementTimeStamp.ToShortDateString());

                                if (statementQty != ourQty)
                                {
                                    currentItem.Remove(0, 1);
                                    currentItem.Insert(0, "*");
                                }
                            }// try get rcgInstrumentName

                            report.Append(currentItem);
                        } //next rcgInstrDescr
                    }     //next acctNumber
                    Log.NewEntry(LogLevel.Major, "ReconcileStatement: \r\n{0}", report.ToString()); // write report to Log file.
                }

                //
                // Exit
                //
                if (isSuccessful)
                {
                    eventArg.Status = RequestStatus.Success;
                }
                else
                {
                    eventArg.Status = RequestStatus.Failed;
                }

                RequestEventArg parentRequest;
                if (eventArg.TryGetParent(out parentRequest))
                {
                    this.HubEventEnqueue(parentRequest);                        // strobe the parent to attempt next task...
                }
                else
                {
                    triggerRequestCompletedEvent = true;                       // otherwise, we are done, trigger event.
                }
            }
            //
            // Debug Test
            //
            else if (eventArg.Type == RequestType.DebugTest)
            {
                Log.BeginEntry(LogLevel.Minor, "ProcessRequest: {0}", eventArg);
                if (eventArg.Data == null)
                {
                    Log.AppendEntry(" First failure.");
                    eventArg.Data = new List <object>();
                    eventArg.Data.Add(1);                   // first failure
                    eventArg.Status = RequestStatus.ContinueWorking;
                }
                else if (((int)eventArg.Data[0]) > 2)
                {   // Success
                    Log.AppendEntry(" Success!");
                    eventArg.Status = RequestStatus.Success;
                    RequestEventArg parent;
                    if (eventArg.TryGetParent(out parent))
                    {
                        this.HubEventEnqueue(parent);
                    }
                }
                else
                {   // another failure
                    int n = (int)eventArg.Data[0];
                    eventArg.Data[0] = n + 1;
                    Log.AppendEntry(" {0} failures, try again.", n);
                    eventArg.Status = RequestStatus.ContinueWorking;        // We will try this again.
                    if (!eventArg.IsChild && !m_WorkingRequests.Contains(eventArg))
                    {
                        m_WorkingRequests.Add(eventArg);
                    }
                }
                Log.EndEntry();
            }
            else if (eventArg.Type == RequestType.Stop)
            {
                Shutdown();
                base.Stop();
            }
            else
            {
                Log.BeginEntry(LogLevel.Minor, "ProcessRequest: {0}", eventArg);
                Log.AppendEntry(" request type not implemented.");
                Log.EndEntry();
            }

            // Exit
            if (triggerRequestCompletedEvent)
            {
                OnRequestCompleted(eventArg);
            }
        }//ProcessRequest()
 public bool TryGetParent(out RequestEventArg parent)
 {
     parent = m_Parent;
     return(parent != null);
 }
        //
        //
        #endregion//Constructors


        #region Public Methods
        // *****************************************************************
        // ****                   Public Methods                        ****
        // *****************************************************************
        //
        //
        public bool IsParentOf(RequestEventArg possibleChild)
        {
            return(Type == RequestType.MultipleSequentialRequests && this.m_Children != null && this.m_Children.Contains(possibleChild));
        }