function current_system_table(household_sizes, spending_levels, householdType,caption,cellfunc) {
	// Specify the row labels and data.
	var rformatfunc = function(input) { return formatNumber(input,"$,##.##"); }
	var rd = new RowDef(spending_levels,rformatfunc,"Income($)");
	
	// Specify the col labels and data.
	var cformatfunc = function(input) { return input; }
	var hht_formatfunc = function(input) { return householdTypeString[input]; }
	var cd_htt_array = new Array(1);
	cd_htt_array[0] = householdType;
	var cd_hht = new ColDef(cd_htt_array,hht_formatfunc);
	var cd_hhs = new ColDef(household_sizes,cformatfunc);
	
	// Specify the table info
 	var td = new TableDef(rd,Array(cd_hht,cd_hhs),cellfunc,caption);
 	var st = new SmartTable(td);
 	return st.getNode();
}

function current_system_rate_cell() {
	var income = arguments[0];
	var householdType = arguments[1];
	var household_size = arguments[2]; 
        
  // Add text to cell
  var etr = new EffectiveTaxRate(income,household_size,
        		  					  				 householdType);
  var rate = etr.rate;
  var title = "Current System Effective Rate (by Houshold Size)";
  var onclick = function () {
  	revealDetails(this,etr.rateDescription());
  }
  
  var cell = detailedCell(rate,"%##.##",title,onclick); 
  return cell;
}

function current_system_credits_disabled_rate_cell() {
	var income = arguments[0];
	var householdType = arguments[1];
	var household_size = arguments[2]; 
        
  // Add text to cell
  var etr = new EffectiveTaxRate(income,household_size,
        		  					  				 householdType,true);
  var rate = etr.rate;
  var title = "Current System Effective Rate (by Houshold Size)";
  var onclick = function () {
  	revealDetails(this,etr.rateDescription());
  }
  
  var cell = detailedCell(rate,"%##.##",title,onclick); 
  return cell;
}

function current_system_bp_cell() {
	var income = arguments[0];
	var householdType = arguments[1];
	var household_size = arguments[2]; 
        
  // Add text to cell
  var etr = new EffectiveTaxRate(income,household_size,
        		  					  				 householdType);
  var bp = etr.buyingPower;
  var title = "Current System Effective Rate (by Houshold Size)";
  var onclick = "revealDetails(this,(new EffectiveTaxRate(";
  onclick = onclick + income + "," + household_size + "," + householdType;
  onclick = onclick + ")).buyingPowerDescription())";
  
  var cell = detailedCell(bp,"%##.##",title,onclick); 
  return cell;
}

function PayrollTax(income) {
  this.fica_rate = 0.062;
  this.medicare_rate = 0.0145;
  this.fica_threshold = 87000;
  this.income = income;	
			
  this._ficaEmployee = function() {
  	var fe = this.fica_rate*this.income;
  	if(this.income > this.fica_threshold) {
	  	fe = this.fica_rate*this.fica_threshold;
  	} 
		return fe;	
  }

  this._fica = function() { 
		return this.ficaEmployee + this.ficaEmployer;
  }
	
  this._medicareEmployee = function () { 
		return this.medicare_rate*this.income;
  }
  
  this._medicare = function() {
		return this.medicareEmployee + this.medicareEmployer;
	}
	
	this._taxEmployee = function() {
		return this.medicareEmployee + this.ficaEmployee;
	}
	
	this._taxEmployer = function() {
		return this.medicareEmployer + this.ficaEmployer;
	}
	
	this._tax = function() {
		return this.medicare + this.fica;	
	}
	
	this.ficaEmployee = this._ficaEmployee();
	this.ficaEmployer = this.ficaEmployee;	
	this.fica = this._fica();
	this.medicareEmployee = this._medicareEmployee();
  this.medicareEmployer = this.medicareEmployee;
  this.medicare = this._medicare();
  this.taxEmployee = this._taxEmployee();
  this.taxEmployer = this._taxEmployer();
  this.tax = this._tax();
	
	this.description = function(dsn) {
		// Add a header line for the Payroll Taxes section
	  text = "Payroll Taxes (Social Security and Medicare)";
		dsn.addBoldLine(text);
		
		// Add a line for employee payroll tax
		text = "ep = Employee Payroll Tax = "
		text = text + formatNumber(this.fica_rate,"%##.##");
		text = text + "*min(i," + formatNumber(this.fica_threshold,"$,##.##");
		text = text + ") + " + formatNumber(this.medicare_rate,"%##.##") + "*i";
		dsn.addLine(text);
		text = "ep = ";
		text = text + formatNumber(this.fica_rate,"%##.##");
		text = text + "*min(" + formatNumber(this.income, "$,##.##");
		text = text + "," + formatNumber(this.fica_threshold,"$,##.##");
		text = text + ") + "   + formatNumber(this.medicare_rate,"%##.##");
		text = text + "*" + formatNumber(this.income, "$,##.##") + " = ";
		text = text + formatNumber(this.taxEmployee,"$,##.##");
		dsn.addLine(text);
			
		// Add a line for employer payroll tax
		text = "Ep = Employer Payroll Tax Match = ep =";
		text = text + formatNumber(this.taxEmployer,"$,##.##");
		dsn.addLine(text);
		
		// Add a line for total payroll tax
		text = "pt = Payroll Tax = ep + Ep = ";
		text = text + formatNumber(this.taxEmployee,"$,##.##") + " + ";
		text = text + formatNumber(this.taxEmployer,"$,##.##") + " = ";
		text = text + formatNumber(this.tax,"$,##.##");
		dsn.addLine(text);
	}
}

function EarnedIncomeTaxCredit(effectiveTaxRate) {
	this.effectiveTaxRate = effectiveTaxRate;
		
	this._creditRate = function() {
		var children = this.effectiveTaxRate.children;
		var rate = 0.0766;
		if (children == 1) {
			rate = 0.3401;
		} else if (children > 1) {
			rate = 0.40;
		}
		return rate;
	}

	this._phaseoutRate = function() {
		var children = this.effectiveTaxRate.children;
		var rate = 0.0766;
		if(children == 1) {
			rate = 0.1598;
		} else if(children > 1) {
			rate = 0.2106;
		}
		return rate;
	}

	this._beginPhaseout = function() {
		var children = this.effectiveTaxRate.children;
		var amount = 6240;
		if(children == 1) {
			amount = 13730;
		} else if(children > 1) {
			amount = 13730;
		}
		if(this.effectiveTaxRate.householdType == married) {
			amount = amount + 1000;
		}
		return amount
	}

	this._maxEligibleIncome = function() {
		var children = this.effectiveTaxRate.children;
		var amount = 4990;
		if (children == 1) {
			amount = 7490;
		} else if (children > 1) {
			amount = 10510;
		}
		return amount;
	}

	this._eligibleIncome = function() {
		var income = this.effectiveTaxRate.income;
		var ei = income;
		if(income >= this.maxEligibleIncome) {
			ei = this.maxEligibleIncome;
		}
		return ei;
	}

	this._overage = function() {
		var income = this.effectiveTaxRate.income;
		var overage = 0;
		if(income >= this.beginPhaseout) {
			overage = income - this.beginPhaseout;
		}
		return overage
	}

	this._phaseout = function() {
		return this.overage*this.phaseoutRate;
	}

	this._credit = function() {
		var credit = this.creditRate*this.eligibleIncome;
		credit = credit - this.phaseout;
		if(credit < 0) {
			credit = 0;
		}
		return credit;
	}
	
	this.creditRate = this._creditRate();
	this.phaseoutRate = this._phaseoutRate();
	this.beginPhaseout = this._beginPhaseout();
	this.maxEligibleIncome = this._maxEligibleIncome();
	this.eligibleIncome = this._eligibleIncome();
	this.overage = this._overage();
	this.phaseout = this._phaseout();
	this.credit = this._credit();		
	
	this.description = function(dsn) {

		// Add a header for the earned income tax credit
		text = "Earned Income Tax Credit (EITC)";
		dsn.addBoldLine(text);
		
		// Add a line for eligbile income
		text = "ei = Eligible Income (";
		text = text + householdTypeString[this.effectiveTaxRate.householdType];
		text = text + ") = " + formatNumber(this.eligibleIncome,"$,##.##");
		dsn.addLine(text);
		
		// Handle EITC phaseout
		if(this.phaseout > 0) {
			newdsn = dsn.addSection();
			
			// Header for EITC phaseout
			text = "Compute EITC Phaseout"
			newdsn.addBoldLine(text);
			
			// EITC phaseout threshold
			text = "ep = EITC Phaseout Threshold (";
			text = text + householdTypeString[this.effectiveTaxRate.householdType];
			text = text + ") = " + formatNumber(this.beginPhaseout,"$,##.##");
			newdsn.addLine(text);
			
			// Over EITC phaseout threshold
			text = "eo = Over EITC Phaseout Threshold = i = ep = ";
			text = formatNumber(this.effectiveTaxRate.income,"$,##.##");
			text = text + " - " + formatNumber(this.beginPhaseout,"$,##.##");
			text = text + " = " + formatNumber(this.overage,"$,##.##");
			newdsn.addLine(text);

			// EITC Credit
			text = "ec = EITC Credit =" + formatNumber(this.creditRate,"%##.##");
			text = text + "*(ei - eo) = " + formatNumber(this.creditRate,"%##.##");
			text = text + "*(" + formatNumber(this.eligibleIncome,"$,##.##");
			text = text + " - " + formatNumber(this.overage,"$,##.##") + ")";
			text = text + " = " + formatNumber(this.credit,"$,##.##");
			dsn.addLine(text);
		} else {
			// EITC Credit
			text = "ec = EITC Credit =" + formatNumber(this.creditRate,"%##.##");
			text = text + "*ei = " + formatNumber(this.creditRate,"%##.##");
			text = text + "*" + formatNumber(this.eligibleIncome,"$,##.##");
			text = text + " = " + formatNumber(this.credit,"$,##.##");
			dsn.addLine(text);
		}
	}
}

function ChildTaxCredit(effectiveTaxRate) {

	this.phaseout_incr = 1000;
	this.phaseout_amount = 50;
	this.per_child_credit = 1000;
	this.additional_credit_threshold = 10500;
	this.additional_credit_rate = 0.1;

	this.effectiveTaxRate = effectiveTaxRate;
	
	this._phaseoutThreshold = function() {
		var threshold = 0;
		if(this.effectiveTaxRate.householdType == married) {
			threshold = 110000;
		} else if(this.effectiveTaxRate.householdType == headOfHousehold) {
			threshold = 75000;
		}
		return threshold;
	}
	
	this._maxCredit = function() {
		var children = this.effectiveTaxRate.children;
		var amount = this.per_child_credit*children;
		return amount;
	}

	this._overage = function() {
		var income = this.effectiveTaxRate.income;
		var overage = 0;
		if(this.maxCredit > 0 && income > this.phaseoutThreshold) {
			overage = income - this.phaseoutThreshold;
		}
		return overage;
	}

	this._phaseout = function() {
		var phaseout_step = Math.floor(this.overage/this.phaseout_incr);
		var phaseout = phaseout_step*this.phaseout_amount;
		return phaseout;
	}

	this._potentialCredit = function() { 
		var amount = this.maxCredit - this.phaseout;
		if(amount < 0) {
			amount = 0;
		}
		return amount;
	}

	this._baseCredit = function() {
		var credit = this.effectiveTaxRate.preCreditTax;
		if(this.effectiveTaxRate.preCreditTax >= this.potentialCredit) {
			credit = this.potentialCredit;
		}
		return credit;
	}

	this._universalAdditionalCredit = function() {
		var credit = 0;
		if(this.potentialCredit > this.baseCredit) {
			income = this.effectiveTaxRate.income;
			var overage = income - this.additional_credit_threshold;
			if(overage > 0) {
				credit = this.additional_credit_rate*overage;
			}
		}
		return credit;
	}
	
	this._threeOrMoreAdditionalCredit = function() {
		var credit = 0;
		if(this.universalAdditionalCredit < this.potentialCredit - this.baseCredit && this.effectiveTaxRate.children >= 3) {
			var payroll = this.effectiveTaxRate.payrollTax;
			var prt = payroll.taxEmployee;
			var eitc = this.effectiveTaxRate.eitc;
			var overage = prt - eitc.credit;
			if(overage > 0) credit = overage;
		}
		return credit;
	}
	
	this._additionalCredit = function() { 
		var credit = Math.max(this.universalAdditionalCredit,this.threeOrMoreAdditionalCredit);
		return credit;
	}
	
	this._credit = function() {
		var credit = this.baseCredit + this.additionalCredit;
		if(credit > this.potentialCredit) credit = this.potentialCredit;
		if(credit < 0) credit = 0;
		return credit;
	}
	
	this.phaseoutThreshold = this._phaseoutThreshold();
	this.maxCredit = this._maxCredit();
	this.overage = this._overage();
	this.phaseout = this._phaseout();
	this.potentialCredit = this._potentialCredit();
	this.baseCredit = this._baseCredit();
	this.universalAdditionalCredit = this._universalAdditionalCredit();
	this.threeOrMoreAdditionalCredit = this._threeOrMoreAdditionalCredit();
	this.additionalCredit = this._additionalCredit();
	this.credit = this._credit();
	
	
	this.description = function(dsn) {
		// Add section header
		text = "Child Tax Credit";
		dsn.addBoldLine(text);
		
		// Number of children
		text = "c = Number of Children = hs - ";
		var adults = 1;
		if(this.effectiveTaxRate.householdType == married) adults = 2;

		text = text + adults + " = " + this.effectiveTaxRate.householdSize;
		text = text + " - " + adults + " = " + this.effectiveTaxRate.children;
		dsn.addLine(text);
		
		// Handle phaseout
		if(this.phaseout > 0){
			var newdsn = dsn.addSection();
			//Header line
			text = "Compute Child Tax Credit Phaseout";
			newdsn.addBoldLine(text);
			
			// Max child credit
			text = "mc = Max Child Credit = ";
			text = text  + formatNumber(this.per_child_credit,"$,##.##") + "*c = ";
			text = text + formatNumber(this.per_child_credit,"$,##.##") + "*";
			text = text + this.effectiveTaxRate.children + " = ";
			text = text + this.maxCredit;
			newdsn.addLine(text);
			
			// Phaseout threshold
			text = "ct = Child Credit Phaseout (";
			text = text + householdTypeString[this.effectiveTaxRate.householdType];
			text = text + ") = " + formatNumber(this.phaseoutThreshold,"$,##.##");
			newdsn.addLine(text);
			
			// Overage
			text = "co = Child Credit Phaseout Overage = i - ct = ";
			text = text + formatNumber(this.effectiveTaxRate.income,"$,##.##");
			text = text + " - " + formatNumber(this.phaseoutThreshold,"$,##.##");
			text = text + " = " + formatNumber(this.overage,"$,##.##");
			newdsn.addLine(text);
			
			// Phaseout
			text = "cp = Child Credit Phaseout = floor(co/";
			text = text + formatNumber(this.phaseout_incr,"$,##.##") + ")*";
			text = text + formatNumber(this.phaseout_amount,"$,##.##") + " = ";
			text = text + "floor(" + formatNumber(this.overage,"$,##.##") + "/";
			text = text + formatNumber(this.phaseout_incr,"$,##.##") + ")*";
			text = text + formatNumber(this.phaseout_amount,"$,##.##") + " = ";			
			text = text + formatNumber(this.phaseout,"$##.##");
			newdsn.addLine(text);
			
			// Potential Credit
			text = "pc = Potential Child Credit = mc - cp = ";
			text = text + formatNumber(this.maxCredit,"$,##.##") + " - ";
			text = text + formatNumber(this.phaseout,"$,##.##") + " = ";
			text = text + formatNumber(this.potentialCredit,"$,##.##");
			dsn.addLine(text);			
		} else {
			// Potential Credit
			text = "pc = Potential Child Credit = "; 
			text = text + formatNumber(this.per_child_credit,"$,##.##") + "*c = ";
			text = text + formatNumber(this.per_child_credit,"$,##.##");
			text = text + "*" + this.effectiveTaxRate.children + " = ";
			text = text + formatNumber(this.potentialCredit,"$,##.##");
			dsn.addLine(text);
		}
		if(this.additionalCredit > 0) {
		
			text = "bc = Base Child Credit = min(pct,pc) = min(";
			text = text + formatNumber(this.effectiveTaxRate.preCreditTax,"$,##.##");
			text = text + "," + formatNumber(this.potentialCredit,"$,##.##");
			text = text + ") = " + formatNumber(this.baseCredit,"$,##.##");
			dsn.addLine(text);
		
			newdsn = dsn.addSection();
			// Header line
			text = "Compute Additional Child Credit";
			newdsn.addBoldLine(text);
			if(this.universalAdditionalCredit > this.threeOrMoreAdditionalCredit){
				
				// Addtional Credit Threshold
				text = "at = Additional Credit Threshold = ";
				text = text + formatNumber(this.additional_credit_threshold,"$,##.##");
				newdsn.addLine(text);
		
				// Potential Additional Credit
				text = "pa = Potential Additional Credit = ";
				text = text + formatNumber(this.additional_credit_rate,"%##.##");
				text = text + "*(i - at) = ";
				text = text + formatNumber(this.additional_credit_rate,"%##.##");
				text = text + "*(" + formatNumber(this.effectiveTaxRate.income,"$,##.##");
				text = text + " - " + formatNumber(this.additional_credit_threshold,"$,##.##");
				text = text + ") = " + formatNumber(this.universalAdditionalCredit,"$,##.##");
				newdsn.addLine(text);
			} else {
				text = "pa = Potential Additional Credit (3 or more children) = ep - ec = ";
				text = text + formatNumber(this.effectiveTaxRate.payrollTax.tax,"$,##.##");
				text = text + " - " + formatNumber(this.effectiveTaxRate.eitc.credit,"$,##.##");
				text = text + " = " + formatNumber(this.threeOrMoreAdditionalCredit,"$,##.##");
				newdsn.addLine(text);
			}
			text = "cc = Child Tax Credit = min(pc,bc + pa) = min(";
			text = text + formatNumber(this.potentialCredit,"$,##.##");
			text = text + "," + formatNumber(this.baseCredit,"$,##.##");
			text = text + " + " + formatNumber(this.additionalCredit,"$,##.##");			
			text = text + ") = " + formatNumber(this.credit,"$,##.##");
			dsn.addLine(text);	
		} else {
			text = "cc = Child Tax Credit = min(pct,pc) = min(";
			text = text + formatNumber(this.effectiveTaxRate.preCreditTax,"$,##.##");
			text = text + "," + formatNumber(this.potentialCredit,"$,##.##");
			text = text + ") = " + formatNumber(this.credit,"$,##.##");
			dsn.addLine(text);
		}
	}
}		

function TaxBracket(rate,minIncome,maxIncome,effectiveTaxRate) {
	this.rate = rate;
	this.minIncome = minIncome;
	this.maxIncome = maxIncome;
	this.effectiveTaxRate = effectiveTaxRate;
	
	this._taxableIncome = function() {
		var income = this.effectiveTaxRate.taxableIncome;
		var taxableIncome = 0;
		if(income > this.minIncome) {
			if(this.maxIncome == null || income <= this.maxIncome){
				taxableIncome = income - this.minIncome;
			} else {
				taxableIncome = this.maxIncome - this.minIncome;
			}
		}
		return taxableIncome;
	}
	
	this._tax = function() {
		return this.rate*this.taxableIncome;
	}
	
	this.taxableIncome = this._taxableIncome();
	this.tax = this._tax();
	
	this.description = function(dsn) {
		if(this.tax > 0){
			dsn.addText("pt");
			dsn.addSubscriptText(formatNumber(this.rate,"%##.##"));
			text = " = Amount of tax on income"; 
			if( this.maxIncome != null ) {
				text = text + " from " + formatNumber(this.minIncome,"$,##.##");
				text = text + " to " + formatNumber(this.maxIncome,"$,##.##");
			} else {
				text = text + " over " + formatNumber(this.minIncome,"$,##.##");
			} 
			dsn.addLine(text);
			dsn.addText("pt");
			dsn.addSubscriptText(formatNumber(this.rate,"%##.##"));
			text = " = ";
			if(this.maxIncome != null && this.effectiveTaxRate.taxableIncome > this.maxIncome){
				text = text + formatNumber(this.rate,"%##.##") + "*";
				text = text + formatNumber(this.maxIncome,"$,##.##") + " - ";
				text = text + formatNumber(this.minIncome,"$,##.##") + ") = "
				text = formatNumber(this.rate,"%##.##") + "*(";
				text = text + formatNumber(this.maxIncome-this.minIncome,"$,##.##"); 
				text = text + " = " + formatNumber(this.tax,"$,##.##");
			} else {
				text = text + formatNumber(this.rate,"%##.##") + "*(ti - ";
				text = text + formatNumber(this.minIncome,"$,##.##") + ") = "
				text = text + formatNumber(this.rate,"%##.##") + "*(";
				text = text + formatNumber(this.effectiveTaxRate.taxableIncome,"$,##.##");
				text = text + " - " + formatNumber(this.minIncome,"$,##.##") + ") = "
				text = text + formatNumber(this.rate,"%##.##") + "*";
				text = text + formatNumber(this.effectiveTaxRate.taxableIncome-this.minIncome,"$,##.##"); 
				text = text + " = " + formatNumber(this.tax,"$,##.##");				
			}
			dsn.addLine(text);
		}
	}
	
}

function Exemption(effectiveTaxRate) {
	this.phaseout_rate = 0.02;
	this.phaseout_incr = 2500;
	this.exemptionAmount = 3050;
	this.effectiveTaxRate = effectiveTaxRate;
	
	this.phaseoutThreshold = function() {
		var hht = effectiveTaxRate.householdType;
		var phaseout = 0;
		if(hht == single) phaseout = 139500;
		if(hht == married) phaseout = 209250;
		if(hht == headOfHousehold) phaseout = 174400;
		return phaseout;
	}
	
	this.overage = function() {
		var income = this.effectiveTaxRate.income;
		var overage = 0;
		if(income > this.phaseoutThreshold()) overage = income - this.phaseoutThreshold();
		return overage;
	}
	
	this.phaseout = function() {
		var phaseout = 0;
		if(this.overage() > 0 ) {
			var phaseout_steps = Math.floor(this.overage()/this.phaseout_incr);		
			phaseout = phaseout_steps*this.phaseout_rate;
		}
		if(phaseout < 0) phaseout = 0;
		return phaseout;
	}
	
	this.amount = function() {
		var amount = this.effectiveTaxRate.householdSize*this.exemptionAmount;
		amount = (1-this.phaseout())*amount;
		if(amount < 0) amount = 0;
		return amount;
	}
	
	this.description = function(dsn) {
		// If we have no phaseout.
	 	if(this.phaseout() ==  0) {
	 		text = "ex = exemption = " + formatNumber(this.exemptionAmount,"$,##.##");
	 		text = text + "*hs = ";
	 		text = text +  formatNumber(this.exemptionAmount,"$,##.##") + "*";
	 		text = text + this.effectiveTaxRate.householdSize + " = ";
	 		text = text + formatNumber(this.amount(),"$,##.##");
	 		dsn.addLine(text);
	 	} else {
	 		dsn = dsn.addSection();
	 		
	 		// Add header line
	 		text = "Compute Exemption Phaseout";
	 		dsn.addBoldLine(text);
	 		
	 		// Add line for exemption phaseout threshold
	 		text = "et = Exemption Phaseout Threshold("; 
	 		text = text + householdTypeString[this.effectiveTaxRate.householdType];
	 		text = text + ") = " + formatNumber(this.phaseoutThreshold(),"$,##.##");
	 		dsn.addLine(text);
	 		
	 		// Add a line for Over phaseout threshold
	 		text = "ov = Over Phaseout Threshold = i - et = ";
	 		text = text + formatNumber(this.effectiveTaxRate.income,"$,##.##");
	 		text = text + " - ";
	 		text = text + formatNumber(this.phaseoutThreshold(),"$,##.##") + " = ";
	 		text = text + formatNumber(this.overage(),"$,##.##");
	 		dsn.addLine(text);
	 		
	 		// Add a line for the exemption phaseout
	 		text = "ep = Exemption Phaseout Percentage = ";
	 		text = text + formatNumber(this.phaseout_rate,"%##.##") + "*floor(ov/";
	 		text = text + formatNumber(this.phaseout_incr,"$,##.##") + ") = ";
	 		text = text + formatNumber(this.phaseout_rate,"%##.##") + "*floor(";
	 		text = text + formatNumber(this.overage(),"$,##.##") + "/";
	 		text = text + formatNumber(this.phaseout_incr,"$,##.##") + ") = ";
	 		text = text + formatNumber(this.phaseout(),"%##.##");
	 		dsn.addLine(text);
	 		
	 		// Add a line for the exemption
	 		text = "ex = Exemption = (100%-ep)*";
	 		text = text + formatNumber(this.exemptionAmount,"$,##.##");
	 		text = text + "*hs = (100 -" + formatNumber(this.phaseout(),"%##.##");
	 		text = text + ")*" + formatNumber(this.exemptionAmount,"$,##.##") + "*";
	 		text = text + this.effectiveTaxRate.householdSize + " = ";
	 		text = text + formatNumber(this.amount(),"$,##.##");
	 		dsn.addLine(text);
	 	}
	} 	
}

function EffectiveTaxRate(income,householdSize,householdType,disableRefundableCredits) {
	this.income = income;
	this.householdSize = householdSize;
	this.householdType = householdType;	
	this.disableRefundableCredits = disableRefundableCredits;
	
	if(this.householdType == single && this.householdSize >1) {
		this.householdType = headOfHousehold;
	} else if (this.householdType == headOfHousehold && this.householdSize == 1) {
		this.householdType = single;
	}

	this._children = function() {
		var children = 0;
		if(this.householdType == married) {
			children = this.householdSize - 2;
		} else if (this.householdType == headOfHousehold) {
			children = this.householdSize - 1;
		}
		if(children < 0) children = 0;
		return children;
	}	
	this.children = this._children();	
	
	this.exemption = new Exemption(this);
	this.payrollTax = new PayrollTax(this.income);

	this._standardDeduction = function() {
		var sd = 0; // Standard deduction
		if(this.householdType == single) sd = 4750;
		if(this.householdType == married) sd = 9000;
		if(this.householdType == headOfHousehold) sd = 7000;
		return sd;
	}
	this.standardDeduction = this._standardDeduction();
	
	this._taxableIncome = function() {
		var taxableIncome = this.income - this.standardDeduction;
		taxableIncome = taxableIncome - this.exemption.amount();
		if(taxableIncome < 0) taxableIncome = 0;
		return taxableIncome;
	}
	this.taxableIncome = this._taxableIncome();
		
	this._taxBrackets = function() {
		var taxbrackets = new Array(6);
		if(this.householdType == single) {
			taxbrackets[0] = new TaxBracket(0.1,0,7000,this);
			taxbrackets[1] = new TaxBracket(0.15,7000,28400,this);
			taxbrackets[2] = new TaxBracket(0.25,28400,68800,this);
			taxbrackets[3] = new TaxBracket(0.28,68800,143500,this);
			taxbrackets[4] = new TaxBracket(0.33,143500,311950,this);
			taxbrackets[5] = new TaxBracket(0.35,311950,null,this);
		} else if (this.householdType == married) {
			taxbrackets[0] = new TaxBracket(0.1,0,14000,this);
			taxbrackets[1] = new TaxBracket(0.15,14000,56800,this);
			taxbrackets[2] = new TaxBracket(0.25,56800,114650,this);
			taxbrackets[3] = new TaxBracket(0.28,114650,174700,this);
			taxbrackets[4] = new TaxBracket(0.33,174700,311950,this);
			taxbrackets[5] = new TaxBracket(0.35,311950,null,this);
		} else if(this.householdType == headOfHousehold) {
			taxbrackets[0] = new TaxBracket(0.1,0,10000,this);
			taxbrackets[1] = new TaxBracket(0.15,10000,38050,this);
			taxbrackets[2] = new TaxBracket(0.25,38050,98250,this);
			taxbrackets[3] = new TaxBracket(0.28,98250,159100,this);
			taxbrackets[4] = new TaxBracket(0.33,159100,311950,this);
			taxbrackets[5] = new TaxBracket(0.35,311950,null,this);
		}
		return taxbrackets;
	}	
	
	this._preCreditTax = function() {
		var tax = 0;
		var taxbrackets = this.taxBrackets
		for(var i = 0;i< taxbrackets.length;i++) {
			tax = tax + taxbrackets[i].tax;	
		}
		return tax;
	}
	
	this.taxBrackets = this._taxBrackets();	
	this.standardDeduction = this._standardDeduction();
	
	this.preCreditTax = this._preCreditTax();
	
	this.eitc = new EarnedIncomeTaxCredit(this);
	this.ctc = new ChildTaxCredit(this);
	
	this._incomeTax = function() {
		var tax = this.preCreditTax;
		var ec = this.eitc.credit;
		tax = tax - ec;
		var cc = this.ctc.credit;
		tax = tax - cc;
		if(this.disableRefundableCredits && tax < 0) tax = 0;		
		return tax;
	}
	
	this.incomeTax = this._incomeTax();
	
	this._tax = function() {
		var tax = this.incomeTax;
		var pt = this.payrollTax.tax;
		tax = tax + pt;
		return tax;
	}
	
	this.tax = this._tax();
	
	this._rate = function() {
		return this.tax/this.income;
	}
	
	this._buyingPower = function() {
		return (this.income - this.tax)/this.income;
	}
	
	
	this.rate = this._rate();
	this.buyingPower = this._buyingPower();
	
	

	this.taxableIncomeDescription = function(dsn) {
		// Add a header line for the Taxable Income Section
	 	text = "Taxable Income:"
	 	dsn.addBoldLine(text);
	 	
	 	// Add a line for the standard deduction
	 	text = "sd = Standard Deduction (" + householdTypeString[this.householdType];
	 	text = text + ") = " + formatNumber(this.standardDeduction,"$,##.##");
	 	dsn.addLine(text);
	 	
	 	// And now the personal exemptions
	 	this.exemption.description(dsn);
	 	
	 	// And now for the taxable income
	 	text = "ti = Taxable Income = i - sd - ex = ";
	 	text = text + formatNumber(this.income,"$,##.##") + " - ";
	 	text = text + formatNumber(this.standardDeduction,"$,##.##") + " - ";
	 	text = text + formatNumber(this.exemption.amount(),"$,##.##") + " = ";
	 	text = text + formatNumber(this.taxableIncome,"$,##.##");
	 	dsn.addLine(text);
	}
	
	this.preCreditTaxDescription = function(dsn) {
		
		// Add a header line for the precredit tax
		text = "PreCredit Income Tax";
		dsn.addBoldLine(text);
		
		var taxbrackets = this.taxBrackets;
		for(var i = 0; i < taxbrackets.length;i++) {
			taxbrackets[i].description(dsn);
		}
		
		dsn.addText("pct = PreCredit Tax = ");
		var ti = this.taxableIncome;		
		for(var i = 0; i < taxbrackets.length;i++) {
			if(taxbrackets[i].maxIncome != null && ti > taxbrackets[i].minIncome){
				if( i > 0 ) dsn.addText(" + ");
				dsn.addText("pt");
				dsn.addSubscriptText(formatNumber(taxbrackets[i].rate,"%##.##"));
			} else {
				break;
			}
		}
		if(i == 0) {
			dsn.addText(formatNumber(0,"$,##.##"));
			return;
		}
		
		dsn.addLine("");			
		dsn.addText("pct = ");
		for(var i = 0; i < taxbrackets.length;i++) {
			if(taxbrackets[i].maxIncome != null && ti > taxbrackets[i].minIncome){
				if( i > 0 ) dsn.addText(" + ");
				dsn.addText(formatNumber(taxbrackets[i].tax,"$,##.##"));
			} else {
				break;
			}
		}
		if(i > 1) {
			dsn.addText(" = " + formatNumber(this.preCreditTax,"$,##.##"));
		}
		dsn.addLine("");
	}	
	
	this.basicDataDescription = function(dsn) {			
	  text = "Basic Data (Filing Status: " + householdTypeString[this.householdType] + ")";
		dsn.addBoldLine(text);
		
		// Add a line for income
		text = "i = Income = " + formatNumber(this.income,"$,##.##");
		dsn.addLine(text);
		
		// Add a line for household size
		text = "hs = Household Size = " + this.householdSize;
		dsn.addLine(text);	  
	}
	
	this.incomeTaxDescription = function(dn) {
		// Taxable Income
	 	dsn = dn.addSection();	 	
	 	this.taxableIncomeDescription(dsn);
	 
	 	// PreCreditTax
	 	dsn = dn.addSection();	 	
	 	this.preCreditTaxDescription(dsn);
	
		if(this.eitc.credit > 0) {
		 	// EITC
		 	dsn = dn.addSection();		 	
		 	this.eitc.description(dsn);
		}
		
		if(this.ctc.credit > 0) {
			// Child Tax Credit
			dsn = dn.addSection();
			this.ctc.description(dsn);
		}
		
		dsn = dn.addSection();
		var flag = (this.disableRefundableCredits && this.incomeTax <= 0);
		var text = "Income Tax";
		if(flag) {
			text = text + " (Refundable Credits Disabled)";
		} 
		dsn.addBoldLine(text);
		dsn.addText("it =  Income Tax");
		dsn.addText(" = ");
		if(flag) dsn.addText("max(");
		dsn.addText("pct");
	 	if(this.eitc.credit > 0) dsn.addText(" - ec");
	 	if(this.ctc.credit > 0) dsn.addText(" - cc");
	 	if(flag) dsn.addText(",$0)");
		dsn.addLine("");
	 	dsn.addText("it = ");
	 	if(flag) dsn.addText("max(");
	 	dsn.addNode(formatNode(this.preCreditTax,"$,##.##"));
	 	if(this.eitc.credit > 0) {
		 	dsn.addText(" - ");
		 	dsn.addNode(formatNode(this.eitc.credit,"$,##.##"));
		}
		if(this.ctc.credit > 0) {
		 	dsn.addText(" - ");
		 	dsn.addNode(formatNode(this.ctc.credit,"$,##.##"));
		}
		if(flag) {
			dsn.addText(",$0) = max(");
			dsn.addNode(formatNode(this.preCreditTax - this.eitc.credit - this.ctc.credit,"$,##.##"));
			dsn.addText(",$0)");
		} 
		dsn.addText(" = ");
		dsn.addNode(formatNode(this.incomeTax,"$,##.##"));
	 	dsn.addLine("");
	}
	
	this.taxDescription = function(dn) {
		// Add a header line for the Basic Data section
	  var dsn = dn.addSection();	
	  this.basicDataDescription(dsn);
	  
		// Describe the payroll taxes.
		var dsn = dn.addSection();	
	  this.payrollTax.description(dsn);
	  
	 	// Describe the Income Taxes
	 	this.incomeTaxDescription(dn);
	 	
	 	// Total Taxes
	 	dsn = dn.addSection();
	 	dsn.addBoldLine("Total Taxes");
	 	
	 	// Total Tax
	 	dsn.addText("t = Tax = it + pt");
	 	dsn.addText(" = ");
	 	dsn.addNode(formatNode(this.incomeTax,"$,##.##"));
	 	dsn.addText(" + ");
	 	dsn.addNode(formatNode(this.payrollTax.tax,"$,##.##"));
		dsn.addText(" = ");
		dsn.addNode(formatNode(this.tax,"$,##.##"));
	 	dsn.addLine("");
	 	return dsn;
	}
	
	this.rateDescription = function() {
		
		var dn = new DescriptionNode();		
		
	  var dsn = this.taxDescription(dn);
	 	
	 	// Rate
	 	dsn.addText("r = Tax Rate = t/i = ");
	 	dsn.addNode(formatNode(this.tax,"$,##.##"));
	 	dsn.addText("/");
	 	dsn.addNode(formatNode(this.income,"$,##.##"));
	 	dsn.addText(" = ");
	 	dsn.addNode(formatNode(this.rate,"%##.##"));
	 	dsn.addLine("");
	 	 	
	  return dn.getNode();
	}
	
	this.buyingPowerDescription = function() {
		var dn = new DescriptionNode();		
		
	  var dsn = this.taxDescription(dn);
	 	
	 	// Buying power
	 	dsn.addText("b = Buying Power = (i-t)/i = (");
	 	dsn.addNode(formatNode(this.income,"$,##.##"));
	 	dsn.addText(" - ");
	 	if(this.tax < 0) dsn.addText("(");
	 	dsn.addNode(formatNode(this.tax,"$,##.##"));
	 	if(this.tax < 0) dsn.addText(")");
	 	dsn.addText(")/");
		dsn.addNode(formatNode(this.income,"$,##.##"));
		dsn.addText(" = ");
		dsn.addNode(formatNode(this.buyingPower,"%##.##"));
		return dn.getNode();
	}
}

