/// <summary>
        /// Returns the payment amount on settlement date based on the cashflowlist.
        /// </summary>
        /// <remarks>
        /// The payment amount on settlement date will be either the dirty price of the bond or the clean price of the bond plus
        /// the accrued interest (two cashflows). Note that for a long position in a bond forward, this value is negative
        /// (indicating outgoing cashflow).
        /// </remarks>
        protected virtual void GetSettlementAmount(Vector amount, double valueDate, double baseDate, IInflationRate inflationRate, IPriceIndexVolatility indexVolatility)
        {
            amount.Clear();
            using (var cache = Vector.CacheLike(amount))
            {
                var    deal          = (IInflationCashflowListDeal)Deal;
                var    cashflows     = deal.GetCashflows();
                Vector settlementPay = cache.Get();

                for (int i = 0; i < cashflows.Count(); ++i)
                {
                    if (cashflows.GetCashflow(i).Payment_Date < deal.Settlement_Date)
                    {
                        continue;
                    }
                    else if (cashflows.GetCashflow(i).Payment_Date == deal.Settlement_Date)
                    {
                        cashflows.GetCashflow(i).ExpectedAmount(settlementPay, CalcUtils.DaysToYears(valueDate - baseDate), inflationRate, indexVolatility,
                                                                IntraValuationDiagnosticsWriterFactory.GetOrCreate(IntraValuationDiagnosticsLevel.None));
                        amount.Add(settlementPay);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Value the deal.
        /// </summary>
        public override void Value(ValuationResults valuationResults, PriceFactorList factors, BaseTimeGrid baseTimes)
        {
            PreValue(factors);

            CallableBondForward deal = (CallableBondForward)Deal;

            double baseDate       = factors.BaseDate;
            double settlementDate = deal.Settlement_Date;
            double tSettle        = CalcUtils.DaysToYears(settlementDate - baseDate);

            TimeGridIterator tgi = new TimeGridIterator(fT);

            PVProfiles      result  = valuationResults.Profile;
            AccruedInterest accrued = valuationResults.Results <AccruedInterest>();

            var intraValuationDiagnosticsWriter =
                IntraValuationDiagnosticsWriterFactory.GetOrCreate(IntraValuationDiagnosticsLevel.None);

            using (var outerCache = Vector.Cache(factors.NumScenarios))
            {
                // SwapOptionPricerObject is null when there are no valid exercise dates.
                SwaptionPricer.WorkingArrays arrays = fSwaptionPricer != null?fSwaptionPricer.PreValue(fDiscountRate, outerCache) : null;

                Vector tExercise = outerCache.Get(double.PositiveInfinity);                    // time of exercise
                int    numberScenariosExercised = 0;

                Vector defaultDate = fCreditRating != null?outerCache.Get(CalcUtils.DateTimeMaxValueAsDouble) : null;

                var defaultedBeforeBaseDate = fNeedsCreditRating &&
                                              CreditRating.DefaultedBeforeBaseDate(fCreditRating, baseDate);

                VectorEngine.For(tgi, () =>
                {
                    using (var cache = Vector.Cache(factors.NumScenarios))
                    {
                        Vector cash = cache.GetClear();
                        Vector pv   = cache.GetClear();

                        if (defaultedBeforeBaseDate || numberScenariosExercised == factors.NumScenarios)
                        {
                            // already defaulted before base date or All scenarios exercised
                            result.AppendVector(tgi.Date, pv);
                            return(LoopAction.Break);
                        }
                        else
                        {
                            // Value of the bond cashflows after the settlement.
                            fCashflowList.Value(pv, cash, null, baseDate, tgi.Date, null, fDiscountRate, fSurvivalProb, null,
                                                null, intraValuationDiagnosticsWriter, 0.0);

                            // Add the value of the principal and amortization cashflows.
                            fFixedCashflowList.Value(pv, cash, baseDate, tgi.Date, null, fDiscountRate, fSurvivalProb,
                                                     intraValuationDiagnosticsWriter, 0.0);

                            if (fSurvivalProb != null)
                            {
                                fRecoveryList.Value(pv, baseDate, tgi.Date, fDiscountRate, fSurvivalProb,
                                                    intraValuationDiagnosticsWriter);
                            }

                            if (fNeedsCreditRating)
                            {
                                UpdateDefaultDate(fCreditRating, tgi.Date, tgi.T, defaultDate);
                            }

                            // Add/subtract value of option
                            if (fSwaptionPricer != null)
                            {
                                using (var innerCache = Vector.Cache(factors.NumScenarios))
                                {
                                    Vector optionPv       = innerCache.Get();
                                    Vector exerciseStrike = innerCache.GetClear();    // strike of underlying at exercise
                                    Vector exerciseFee    = innerCache.GetClear();    // fee paid on exercise
                                    fSwaptionPricer.Value(optionPv, tgi.T, fDiscountRate, fInterestYieldVol, fSurvivalProb, arrays, tExercise,
                                                          exerciseStrike, exerciseFee, Early_Exercise_Today == YesNo.Yes, ref numberScenariosExercised);

                                    // Ignore optionality if in default.
                                    if (fNeedsCreditRating)
                                    {
                                        optionPv.AssignConditional(defaultDate > tgi.Date, optionPv, 0.0);
                                    }

                                    pv.Add(optionPv);
                                }
                            }

                            if (tgi.Date < settlementDate)
                            {
                                // Forward deal before settlement date
                                if (deal.Is_Defaultable == YesNo.No)
                                {
                                    pv.Assign((pv / fDiscountRate.Get(tgi.T, tSettle) - fSettlementAmount) * fRepoRate.Get(tgi.T, tSettle));
                                }
                                else
                                {
                                    pv.Subtract((fSettlementAmount - fAccrued) * fRepoRate.Get(tgi.T, tSettle) + fAccrued * fDiscountRate.Get(tgi.T, tSettle));   // discount accrued with bond rate; accrued interest must cancel
                                }
                            }
                            else if (tgi.Date == settlementDate)
                            {
                                // Forward deal at settlement date
                                pv.Subtract(fSettlementAmount);
                                cash.Subtract(fSettlementAmount);
                            }

                            if (deal.IsForward())
                            {
                                // Cash settled forward
                                if (tgi.Date == settlementDate)
                                {
                                    cash.Assign(pv);
                                }
                                else
                                {
                                    cash.Clear();
                                }
                            }
                            else if (tgi.Date >= settlementDate)
                            {
                                using (var innerCache = Vector.Cache(factors.NumScenarios))
                                {
                                    Vector afterExercise  = innerCache.Get(tExercise < tgi.T);
                                    Vector beforeExercise = innerCache.Get(tExercise > tgi.T);

                                    Vector exercisedToday = innerCache.GetClear();
                                    exercisedToday.Assign(afterExercise.Or(beforeExercise));
                                    exercisedToday.Assign(!exercisedToday);

                                    double callAmount = deal.Notional * Percentage.PercentagePoint * deal.Call_Prices.GetRate(tgi.Date);

                                    // Before exercise: pv is bondPV + optionPv and cash is bondCash.
                                    // On exercise: pv and cash are bondCash + callAmount.
                                    // After exercise: pv and cash are zero.
                                    cash.AssignConditional(exercisedToday, cash + callAmount, beforeExercise * cash);
                                    pv.AssignConditional(exercisedToday, cash, beforeExercise * pv);
                                }
                            }

                            // Apply leg sign to results
                            int buySellSign = deal.Buy_Sell == BuySell.Buy ? +1 : -1;
                            ApplySign(pv, cash, buySellSign);

                            if (fNeedsCreditRating)
                            {
                                Vector beforeExercise      = cache.Get(tExercise > tgi.T);
                                Vector modifiedDefaultDate = cache.Get();

                                // If default occurs after the call option has been exercise, default is irrelevant.
                                // If default occurs on the same date that the call option is exercised, the assumption
                                // is that the bond has been paid back in full, otherwise it wouldn''t be considered exercised.
                                modifiedDefaultDate.AssignConditional(beforeExercise, defaultDate, double.PositiveInfinity);
                                GetDefaultValue(baseDate, tgi.Date, modifiedDefaultDate, fRecoveryRate, pv, cash);
                            }

                            valuationResults.Cash.Accumulate(fFxRate, tgi.Date, cash);
                            result.AppendVector(tgi.Date, pv * fFxRate.Get(tgi.T));

                            if (accrued != null)
                            {
                                accrued.SetValue(tgi.Date, fCashflowList.CalculateAccrual(tgi.Date, accrued.AccrueFromToday, fDeal.GetHolidayCalendar()) * buySellSign);
                            }
                        }
                    }

                    return(LoopAction.Continue);
                });
            }

            result.Complete(fT);
        }