/// <summary>
 /// The function called at every timer interval. It checks the backgroundworker isbusy
 /// state. If not busy then it stops the timer and starts the backgroundworker with the
 /// saved latest argument. The saved argument is also nulled since that aspect is used
 /// as a flag. Otherwise the timer is allowed to remain running.
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void CheckBackgroundWorkerStateTimer_Elapsed(object sender, ElapsedEventArgs e)
 {
     if (bwTableSolutions.IsBusy)
     {
         return;
     }
     timerRetryUntilNotBusy.Stop();
     bwTableSolutions.RunWorkerAsync(m_Argument);
     m_Argument = null;
     return;
 }
        private void RunBackgroundWorkerTableSolutions(double cfm, double lph, double surfe, bool colebrook, bool limitvelocity, double vellimit)
        {
            TableSolutionArgs thisTableSol = new TableSolutionArgs {
                Cfm           = cfm,
                Lph           = lph,
                Surfe         = surfe,
                Colebrook     = colebrook,
                Limitvelocity = limitvelocity,
                Vellimit      = vellimit,
                MaxAr         = sessionModel.MaxAR,
                DLiner        = sessionModel.Dliner,
                LphMargin     = sessionModel.LphMargin,
                Dtype         = sessionModel.Dtype,
                ChkHRange     = sessionModel.ChkHRange,
                HtLL          = sessionModel.HtLL,
                HtUL          = sessionModel.HtUL,
                ChkWRange     = sessionModel.ChkWRange,
                WtLL          = sessionModel.WtLL,
                WtUL          = sessionModel.WtUL
            };

            // If not null then there is an argument pending. Throw it out and
            // replace it with a new argument pending. This serves as both a flag
            // here and a way to save the most current argument for the waiting
            // backgroundworker state checker.
            if (m_Argument != null)
            {
                m_Argument = thisTableSol;
                return;
            }
            // Check if backgroundworker is not busy.
            // Run the not busy backgroundworker with the current argument.
            if (!bwTableSolutions.IsBusy)
            {
                string solTypeText = StrSoluT();
                sessionModel.Ductshapevis = Visibility.Hidden;
                sessionModel.SolutionsMsg = "Calculating " + solTypeText + " Solutions .......";
                bwTableSolutions.RunWorkerAsync(thisTableSol);
                return;
            }
            // If here then backgroundworker is currently busy. Save this current desired
            // argument and then issue a request to cancel the backgroundworker.
            // Then start the backgroundworker state checker timer.
            m_Argument = thisTableSol;
            bwTableSolutions.CancelAsync();
            sessionModel.SolutionsMsg      = "Calculation cancel is pending .....";
            timerRetryUntilNotBusy.Enabled = true;
            timerRetryUntilNotBusy.Start();
            // The request to cancel has been issued and the state checker timer has been
            // activated. UI returns to user but the revised table has yet to be calculated.
            // The state checker will start the backgroundworker with the saved argument when
            // it sees the backgroundworker not busy.
            return;
        }
        private void BwTableSolutions_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker  worker = sender as BackgroundWorker;
            TableSolutionArgs TSA    = e.Argument as TableSolutionArgs;

            double    cfm           = TSA.Cfm;
            double    lph           = TSA.Lph;
            double    surfe         = TSA.Surfe;
            bool      colebrook     = TSA.Colebrook;
            bool      limitvelocity = TSA.Limitvelocity;
            double    vellimit      = TSA.Vellimit;
            double    maxAr         = TSA.MaxAr;
            double    dLiner        = TSA.DLiner;
            double    lphMargin     = TSA.LphMargin;
            int       dtype         = TSA.Dtype;
            bool      chkHRange     = TSA.ChkHRange;
            double    htLL          = TSA.HtLL;
            double    htUL          = TSA.HtUL;
            bool      chkWRange     = TSA.ChkWRange;
            double    wtLL          = TSA.WtLL;
            double    wtUL          = TSA.WtUL;
            DataTable argSolTable   = new SolutionsTable();//   TSA.SolutTable;

            double _tryLPH     = 0;
            double _rEqCirDct  = 0;
            int    _maxDuct    = 0;
            int    _maxDuctH   = 0;
            int    _maxDuctW   = 0;
            double _area_sf    = 0;
            string _typ        = null;
            double _dVel       = 0;
            double _HtBot      = 0;
            double _WtBot      = 0;
            double smallNumber = 5E-3;

            _maxDuct = Convert.ToInt32(Math.Truncate((maxAr - 1) * ReqEqvCirDuct(cfm, lph, surfe, colebrook, limitvelocity, vellimit)));
            _maxDuct = Convert.ToInt32(Math.Max(_maxDuct, 6));
            // limit lower size
            _maxDuctH = _maxDuct;
            _maxDuctW = _maxDuct;
            _HtBot    = 6;
            _WtBot    = 6;
            if (chkHRange)
            {
                _HtBot    = htLL;
                _maxDuctH = Convert.ToInt32(htUL);
            }
            if (chkWRange)
            {
                _WtBot    = wtLL;
                _maxDuctW = Convert.ToInt32(wtUL);
            }

            _typ = (dtype == 0 ? " R" : " FO");
            double DDLiner = 2 * dLiner;

            for (double ductHeight = _HtBot; ductHeight <= _maxDuctH; ductHeight += Dinc)
            {
                if ((worker.CancellationPending))
                {
                    e.Cancel = true;
                    return;
                }
                if (argSolTable.Rows.Count > 60)
                {
                    break;
                }
                // Not adjusting the inner loop lower bound to eliminate mirror duplicates!! The
                // problem with that approach is that the lower and upper dimension limits can
                // vary.
                for (double wt = _WtBot; wt <= _maxDuctW; wt += Dinc)
                {
                    if ((worker.CancellationPending))
                    {
                        e.Cancel = true;
                        return;
                    }
                    // check ar and even size first
                    if ((Math.Max(wt, ductHeight) / Math.Min(wt, ductHeight) <= maxAr) && ((wt + DDLiner) % 2 == 0) && ((ductHeight + DDLiner) % 2 == 0))
                    {
                        _rEqCirDct = DhEqCircRO(ductHeight, wt, dtype);
                        _tryLPH    = CircDuctPLPH(cfm, _rEqCirDct, surfe, colebrook);
                        // The viable solution must first come under the lph criterium. Then
                        // it must be close enough to the lph according to the allowed margin factor.
                        if ((_tryLPH <= lph) && ((lphMargin * lph) - _tryLPH <= smallNumber))
                        {
                            _area_sf = DAreaRO(wt, ductHeight, dtype);
                            _dVel    = Vel(cfm, _area_sf);
                            // velocity limit check, if fails then skip this for
                            if ((limitvelocity) && (_dVel > vellimit))
                            {
                                continue;
                            }
                            double  drWt  = wt + DDLiner;
                            double  drHt  = ductHeight + DDLiner;
                            double  drPFT = DuctPFT(drWt, drHt, dtype);
                            DataRow dr    = argSolTable.NewRow();
                            // inlist check, if already in list as reverse size then skip this solution
                            if (InList(drHt, drWt, argSolTable))
                            {
                                continue;
                            }
                            dr[0] = drWt;
                            dr[1] = "x";
                            dr[2] = drHt;
                            dr[3] = _typ;
                            dr[4] = Math.Round(_tryLPH, 3, MidpointRounding.AwayFromZero).ToString();
                            dr[5] = _dVel.ToString("#,##0");
                            dr[6] = Math.Round((Math.Max(wt, ductHeight) / Math.Min(wt, ductHeight)), 2, MidpointRounding.AwayFromZero).ToString("0.00");
                            dr[7] = drPFT.ToString("0.00");
                            argSolTable.Rows.Add(dr);
                        }
                    }
                    if (argSolTable.Rows.Count > 60)
                    {
                        break;
                    }
                }
            }
            // sort by aspect ratio first, then by pressure loss
            // This puts the most efficient section at the list top.
            // sessionModel.SolTable.DefaultView.Sort = "PFT ASC, AR ASC, PLPH DESC";
            argSolTable.DefaultView.Sort = "AR ASC, PLPH ASC";
            // Backgroundworker return value
            e.Result = argSolTable;
        }