public IndependentEfcCalculatorArguments ValidateIndependentEfcCalculatorArguments(RawIndependentEfcCalculatorArguments args)
        {
            if (args == null)
            {
                throw new ArgumentException("No raw arguments provided");
            }

            // Age
            int age
                = _validator.ValidateNonZeroInteger(
                        args.StudentAge,
                        LabelIndStudentAge,
                        ParamIndStudentAge);

            // Marital Status
            MaritalStatus maritalStatus
                = _validator.ValidateMaritalStatus(
                        args.MaritalStatus,
                        LabelIndStudentMaritalStatus,
                        ParamMaritalStatus);

            // Is Student Working?
            bool isStudentWorking
                = _validator.ValidateBoolean(
                        args.IsStudentWorking,
                        LabelIsStudentWorking,
                        ParamIsStudentWorking);

            // Student Work Income
            double studentWorkIncome
                = isStudentWorking
                        ? _validator.ValidatePositiveMoneyValue(
                            args.StudentWorkIncome,
                            LabelStudentWorkIncome,
                            ParamStudentWorkIncome)
                        : 0;

            HouseholdMember student = new HouseholdMember
                                            {
                                                IsWorking = isStudentWorking,
                                                WorkIncome = studentWorkIncome
                                            };

            HouseholdMember spouse = null;
            
            if (maritalStatus == MaritalStatus.MarriedRemarried)
            {
                // Is Spouse Working?
                bool isSpouseWorking
                    = _validator.ValidateBoolean(
                            args.IsSpouseWorking,
                            LabelIsSpouseWorking,
                            ParamIsSpouseWorking);

                // Spouse Work Income
                double spouseWorkIncome
                    = isSpouseWorking
                            ? _validator.ValidatePositiveMoneyValue(
                                    args.SpouseWorkIncome,
                                    LabelSpouseWorkIncome,
                                    ParamSpouseWorkIncome)
                            : 0;

                spouse = new HouseholdMember
                                {
                                    IsWorking = isSpouseWorking,
                                    WorkIncome = spouseWorkIncome
                                };
            }

            // Student and Spouse's AGI
            double agi = _validator.ValidateMoneyValue(
                            args.StudentAgi,
                            LabelIndStudentAgi,
                            ParamIndStudentAgi);

            // Are Tax Filers?
            bool areTaxFilers
                = _validator.ValidateBoolean(
                        args.IsStudentTaxFiler,
                        LabelIsIndStudentTaxFiler,
                        ParamIsIndStudentTaxFiler);

            // Income Tax Paid
            double incomeTaxPaid
                = _validator.ValidateMoneyValue(
                        args.StudentIncomeTax,
                        LabelIndStudentIncomeTax,
                        ParamIndStudentIncomeTax);

            // Untaxed Income And Benefits
            double untaxedIncomeAndBenefits
                = _validator.ValidatePositiveMoneyValue(
                        args.StudentUntaxedIncomeAndBenefits,
                        LabelIndStudentUntaxedIncomeAndBenefits,
                        ParamIndStudentUntaxedIncomeAndBenefits);

            // Additional Financial Information
            double additionalFinancialInfo
                = _validator.ValidatePositiveMoneyValue(
                        args.StudentAdditionalFinancialInfo,
                        LabelIndStudentAdditionalFinancialInfo,
                        ParamIndStudentAdditionalFinancialInfo);

            // Cash, Savings, Checking
            double cashSavingsChecking
                = _validator.ValidatePositiveMoneyValue(
                        args.StudentCashSavingsChecking,
                        LabelIndStudentCashSavingsChecking,
                        ParamIndStudentCashSavingsChecking);

            // Investment Net Worth
            double investmentNetWorth
                = _validator.ValidateMoneyValue(
                        args.StudentInvestmentNetWorth,
                        LabelIndStudentInvestmentNetWorth,
                        ParamIndStudentInvestmentNetWorth);

            // Business Farm Net Worth
            double businessFarmNetWorth
                = _validator.ValidateMoneyValue(
                        args.StudentBusinessFarmNetWorth,
                        LabelIndStudentBusinessFarmNetWorth,
                        ParamIndStudentBusinessFarmNetWorth);

            // Has Dependents?
            bool hasDependents
                = _validator.ValidateBoolean(
                        args.HasDependents,
                        LabelIndStudentHasDep,
                        ParamIndStudentHasDep);

            // State of Residency
            UnitedStatesStateOrTerritory stateOfResidency
                = _validator.ValidateUnitedStatesStateOrTerritory(
                        args.StateOfResidency,
                        LabelStateOfResidency,
                        ParamStateOfResidency);

            // Number in Household
            int numberInHousehold
                = _validator.ValidateNonZeroInteger(
                        args.NumberInHousehold,
                        LabelNumInHousehold,
                        ParamNumInHousehold);

            // Number in College
            int numberInCollege
                = _validator.ValidateNonZeroInteger(
                        args.NumberInCollege,
                        LabelNumInCollege,
                        ParamNumInCollege);

            // CHECK: Number in Household must be greater than or equal to Number in College
            if (numberInCollege > numberInHousehold)
            {
                _validator.Errors.Add(new ValidationError(ParamNumInCollege,
                    String.Format(@"{0} must be less than or equal to {1}",
                    LabelNumInCollege, LabelNumInHousehold)));
            }

            // CHECK: If student has dependents, Number in Household can not be less than two
            if (hasDependents && numberInHousehold < 2)
            {
                _validator.Errors.Add(new ValidationError(ParamIndStudentHasDep,
                    String.Format(@"Student has dependents, but {0} was less than two.",
                    LabelNumInHousehold)));
            }

            // Is Qualified for Simplified
            bool isQualifiedForSimplified
                = _validator.ValidateBoolean(
                        args.IsQualifiedForSimplified,
                        LabelIsQualifiedForSimplified,
                        ParamIsQualifiedForSimplified);

            // Months of Enrollment
            int monthsOfEnrollment
                = _validator.ValidateNonZeroInteger(
                        args.MonthsOfEnrollment,
                        LabelMonthsOfEnrollment,
                        ParamMonthsOfEnrollment);

            if (_validator.Errors.Any())
            {
                return null;
            }

            // Build calculation arguments
            IndependentEfcCalculatorArguments parsedArgs =
                new IndependentEfcCalculatorArguments
                {
                    Student = student,
                    Spouse = spouse,
                    AdjustedGrossIncome = agi,
                    AreTaxFilers = areTaxFilers,
                    IncomeTaxPaid = incomeTaxPaid,
                    UntaxedIncomeAndBenefits = untaxedIncomeAndBenefits,
                    AdditionalFinancialInfo = additionalFinancialInfo,
                    CashSavingsCheckings = cashSavingsChecking,
                    InvestmentNetWorth = investmentNetWorth,
                    BusinessFarmNetWorth = businessFarmNetWorth,
                    HasDependents = hasDependents,
                    MaritalStatus = maritalStatus,
                    StateOfResidency = stateOfResidency,
                    NumberInHousehold = numberInHousehold,
                    NumberInCollege = numberInCollege,
                    Age = age,
                    IsQualifiedForSimplified = isQualifiedForSimplified,
                    MonthsOfEnrollment = monthsOfEnrollment
                };

            return parsedArgs;
        }
        public void GetIndependentEfcProfile_ThreeMonthsEnrollment_Calculated()
        {
            var args = new IndependentEfcCalculatorArguments
            {
                Student = new HouseholdMember
                {
                    IsWorking = true,
                    WorkIncome = 60000
                },
                Spouse = null,
                AdjustedGrossIncome = 60000,
                AreTaxFilers = true,
                IncomeTaxPaid = 6000,
                UntaxedIncomeAndBenefits = 1000,
                AdditionalFinancialInfo = 200,
                CashSavingsCheckings = 80000,
                InvestmentNetWorth = 5000,
                BusinessFarmNetWorth = 0,
                HasDependents = false,
                MaritalStatus = MaritalStatus.SingleSeparatedDivorced,
                StateOfResidency = UnitedStatesStateOrTerritory.Alabama,
                NumberInHousehold = 1,
                NumberInCollege = 1,
                Age = 25,
                MonthsOfEnrollment = 3
            };

            EfcProfile profile = _efcCalculator.GetIndependentEfcProfile(args);
            Assert.AreEqual(12243, profile.ExpectedFamilyContribution);
        }
        public IndependentEfcCalculatorArguments ValidateSimpleIndependentEfcCalculatorArguments(RawSimpleIndependentEfcCalculatorArguments args)
        {
            if (args == null)
            {
                throw new ArgumentException("No raw arguments provided");
            }

            // Marital Status
            MaritalStatus maritalStatus
                = _validator.ValidateMaritalStatus(
                    args.MaritalStatus,
                    LabelIndStudentMaritalStatus,
                    ParamMaritalStatus);

            // Student Age
            int studentAge =
                _validator.ValidateNonZeroInteger(
                    args.StudentAge,
                    LabelIndStudentAge,
                    ParamIndStudentAge);

            // Student Income
            double studentIncome =
                _validator.ValidatePositiveMoneyValue(
                    args.StudentIncome,
                    LabelIndStudentIncome,
                    ParamIndStudentIncome);

            // Student Other Income
            double studentOtherIncome =
                _validator.ValidatePositiveMoneyValue(
                    args.StudentOtherIncome,
                    LabelIndStudentOtherIncome,
                    ParamIndStudentOtherIncome);

            // Student Income Earned By
            IncomeEarnedBy incomeEarnedBy =
                _validator.ValidateIncomeEarnedBy(
                    args.StudentIncomeEarnedBy,
                    LabelIndStudentIncomeEarnedBy,
                    ParamIndStudentIncomeEarnedBy);

            // CHECK: If Single/Separated/Divorced, "Student's Income Earned By" can not be "Both"
            if (maritalStatus == MaritalStatus.SingleSeparatedDivorced && incomeEarnedBy == IncomeEarnedBy.Both)
            {
                _validator.Errors.Add(new ValidationError(ParamIndStudentIncomeEarnedBy,
                    String.Format(@"{0} was ""Single/Separated/Divorced"", but {1} was marked as earned by both student and spouse",
                    LabelIndStudentMaritalStatus, LabelIndStudentIncomeEarnedBy)));
            }

            // CHECK: If "Student's Income Earned By" is "None", then "Parent Income" must be 0
            if (incomeEarnedBy == IncomeEarnedBy.None && studentIncome > 0)
            {
                _validator.Errors.Add(new ValidationError(ParamParentIncome,
                    String.Format(@"{0} was marked as earned by neither student nor spouse, but {1} was greater than 0",
                        LabelIndStudentIncomeEarnedBy, LabelIndStudentIncome)));
            }

            // Student Income Tax Paid
            double studentIncomeTaxPaid =
                _validator.ValidatePositiveMoneyValue(
                    args.StudentIncomeTax,
                    LabelIndStudentIncomeTax,
                    ParamIndStudentIncomeTax);

            // Student Assets
            double studentAssets =
                _validator.ValidatePositiveMoneyValue(
                    args.StudentAssets,
                    LabelIndStudentAssets,
                    ParamIndStudentAssets);

            // Number in Household
            int numberInHousehold =
                _validator.ValidateNonZeroInteger(
                    args.NumberInHousehold,
                    LabelNumInHousehold,
                    ParamNumInHousehold);

            // Number in College
            int numberInCollege =
                _validator.ValidateNonZeroInteger(
                    args.NumberInCollege,
                    LabelNumInCollege,
                    ParamNumInCollege);

            // CHECK: Number in Household must be greater than or equal to Number in College
            if (numberInCollege > numberInHousehold)
            {
                _validator.Errors.Add(new ValidationError(ParamNumInCollege,
                    String.Format(@"{0} must be less than or equal to {1}",
                    LabelNumInCollege, LabelNumInHousehold)));
            }

            // Has Dependents
            bool hasDependents =
                _validator.ValidateBoolean(
                    args.HasDependents,
                    LabelIndStudentHasDep,
                    ParamIndStudentHasDep);

            // CHECK: If student has dependents, Number in Household can not be less than two
            if (hasDependents && numberInHousehold < 2)
            {
                _validator.Errors.Add(new ValidationError(ParamIndStudentHasDep,
                    String.Format(@"Student has dependents, but {0} was less than two.",
                    LabelNumInHousehold)));
            }

            // State of Residency
            UnitedStatesStateOrTerritory stateOfResidency =
                _validator.ValidateUnitedStatesStateOrTerritory(
                    args.StateOfResidency, 
                    LabelStateOfResidency,
                    ParamStateOfResidency);

            if (_validator.Errors.Count > 0)
            {
                return null;
            }

            // Build a list of arguments for the full EFC calculation using assumed
            // values gleaned from the "simplified" values provided

            bool isStudentWorking = false;
            bool isSpouseWorking = false;

            double studentWorkIncome = 0;
            double spouseWorkIncome = 0;

            if(incomeEarnedBy == IncomeEarnedBy.One)
            {
                isStudentWorking = true;
                studentWorkIncome = studentIncome;
            }

            if(incomeEarnedBy == IncomeEarnedBy.Both)
            {
                isStudentWorking = isSpouseWorking = true;
                studentWorkIncome = spouseWorkIncome = (studentIncome/2);
            }

            HouseholdMember student = new HouseholdMember
            {
                IsWorking = isStudentWorking,
                WorkIncome = studentWorkIncome
            };

            HouseholdMember spouse = null;
            if (maritalStatus == MaritalStatus.MarriedRemarried)
            {
                spouse = new HouseholdMember
                {
                    IsWorking = isSpouseWorking,
                    WorkIncome = spouseWorkIncome
                };
            }

            IndependentEfcCalculatorArguments parsedArgs = new IndependentEfcCalculatorArguments
            {
                Student = student,
                Spouse = spouse,

                // ASSUME: "Student and Spouse's Income" == "Student and Spouse's AGI"
                AdjustedGrossIncome = studentIncome,

                // ASSUME: Student and Spouse are tax filers
                AreTaxFilers = true,

                IncomeTaxPaid = studentIncomeTaxPaid,

                // ASSUME: "Student and Spouse's Untaxed Income and Benefits" == "Student and Spouse's Other Income"
                UntaxedIncomeAndBenefits = studentOtherIncome,

                // ASSUME: "Student and Spouse's Additional Financial Information" is zero
                AdditionalFinancialInfo = 0,

                // ASSUME: "Student's and Spouse's Cash, Savings, and Checking" == "Student and Spouse's Assets"
                CashSavingsCheckings = studentAssets,

                // ASSUME: "Student and Spouse's Net Worth of Investments" is zero
                InvestmentNetWorth = 0,

                // ASSUME: "Student and Spouse's Net Worth of Business and/or Investment Farm" is zero
                BusinessFarmNetWorth = 0,

                HasDependents = hasDependents,
                MaritalStatus = maritalStatus,
                StateOfResidency = stateOfResidency,
                NumberInHousehold = numberInHousehold,
                NumberInCollege = numberInCollege,
                Age = studentAge,

                // ASSUME: Student is NOT qualified for simplified formula
                IsQualifiedForSimplified = false,

                // ASSUME: Nine months of enrollment
                MonthsOfEnrollment = 9

            };

            return parsedArgs;
        }
        public void GetIndependentEfcProfile_AutoZero_Calculated()
        {
            var args = new IndependentEfcCalculatorArguments
            {
                Student = new HouseholdMember
                {
                    IsWorking = true,
                    WorkIncome = 11500
                },
                Spouse = new HouseholdMember
                {
                    IsWorking = true,
                    WorkIncome = 11500
                },
                AdjustedGrossIncome = 32000,
                AreTaxFilers = false,
                IncomeTaxPaid = 6000,
                UntaxedIncomeAndBenefits = 999999999999,
                AdditionalFinancialInfo = 0,
                CashSavingsCheckings = 123456789,
                InvestmentNetWorth = 123456789,
                BusinessFarmNetWorth = 350000,
                HasDependents = true,
                MaritalStatus = MaritalStatus.MarriedRemarried,
                StateOfResidency = UnitedStatesStateOrTerritory.Alaska,
                NumberInHousehold = 3,
                NumberInCollege = 1,
                Age = 30,
                IsQualifiedForSimplified = true,
                MonthsOfEnrollment = 9
            };

            EfcProfile profile = _efcCalculator.GetIndependentEfcProfile(args);
            Assert.AreEqual(0, profile.ExpectedFamilyContribution);
        }
        public void GetIndependentEfcProfile_HasDependentsLowValues_Calculated()
        {
            var args = new IndependentEfcCalculatorArguments
            {
                Student = new HouseholdMember
                {
                    IsWorking = false,
                    WorkIncome = 0
                },
                Spouse = new HouseholdMember
                {
                    IsWorking = false,
                    WorkIncome = 0
                },
                AdjustedGrossIncome = 0,
                AreTaxFilers = false,
                IncomeTaxPaid = 0,
                UntaxedIncomeAndBenefits = 10000,
                AdditionalFinancialInfo = 0,
                CashSavingsCheckings = 0,
                InvestmentNetWorth = 0,
                BusinessFarmNetWorth = 0,
                HasDependents = true,
                MaritalStatus = MaritalStatus.MarriedRemarried,
                StateOfResidency = UnitedStatesStateOrTerritory.AmericanSamoa,
                NumberInHousehold = 3,
                NumberInCollege = 1,
                Age = 25,
                MonthsOfEnrollment = 9
            };

            EfcProfile profile = _efcCalculator.GetIndependentEfcProfile(args);
            Assert.AreEqual(0, profile.ExpectedFamilyContribution);
        }
        public void GetIndependentEfcProfile_NoStudent_ZeroEfc()
        {
            IndependentEfcCalculatorArguments args = new IndependentEfcCalculatorArguments
            {
                NumberInCollege = 3,
                Student = null
            };

            EfcProfile result = _efcCalculator.GetIndependentEfcProfile(args);
            Assert.AreEqual(0, result.ExpectedFamilyContribution);
        }
        public void GetIndependentEfcProfile_NegativeNumberInCollege_ZeroEfc()
        {
            IndependentEfcCalculatorArguments args = new IndependentEfcCalculatorArguments
            {
                NumberInCollege = -1,
                Student = new HouseholdMember()
            };

            EfcProfile result = _efcCalculator.GetIndependentEfcProfile(args);
            Assert.AreEqual(0, result.ExpectedFamilyContribution);
        }
        /// <summary>
        /// Calculates student contribution (PC) and expected family contribution (EFC) for an independent student
        /// </summary>
        /// <param name="args">Parameters for the calculation</param>
        /// <returns>Student contribution (PC) and expected family contribution (EFC) for an independent student</returns>
        public EfcProfile GetIndependentEfcProfile(IndependentEfcCalculatorArguments args)
        {
            if (args.NumberInCollege <= 0
                    || args.MonthsOfEnrollment <= 0
                    || args.Student == null)
            {
                return new EfcProfile(0, 0, 0, 0);
            }

            EfcCalculationRole role = (args.HasDependents)
                                          ? EfcCalculationRole.IndependentStudentWithDependents
                                          : EfcCalculationRole.IndependentStudentWithoutDependents;

            double workIncome = 0;

            List<HouseholdMember> householdMembers = new List<HouseholdMember> { args.Student };
            workIncome += args.Student.IsWorking ? args.Student.WorkIncome : 0;

            if (args.Spouse != null)
            {
                if (args.Spouse.IsWorking)
                {
                    workIncome += args.Spouse.WorkIncome;
                }

                householdMembers.Add(args.Spouse);
            }

            double simpleIncome = (args.AreTaxFilers) ? args.AdjustedGrossIncome : workIncome;

            // Determine Auto Zero EFC eligibility
            if (args.IsQualifiedForSimplified
                && role == EfcCalculationRole.IndependentStudentWithDependents
                && simpleIncome <= _constants.AutoZeroEfcMax)
            {
                return new EfcProfile(0, 0, 0, 0);
            }

            // Student's Total Income
            double totalIncome = _incomeCalculator.CalculateTotalIncome(
                                    args.AdjustedGrossIncome,
                                    workIncome,
                                    args.AreTaxFilers,
                                    args.UntaxedIncomeAndBenefits,
                                    args.AdditionalFinancialInfo);

            // Student's Total Allowances
            double totalAllowances = _allowanceCalculator.CalculateTotalAllowances(
                                        role,
                                        args.MaritalStatus,
                                        args.StateOfResidency,
                                        args.NumberInCollege,
                                        args.NumberInHousehold,
                                        householdMembers,
                                        totalIncome,
                                        args.IncomeTaxPaid);

            // Student's Available Income (Contribution from Available Income)
            double availableIncome = _incomeCalculator.CalculateAvailableIncome(role, totalIncome, totalAllowances);

            // Determine Simplified EFC Equation Eligibility
            bool useSimplified = (args.IsQualifiedForSimplified && simpleIncome <= _constants.SimplifiedEfcMax);

            // Student's Contribution From Assets
            double assetContribution = 0;

            if (!useSimplified)
            {
                assetContribution = _assetContributionCalculator.CalculateContributionFromAssets(
                    role,
                    args.MaritalStatus,
                    args.Age,
                    args.CashSavingsCheckings,
                    args.InvestmentNetWorth,
                    args.BusinessFarmNetWorth);
            }

            // Student's Adjusted Available Income
            double adjustedAvailableIncome = availableIncome + assetContribution;

            // Student Contribution From AAI
            double studentContributionFromAai
                = _aaiContributionCalculator.CalculateContributionFromAai(role, adjustedAvailableIncome);

            // Student's Contribution
            double studentContribution = Math.Round(studentContributionFromAai / args.NumberInCollege,
                MidpointRounding.AwayFromZero);

            // Modify Student's Available Income based on months of enrollment
            if (args.MonthsOfEnrollment < DefaultMonthsOfEnrollment)
            {
                // LESS than default months of enrollment
                double monthlyContribution = Math.Round(studentContribution / DefaultMonthsOfEnrollment);
                studentContribution = monthlyContribution * args.MonthsOfEnrollment;
            }

            // For MORE than default months of enrollment, the standard contribution is used

            EfcProfile profile = new EfcProfile(studentContribution, 0, studentContribution, 0);
            return profile;
        }