// Calculator Retirement Planner

cNeedAfterFirstSpouseDies = 0.75;

//constructor
function RetirementPlanner(setDefaults)
{
	//inputs
	if (setDefaults == 0) {

  		this.bMarried = true;
  		this.iYourCurrentAge = "";
		this.iSpCurrentAge = "";
		this.dYourAnnualSalary = "";
		this.dSpAnnualSalary = "";
		this.iYourRetirementAge = "";
		this.iSpRetirementAge = "";
		this.iYourLifeExpectancy = "";
		this.iSpLifeExpectancy = "";
		this.dAnnualRetIncNeeded = "";
        
		this.bYourCalculatorEstimate = true;
		this.bSpCalculatorEstimate = true;
		this.dYourMonthlyEstimate = "";
		this.dSpMonthlyEstimate = "";
		
		this.dYourTaxDeferCurrentBalance = "";
		this.dSpTaxDeferCurrentBalance = "";
		this.dYourTaxDeferAnnContr = "";
		this.dSpTaxDeferAnnContr = "";
		this.dYourTaxDeferContrRate = 0;
		this.dSpTaxDeferContrRate = 0;
		this.dYourTaxDeferROR = "";
		this.dSpTaxDeferROR = "";
		
		this.dYourTaxableCurrentBalance = "";
		this.dSpTaxableCurrentBalance = "";
		this.dYourTaxableAnnContr = "";
		this.dSpTaxableAnnContr = "";
		this.dYourTaxableContrRate = 0;
		this.dSpTaxableContrRate = 0;
		this.dYourTaxableROR = "";
		this.dSpTaxableROR = "";

		this.dYourAnnualPension	= "";
		this.dSpAnnualPension = "";
		this.iYourPensionStartAge	= "";
		this.iSpPensionStartAge = "";

		this.dYourCBCurrentBalance = "";
		this.dSpCBCurrentBalance = "";
		this.dYourCBAnnContr = "";
		this.dSpCBAnnContr = "";
		this.dYourCBContrRate = 0;
		this.dSpCBContrRate = 0;
		this.dYourCBROR = "";
		this.dSpCBROR = "";
		
		this.dInflation = "";

		//09-02-2008 enhancement
		this.bMortgage = false;
		this.dMortgageAmt = "";
		this.iMortgagePayoffAge = "";
		this.iYourSocSecStartAge = 62;
		this.iSpSocSecStartAge = 62;
	} else {
		this.bMarried = true;
  		this.iYourCurrentAge = 50;
		this.iSpCurrentAge = 44;
		this.dYourAnnualSalary = 16000;
		this.dSpAnnualSalary = 54900;
		this.iYourRetirementAge = 60;
		this.iSpRetirementAge = 63;
		this.iYourLifeExpectancy = 73;
		this.iSpLifeExpectancy = 75;
		this.dAnnualRetIncNeeded = 90000;
        
		this.bYourCalculatorEstimate = true;
		this.bSpCalculatorEstimate = true;
		this.dYourMonthlyEstimate = 353;
		this.dSpMonthlyEstimate = 3543;
		
		this.dYourTaxDeferCurrentBalance = 100000;
		this.dSpTaxDeferCurrentBalance = 12000;
		this.dYourTaxDeferAnnContr = 435;
		this.dSpTaxDeferAnnContr = 3000;
		this.dYourTaxDeferContrRate = 0;
		this.dSpTaxDeferContrRate = 0;
		this.dYourTaxDeferROR = 8;
		this.dSpTaxDeferROR = 6;
		
		this.dYourTaxableCurrentBalance = 67000;
		this.dSpTaxableCurrentBalance = 40000;
		this.dYourTaxableAnnContr = 10000;
		this.dSpTaxableAnnContr = 2000;
		this.dYourTaxableContrRate = 0;
		this.dSpTaxableContrRate = 0;
		this.dYourTaxableROR = 3.75;
		this.dSpTaxableROR = 2.00;

		this.dYourAnnualPension	= 12000;
		this.dSpAnnualPension = 23000;
		this.iYourPensionStartAge = 60;
		this.iSpPensionStartAge = 65;

		this.dYourCBCurrentBalance = 67000;
		this.dSpCBCurrentBalance = 40000;
		this.dYourCBAnnContr = 10000;
		this.dSpCBAnnContr = 2000;
		this.dYourCBContrRate = 0;
		this.dSpCBContrRate = 0;
		this.dYourCBROR = 3.75;
		this.dSpCBROR = 2.00;

		this.dInflation = 3.00;

		//09-02-2008 enhancement
		this.bMortgage = false;
		this.dMortgageAmt = "";
		this.iMortgagePayoffAge = "";
		this.iYourSocSecStartAge = 62;
		this.iSpSocSecStartAge = 62;
	}

	//intermediate calcs
	this.iFirstRetAge = 0;
	this.iLastRetAge = 0;
	this.iFirstDeathAge = 0;
	this.iLastDeathAge = 0;
	this.bSpRetiresFirst = false;
	this.bIncludeSalary = false;
	
	//outputs
      this.dProjectedAssetsRetirement = 0;
      this.dAssetsNeededRetirement = 0;
	this.dShortfallRetirement = 0;				
 
	this.iAssetsRunOutAge = 0;
	this.dAdditionalNeededAnnualSavings = 0;
	
	this.dAnnualNeed = new Array();
	this.dSalary  = new Array();
	this.dPension  = new Array();
	this.dSocialSecurity  = new Array();
	this.dWithdrawn	 = new Array();
	this.dShortfall = new Array();

	this.iResultHeaderRows = 0;
	this.iResultRows = 0;
	this.iResultCols = 0;
	this.aResultArray = new Array();

	//methods
 	this.mDoCalc = DoCalc;
 	
 	this.mSpAgeAtUserAge = spAgeAtUserAge;
 	this.mUserAgeAtSpAge = userAgeAtSpAge;
 	this.mGetYear = getYear;
 	this.mSetAges = setAges;
 	this.mSetNeed = setNeed;
 	this.mSetSalary = setSalary;
 	this.mSetPension = setPension;
 	this.mSetSocSec = setSocSec;
 	this.mSetWithdrawal = setWithdrawal;
 	this.mFindNeededBalanceAtRetirement = findNeededBalanceAtRetirement;
 	
 	this.mFillResults = fillResults;

	return true;
}

function spAgeAtUserAge(userAge)
{
	return userAge - this.iYourCurrentAge + this.iSpCurrentAge;
}

function userAgeAtSpAge(spAge)
{
	return spAge - this.iSpCurrentAge + this.iYourCurrentAge;
}

function getYear(userAge)
{
	//cCurrentYear from SocSec.js
	return cCurrentYear - this.iYourCurrentAge + userAge;
}

function setAges()
{
 	if (this.bMarried) 
 	{
		this.iFirstRetAge = Math.min(this.iYourRetirementAge,
		                             this.mUserAgeAtSpAge(this.iSpRetirementAge));
		this.iLastRetAge = Math.max(this.iYourRetirementAge,
		                            this.mUserAgeAtSpAge(this.iSpRetirementAge));
		this.iFirstDeathAge = Math.min(this.iYourLifeExpectancy,
		                               this.mUserAgeAtSpAge(this.iSpLifeExpectancy));
		this.iLastDeathAge = Math.max(this.iYourLifeExpectancy,
		                              this.mUserAgeAtSpAge(this.iSpLifeExpectancy));
        	this.bSpRetiresFirst = (this.iYourRetirementAge 
        	                        > this.mUserAgeAtSpAge(this.iSpRetirementAge));
		                            
	} else {
		this.iFirstRetAge = this.iYourRetirementAge;
		this.iLastRetAge = this.iYourRetirementAge;
		this.iFirstDeathAge = this.iYourLifeExpectancy;
		this.iLastDeathAge = this.iYourLifeExpectancy;
		this.bSpRetiresFirst = false;
	}
	return true;
}

function setNeed()
{
	var incrFactor = 1 + this.dInflation/100;
	var need = this.dAnnualRetIncNeeded * Math.pow(incrFactor,this.iFirstRetAge-this.iYourCurrentAge);
	
	for (var j=this.iFirstRetAge;j<this.iLastDeathAge;j++)
	{
		if (j==this.iFirstDeathAge)
			need = need * cNeedAfterFirstSpouseDies;
		this.dAnnualNeed[j] = need;
		need = need * incrFactor;

		//09-02-2008 enhancement
		if (this.bMortgage && j>=this.iMortgagePayoffAge)
			this.dAnnualNeed[j] = Math.max(0, this.dAnnualNeed[j] - this.dMortgageAmt*12.0);
	}		
	return true;
}

function setSalary()
{
	this.bIncludeSalary = (this.iFirstRetAge != this.iLastRetAge);
	
	if (this.bIncludeSalary) 
	{
		var incrFactor = 1 + this.dInflation/100;
		var salary = ((this.bSpRetiresFirst) ? this.dYourAnnualSalary : this.dSpAnnualSalary) 
		             * Math.pow(incrFactor,this.iFirstRetAge - this.iYourCurrentAge);
		for (var j=this.iFirstRetAge; j<this.iLastRetAge;j++)
		{
			this.dSalary[j] = salary;
			salary *= incrFactor;
		}
		for (var j=this.iLastRetAge; j<this.iLastDeathAge;j++)
		{
			this.dSalary[j] = 0;
		}
	}
	else 
	{
		for (var j=this.iFirstRetAge; j<this.iLastDeathAge;j++)
			this.dSalary[j] = 0;
	}

	return true;
}

function setPension()
{
	for (var j=this.iFirstRetAge; j<this.iLastDeathAge;j++)
	{
		this.dPension[j] = 0;
	}
	
	//user
	if (this.dYourAnnualPension > 0) {
		for (var j=Math.max(this.iYourRetirementAge, this.iYourPensionStartAge);j<this.iYourLifeExpectancy;j++)
		{
			this.dPension[j] = Number(this.dYourAnnualPension);
		}
	}

	//spouse
	if (this.bMarried && this.dSpAnnualPension > 0)
	{
		for (var j=Math.max(this.iSpRetirementAge, this.iSpPensionStartAge);j<this.iSpLifeExpectancy;j++)
		{
			this.dPension[this.mUserAgeAtSpAge(j)] += Number(this.dSpAnnualPension);
		}			
	}
}

function setSocSec()
{
	var spSocSec;
	var socSec = new createSocSec(this.dYourAnnualSalary,
                      			this.mGetYear(0), //birthyear
                      			this.mGetYear(this.iYourRetirementAge-1), //ProjectedLastWorkYear,  
                      			this.dInflation/100,                 
                      			this.dInflation/100);

	//09-02-2008 enhancement
	socSec.SetBenefitStartAge(this.iYourSocSecStartAge);
	
	if (!this.bYourCalculatorEstimate)
	{
		socSec.AddPIAOverride(tRetire,this.dYourMonthlyEstimate);
	}

	if (this.bMarried)
	{
		spSocSec = new createSocSec(this.dSpAnnualSalary,
                      			    this.mGetYear(this.mUserAgeAtSpAge(0)), //birthyear
                      			    this.mGetYear(this.mUserAgeAtSpAge(this.iSpRetirementAge-1)),
                      			    this.dInflation/100,                 
                      		          this.dInflation/100);
		
		//09-02-2008 enhancement
		spSocSec.SetBenefitStartAge(this.iSpSocSecStartAge);

		if (!this.bSpCalculatorEstimate)
		{
			spSocSec.AddPIAOverride(tRetire,this.dSpMonthlyEstimate);
		}

		spSocSec.AddSpSocSec(socSec,this.iYourRetirementAge, this.iYourLifeExpectancy);
		socSec.AddSpSocSec(spSocSec,this.iSpRetirementAge, this.iSpLifeExpectancy);
		
		spSocSec.CalcRetireArray(this.mSpAgeAtUserAge(this.iFirstRetAge), 
					 this.iSpRetirementAge, 
					 this.iSpLifeExpectancy, 
					 this.mSpAgeAtUserAge(this.iLastDeathAge));
	}
	
	socSec.CalcRetireArray(	this.iFirstRetAge, 
				this.iYourRetirementAge, 
				this.iYourLifeExpectancy, 
				this.iLastDeathAge);

	for (var j=this.iFirstRetAge; j<this.iLastDeathAge; j++)
	{
		this.dSocialSecurity[j] = socSec.mRetireBestArray[j]*12;
		if (this.bMarried)
		{
			this.dSocialSecurity[j] += spSocSec.mRetireBestArray[this.mSpAgeAtUserAge(j)]*12;
		}
	}
	
	return true;
}

function setWithdrawal(userDefCont)
{
	var userTaxDeferAcct = new account(	this.dYourTaxDeferCurrentBalance,
						userDefCont,
						this.dYourTaxDeferContrRate/100,
						this.dYourTaxDeferROR/100,
						this.iYourCurrentAge,
						this.iFirstRetAge,
						true);

	var userTaxableAcct = new account(	this.dYourTaxableCurrentBalance,
						this.dYourTaxableAnnContr,
						this.dYourTaxableContrRate/100,
						this.dYourTaxableROR/100,
						this.iYourCurrentAge,
						this.iFirstRetAge,
						false);

	var userCBAcct = new account(		this.dYourCBCurrentBalance,
						this.dYourCBAnnContr,
						this.dYourCBContrRate/100,
						this.dYourCBROR/100,
						this.iYourCurrentAge,
						this.iFirstRetAge,
						false);
	var spTaxDeferAcct;
	var spTaxableAcct;
	var spCBAcct;
						
	if (this.bMarried)
	{
		spTaxDeferAcct = new account(	this.dSpTaxDeferCurrentBalance,
						this.dSpTaxDeferAnnContr,
						this.dSpTaxDeferContrRate/100,
						this.dSpTaxDeferROR/100,
						this.mUserAgeAtSpAge(this.iSpCurrentAge),
						this.iFirstRetAge,
						false);

		spTaxableAcct = new account(	this.dSpTaxableCurrentBalance,
						this.dSpTaxableAnnContr,
						this.dSpTaxableContrRate/100,
						this.dSpTaxableROR/100,
						this.mUserAgeAtSpAge(this.iSpCurrentAge),
						this.iFirstRetAge,
						false);		

		spCBAcct = new account(		this.dSpCBCurrentBalance,
						this.dSpCBAnnContr,
						this.dSpCBContrRate/100,
						this.dSpCBROR/100,
						this.mUserAgeAtSpAge(this.iSpCurrentAge),
						this.iFirstRetAge,
						false);		
	}
	
	var neededWithdrawal = 0;
	
	for (var age=this.iYourCurrentAge; age<this.iLastDeathAge; age++)
	{
		if (age >= this.iFirstRetAge)
			neededWithdrawal = this.dAnnualNeed[age] 
 		    				- this.dSalary[age]
						- this.dPension[age]
						- this.dSocialSecurity[age];
		else
			neededWithdrawal = 0;
		
		neededWithdrawal = Math.max(0,neededWithdrawal);
		this.dWithdrawn[age] = neededWithdrawal;
		
		if (this.bMarried)	    
			neededWithdrawal -= spTaxableAcct.mProjectYear(age,neededWithdrawal);
		neededWithdrawal -= userTaxableAcct.mProjectYear(age,neededWithdrawal);
		

		if (this.bMarried)	    
			neededWithdrawal -= spCBAcct.mProjectYear(age,neededWithdrawal);
		neededWithdrawal -= userCBAcct.mProjectYear(age,neededWithdrawal);

		
		if (this.bMarried)
			neededWithdrawal -= spTaxDeferAcct.mProjectYear(age,neededWithdrawal);
		neededWithdrawal -= userTaxDeferAcct.mProjectYear(age,neededWithdrawal);
		
		this.dWithdrawn[age] -= neededWithdrawal;
	}
	
	this.dProjectedAssetsRetirement = userTaxDeferAcct.mBalanceArray[this.iFirstRetAge]
						+ userTaxableAcct.mBalanceArray[this.iFirstRetAge]
						+ userCBAcct.mBalanceArray[this.iFirstRetAge];
	if (this.bMarried)
	{
		this.dProjectedAssetsRetirement += spTaxDeferAcct.mBalanceArray[this.iFirstRetAge]
							+ spTaxableAcct.mBalanceArray[this.iFirstRetAge]
							+ spCBAcct.mBalanceArray[this.iFirstRetAge];
	}
	this.iAssetsRunOutAge = userTaxDeferAcct.mAssetsRunOutAge;
	
	var balanceAtDeath = userTaxDeferAcct.mBalanceArray[this.iLastDeathAge]
						+ userTaxableAcct.mBalanceArray[this.iLastDeathAge]
						+ userCBAcct.mBalanceArray[this.iLastDeathAge];
	if (this.bMarried)
	{
		balanceAtDeath += spTaxDeferAcct.mBalanceArray[this.iLastDeathAge]
					+ spTaxableAcct.mBalanceArray[this.iLastDeathAge]	
					+ spCBAcct.mBalanceArray[this.iLastDeathAge];	
	}

	//added 01/13/2005
	this.dAssetsNeededRetirement = this.dProjectedAssetsRetirement
 	this.dAssetsNeededRetirement -= userTaxDeferAcct.mPVBalance(this.iFirstRetAge,this.iLastDeathAge)
                                      + userTaxableAcct.mPVBalance(this.iFirstRetAge,this.iLastDeathAge)
                                      + userCBAcct.mPVBalance(this.iFirstRetAge,this.iLastDeathAge);
	if (this.bMarried)
	{
	 	this.dAssetsNeededRetirement -= spTaxDeferAcct.mPVBalance(this.iFirstRetAge,this.iLastDeathAge)
         	                                + spTaxableAcct.mPVBalance(this.iFirstRetAge,this.iLastDeathAge)
         	                                + spCBAcct.mPVBalance(this.iFirstRetAge,this.iLastDeathAge);
	}
	//end 01/13/2005 added code

	return balanceAtDeath;
}

function fillResults()
{
	this.dShortfallRetirement = this.dAssetsNeededRetirement - this.dProjectedAssetsRetirement;

	this.iResultHeaderRows = 2;
	this.iResultRows = this.iLastDeathAge - this.iFirstRetAge+2;
	if (this.bIncludeSalary)
		this.iResultCols = 7;
	else	
		this.iResultCols = 6;

	var k = 0;
	this.aResultArray[k++] = "";
	this.aResultArray[k++] = "Annual";
	if (this.bIncludeSalary)
		this.aResultArray[k++] = "";
	this.aResultArray[k++] = "";
	this.aResultArray[k++] = "Social";
	this.aResultArray[k++] = "Savings";
	this.aResultArray[k++] = ""
	this.aResultArray[k++] = "Age";
	this.aResultArray[k++] = "Need";
	if (this.bIncludeSalary)
		this.aResultArray[k++] = "Salary";
	this.aResultArray[k++] = "Pension";
	this.aResultArray[k++] = "Security";
	this.aResultArray[k++] = "Withdrawn";
	this.aResultArray[k++] = "Shortfall"
	
	var shortfall = 0;
	var age = this.iFirstRetAge;
	for (var j = 2; j<this.iResultRows; j++)
	{
		//age
		this.aResultArray[k++] = age; 		
		//need
		this.aResultArray[k++] = fmtNum(this.dAnnualNeed[age],",","$");
		//salary
		if (this.bIncludeSalary)
			this.aResultArray[k++] = fmtNum(this.dSalary[age],",","$");
		//pension
		this.aResultArray[k++] = fmtNum(this.dPension[age],",","$");
		//socsec
		this.aResultArray[k++] = fmtNum(this.dSocialSecurity[age],",","$");;
		//withdraw
		this.aResultArray[k++] = fmtNum(this.dWithdrawn[age],",","$");;;
		//shortfall
		shortfall = this.dAnnualNeed[age] 
 		        	- this.dSalary[age]
				- this.dPension[age]
				- this.dSocialSecurity[age]
				- this.dWithdrawn[age];
		shortfall = Math.max(0,shortfall);				
		this.aResultArray[k++] = fmtNum(shortfall,",","$");
		
		age++;
	}		
	return true;
}


function DoCalc()
{

	this.mSetAges();
	this.mSetNeed();
	this.mSetSalary();
	this.mSetPension();
	this.mSetSocSec();
	
	//iterate
	this.mFindNeededBalanceAtRetirement();

	//actual
	this.mSetWithdrawal(this.dYourTaxDeferAnnContr);

	this.mFillResults();

	return true;
}

function findNeededBalanceAtRetirement()
{
	this.stopIteration = 0.01;
	this.maxSolution = this.dAnnualRetIncNeeded * 1000;
	this.minSolution = 0;
	this.calculation = setWithdrawal;
	
	this.dAdditionalNeededAnnualSavings = iterate(this)-this.dYourTaxDeferAnnContr;
	
	//Deleted 01/13/2005: this.dAssetsNeededRetirement = this.dProjectedAssetsRetirement;
}