//
        //
        #endregion//Constructors


        #region Public Methods
        // *****************************************************************
        // ****                     Public Methods                      ****
        // *****************************************************************
        /// <summary>
        /// When an instrument is clicked on in the position viewer window, that window
        /// calls this routine letting us know which instrument is active.
        /// </summary>

        /*
         * public void SetInstrument(FillHub fillHub, Misty.Lib.Products.InstrumentBase instrument)
         * {
         *  m_CurrentInstrument = instrument;               // set current instrument
         *  m_FillHub = fillHub;                            // set current fill hub
         *  this.Text = string.Format("Add Fills - {0}", m_CurrentInstrument.FullName);
         *  this.labelInstrumentName.Text = m_CurrentInstrument.FullName;
         *  this.labelExpirationDate.Text = string.Format("{0:ddd dd MMM yyyy}", m_CurrentInstrument.ExpirationDate);
         *
         *  // Update Markets
         *  Misty.Lib.BookHubs.Book aBook;
         *  if (m_Market.TryEnterReadBook(out aBook))
         *  {
         *      foreach (Misty.Lib.BookHubs.MarketInstrument mktInstr in aBook.Instruments.Values)
         *      {
         *          if (mktInstr.Name.Equals(m_CurrentInstrument.FullName))
         *          {
         *              labelAskPrice.Text = mktInstr.Price[Misty.Lib.Utilities.QTMath.AskSide][0].ToString();
         *              labelBidPrice.Text = mktInstr.Price[Misty.Lib.Utilities.QTMath.BidSide][0].ToString();
         *              labelAskQty.Text = mktInstr.Qty[Misty.Lib.Utilities.QTMath.AskSide][0].ToString();
         *              labelBidQty.Text = mktInstr.Qty[Misty.Lib.Utilities.QTMath.BidSide][0].ToString();
         *              break;
         *          }
         *      }
         *      m_Market.ExitReadBook(aBook);
         *  }
         *  // Reset defaults
         *  SetConfirmMode(buttonSubmitFill,false,0);
         * }//SetInstrument()
         * //
         */
        //
        //
        public void SetInstrument(FillHub fillHub, Misty.Lib.Products.InstrumentName instrument)
        {
            m_CurrentInstrument           = instrument;     // set current instrument
            m_FillHub                     = fillHub;        // set current fill hub
            this.Text                     = string.Format("Add Fills - {0}", m_CurrentInstrument.FullName);
            this.labelInstrumentName.Text = m_CurrentInstrument.FullName;

            /*
             * Misty.Lib.Products.InstrumentBase instrBase;
             * if (m_Market.TryGetInstrument(instrument, out instrBase))
             * {
             *  this.labelExpirationDate.Text = string.Format("{0:ddd dd MMM yyyy}", instrBase.ExpirationDate);
             * }
             * else
             *  this.labelExpirationDate.Text = "unknown market instr";
             */
            TradingTechnologies.TTAPI.InstrumentDetails details;
            if (m_Market.TryLookupInstrumentDetails(instrument, out details))
            {
                this.labelExpirationDate.Text = string.Format("{0:ddd dd MMM yyyy}", details.ExpirationDate.ToDateTime());
            }
            else
            {
                this.labelExpirationDate.Text = "unknown market instr";
            }

            // Update Markets
            Misty.Lib.BookHubs.Book aBook;
            if (m_Market.TryEnterReadBook(out aBook))
            {
                foreach (Misty.Lib.BookHubs.Market mktInstr in aBook.Instruments.Values)
                {
                    if (mktInstr.Name.Equals(m_CurrentInstrument))
                    {
                        labelAskPrice.Text = mktInstr.Price[Misty.Lib.Utilities.QTMath.AskSide][0].ToString();
                        labelBidPrice.Text = mktInstr.Price[Misty.Lib.Utilities.QTMath.BidSide][0].ToString();
                        labelAskQty.Text   = mktInstr.Qty[Misty.Lib.Utilities.QTMath.AskSide][0].ToString();
                        labelBidQty.Text   = mktInstr.Qty[Misty.Lib.Utilities.QTMath.BidSide][0].ToString();
                        break;
                    }
                }
                m_Market.ExitReadBook(aBook);
            }
            // Reset defaults
            SetConfirmMode(buttonSubmitFill, false, 0);
        }//SetInstrument()
        }// 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()
        }         // ReadStatements()

        //
        //
        //
        // *****************************************************************
        // ****                 Create InstrumentName()                 ****
        // *****************************************************************
        private bool CreateInstrumentName(string typeCodeStr, string callPutFlag, string instrDescStr, string instrSymbolStr, out Misty.Lib.Products.Product rcgProduct, out Misty.Lib.Products.InstrumentName rcgInstrumentName)
        {
            int  n;
            bool isOption = false;

            if (callPutFlag.Equals("C"))
            {
                isOption = true;
            }
            else if (callPutFlag.Equals("P"))
            {
                isOption = true;
            }

            if (isOption)
            {
                Misty.Lib.Products.ProductTypes mistyProductType = Misty.Lib.Products.ProductTypes.Option;
                string exchStr    = string.Empty;
                string instrStr   = instrDescStr;
                string seriesName = instrDescStr;
                rcgProduct        = new Misty.Lib.Products.Product(exchStr, instrStr, mistyProductType);
                rcgInstrumentName = new Misty.Lib.Products.InstrumentName(rcgProduct, seriesName);
            }
            else if (string.IsNullOrEmpty(typeCodeStr) || typeCodeStr.Equals("F"))
            {   // futures format = "DEC 13 TOCOM GOLD"
                Misty.Lib.Products.ProductTypes mistyProductType = Misty.Lib.Products.ProductTypes.Future;
                string[] elements;
                try
                {
                    elements = instrDescStr.Split(DelimSpace, StringSplitOptions.RemoveEmptyEntries);
                    int nextPtr = 0;
                    //
                    // Instrument date extraction
                    //
                    string seriesName;
                    if (Int32.TryParse(elements[0], out n))
                    {                                                                                                         // Seems to be "dd MMM yy" format, since first element is integer n = "dd"
                        string s         = elements[1].Trim();                                                                // extract month part
                        string monthName = string.Format("{0}{1}", s.Substring(0, 1).ToUpper(), s.Substring(1, 2).ToLower()); // MAY --> May
                        seriesName = string.Format("{0:00}{1}{2}", n, monthName, elements[2].Trim());                         // 08May13 for example
                        seriesName = "CA 3M";
                        nextPtr    = 3;                                                                                       // ptr to next element.
                    }
                    else
                    {                                                                                                         // Seems to be "MMM yy" format
                        string s         = elements[0].Trim();                                                                // extract month part
                        string monthName = string.Format("{0}{1}", s.Substring(0, 1).ToUpper(), s.Substring(1, 2).ToLower()); // MAY --> May
                        seriesName = string.Format("{0}{1}", monthName, elements[1].Trim());
                        nextPtr    = 2;                                                                                       // ptr to next element.
                    }
                    string exchStr;
                    string instrStr;
                    int    remainingElements = elements.Length - nextPtr;
                    if (remainingElements == 1)
                    {   // No obvious delineation between product and exch?
                        // Assume a 3-character exchange code!  I believe RCG uses fixed length fields...
                        string s = elements[nextPtr].Trim();
                        exchStr  = s.Substring(0, 3);               // First 3 chars
                        instrStr = s.Substring(3);                  // remaining symbol
                        nextPtr++;
                    }
                    else
                    {
                        exchStr = elements[nextPtr].Trim();         // presume exch name is ONE-word long
                        nextPtr++;
                        instrStr = elements[nextPtr].Trim();
                        nextPtr++;
                        while (nextPtr < elements.Length)
                        {
                            instrStr = string.Format("{0} {1}", instrStr, elements[nextPtr].Trim());
                            nextPtr++;
                        }
                    }
                    rcgProduct        = new Misty.Lib.Products.Product(exchStr, instrStr, mistyProductType);
                    rcgInstrumentName = new Misty.Lib.Products.InstrumentName(rcgProduct, seriesName);
                }
                catch (Exception)
                {
                    // TODO: Write error message to log, and continue.
                    rcgProduct        = new Misty.Lib.Products.Product();
                    rcgInstrumentName = new Misty.Lib.Products.InstrumentName();
                    return(false);
                }
            }
            else
            {
                rcgProduct        = new Misty.Lib.Products.Product();
                rcgInstrumentName = new Misty.Lib.Products.InstrumentName();
            }
            // Exit
            return(true);
        }// CreateInstrumentName()