private IRetirementReport ReportFor(Family family, bool exitOnceMinCalcd = false, DateTime?givenRetirementDate = null)
        {
            _incomeTaxCalculator = new IncomeTaxCalculator();
            var result = new RetirementReport(_pensionAgeCalc, _incomeTaxCalculator, family, _now, givenRetirementDate, _assumptions, _taxSystem);

            var calcdMinimum = false;

            var monthsToDeath = MonthsToDeath(family.PrimaryPerson.Dob, _now);

            for (var month = 1; month <= monthsToDeath; month++)
            {
                ProgressTheResultBy1Month(family, givenRetirementDate, result, calcdMinimum);

                if (givenRetirementDate == null && !calcdMinimum)
                {
                    var retirementReport = result.CopyCalcMinimumMode();
                    if (IsThatEnoughTillDeath(family, retirementReport, month, monthsToDeath))
                    {
                        result.Persons.ForEach((p) => p.FinancialIndependenceDate = result.PrimaryPerson.StepReport.CurrentStep.StepDate);

                        if (exitOnceMinCalcd)
                        {
                            return(result);
                        }
                        calcdMinimum = true;
                    }
                }
            }

            return(result);
        }
        private bool IsThatEnoughTillDeath(Family family, RetirementReport report, int month, int monthsToDeath)
        {
            var emergencyFundMet = false;
            var minimumCash      = 0;

            for (var m = month + 1; m <= monthsToDeath; m++)
            {
                var addMonths = _now.AddMonths(m);
                ProgressTheResultBy1Month(family, null, report, true);
                if (report.EmergencyFund() >= report.RequiredEmergencyFund(addMonths))
                {
                    emergencyFundMet = true;
                }

                if ((report.Investments() + report.EmergencyFund() <= minimumCash) || (emergencyFundMet && report.Investments() <= minimumCash))
                {
                    return(false);
                }
            }

            return(emergencyFundMet);
        }
        private void ProgressTheResultBy1Month(Family family, DateTime?givenRetirementDate, RetirementReport result, bool calcdMinimum)
        {
            foreach (var person in result.Persons)
            {
                person.StepReport.NewStep(calcdMinimum, result, result.Persons.Count, givenRetirementDate);

                if (person.Retired(calcdMinimum, person.StepReport.CurrentStep.StepDate, givenRetirementDate))
                {
                    person.CrystallisePension();
                }

                var salary = person.MonthlySalaryAfterDeductionsAt(person.StepReport.CurrentStep.StepDate);

                person.StepReport.UpdateSpending();
                person.StepReport.UpdatePrivatePension();
                person.StepReport.UpdateGrowth();
                person.StepReport.UpdateStatePensionAmount(_statePensionAmountCalculator, person.StatePensionDate, salary);
                person.StepReport.UpdateSalary(salary);
                person.StepReport.ProcessTaxableIncomeIntoSavings();
            }

            var personWithClaim = result.PersonReportFor(family.PersonWithChildBenefitClaim());

            if (personWithClaim != null)
            {
                var personWithoutClaim = result.PersonReportFor(family.PersonWithoutChildBenefitClaim());
                personWithClaim.StepReport.UpdateChildBenefit(personWithoutClaim);
            }

            result.BalanceSavings();
        }