// Enhancement: Add rental income
// Enhancement: Add homeowners/condo fees
// Enhancement: Add additional utilities for buying
// Enhancement: Add discount points & deductibility for year 1
// Enhancement: Add renter's insurance

// See notes in separate file.

//----------------------------------------
// Undo the CSS max-width for this page
//----------------------------------------
document.body.style.maxWidth="none";

//----------------------------------------
// Set variables & run on load
//----------------------------------------
window.lastDP = 4; // Set this so we can reset it if user cancels a request to set a custom DP
window.lastIntRate = 3; // Ditto
frm=document.getElementById('RentVsBuyCalculator'); // Used in an onchange, so must run before the main function

calculate();


//----------------------------------------
// Set column display width
//----------------------------------------
if (self.innerHeight) {x = self.innerWidth;} // Everything but IE
else { x = document.body.clientWidth;} // Explorer

col1=document.getElementById('Col1').style;
col2=document.getElementById('Col2').style;
col3=document.getElementById('Col3').style;
if (x <1000) { // tiny screens, sized for 800 pixels wide; Adsense and the Mega Table still cause horizontal scrolling, but at least the intro text is readable
	col1.width=165
	col2.width=225
	col3.width=200
}
else if (x>1024) { // Big screens
	col2.width=325;
	col3.width=275;
}
else { // 1024x768, sized for 1000 pixels wide
	col1.width=320;
	col2.width=275;
	col2.width=225;
}


//----------------------------------------
// Debugger
//----------------------------------------
function debug(theVal) {
	document.getElementById('debug').innerHTML=theVal;
}


//----------------------------------------
// Calculate!
//----------------------------------------
function calculate() {

// Get the house input
	price = fix(frm.Price.value)-0;

	downPaymentRate = frm.DownPayment.options[frm.DownPayment.selectedIndex].value-0;
	if (downPaymentRate<=100) downPayment = price*downPaymentRate;
	else { downPayment = downPaymentRate; downPaymentRate = downPayment/price; } // Custom DP
	document.getElementById('downPaymentText').innerHTML=addCommas(downPayment);

	term = frm.Term.options[frm.Term.selectedIndex].value-0;
	usePMI = frm.PMI.checked;
	rate = (frm.Rate.options[frm.Rate.selectedIndex].value-0)/12;
	rolled = frm.Rolled.checked;
	initialMaintenance = fix(frm.InitialMaintenance.value)-0;
	maintenanceInflation = (frm.MaintenanceInflation.options[frm.MaintenanceInflation.selectedIndex].value-0)+1;
	appRate = (frm.AppRate.options[frm.AppRate.selectedIndex].value-0)+1;
	saleCommissionRate = frm.SaleCommissionRate.options[frm.SaleCommissionRate.selectedIndex].value-0;

	deduction = frm.Deduction.checked;
	deductibleExclusion=fix(frm.DeductibleExclusion.value)-0;
	taxBracket = frm.TaxBracket.options[frm.TaxBracket.selectedIndex].value-0;
	if (frm.TaxCredit.checked) taxCredit = price*0.10;
	else taxCredit=0;
	if (taxCredit >8000) taxCredit=8000;
	if (frm.HomeCapitalGains.checked) homeSaleExclusion = 250000; else homeSaleExclusion=0;

	if (!frm.ClosingCostsLock.checked) frm.ClosingCosts.value = Math.round(price*0.03);
	closingCosts = fix(frm.ClosingCosts.value)-0;

	if (!frm.MaintenanceLock.checked) frm.Maintenance.value = Math.round(price*0.01);
	maintenance = fix(frm.Maintenance.value)-0;

	if (!frm.TaxesInsuranceLock.checked) frm.TaxesInsurance.value = Math.round(price*0.02);
	taxesInsurance = fix(frm.TaxesInsurance.value)-0;
	
// Get the rental input
	rent = fix(frm.Rent.value)-0;
	rentInflation = frm.RentInflation.options[frm.RentInflation.selectedIndex].value-0;
	RoR = (frm.ROR.options[frm.ROR.selectedIndex].value-0)+1;
	cgbracket = frm.CGbracket.options[frm.CGbracket.selectedIndex].value-0;

// Figure monthly mortgage payment (excludes PMI for now to keep it simple; PMI added later)
	loan = price-downPayment;
	if (rolled) loan+=closingCosts;
	months = term*12;
	pmt = (rate*loan) / (1- Math.pow(1+rate,-months) );

// Figure PMI and write the monthly payment amount
//   figures taken from http://www.bartaustin.com/lasvegas/pmi-calculation.html
	if (usePMI && downPaymentRate <0.20) {
		loanPercentage = 1-downPaymentRate;
		if (term <=15) {
			if (loanPercentage > 0.95) { PMIfactor=0.0079;}
			else if (loanPercentage > 0.90) { PMIfactor = 0.0026;}
			else if (loanPercentage > 0.85) { PMIfactor = 0.0023;}
			else if (loanPercentage <= 0.85) { PMIfactor= 0.0019;}
		}
		else if (term >15) {
			if (loanPercentage > 0.95) { PMIfactor=0.0090;}
			else if (loanPercentage > 0.90) { PMIfactor = 0.0078;}
			else if (loanPercentage > 0.85) { PMIfactor = 0.0052;}
			else if (loanPercentage <= 0.85) { PMIfactor= 0.0032;}
		}
		pmi = ((price-downPayment)*PMIfactor)/12;
	}
	document.getElementById('PMT').innerHTML = addCommas(pmt+pmi+taxesInsurance/12);
	pmi*=12; // convert back to annual amount


// Set initial variables

	balance=loan; // downPayment already subtracted
	paidEquity = downPayment;
	if (rolled) paidEquityRate = (1-closingCosts/loan);  // Account for the portion that repays the closing costs isn't building equity
	else paidEquityRate = 1;

	interest=0, cashSpent=0, houseValue=price, houseValueNet=0, periodRent=rent*12, paidRent=0, investment=0, investmentPrincipal=0, firstYearOfProfit=0, noProfitInSummary=0;
	resultsYear = frm.ShowYear.options[frm.ShowYear.selectedIndex].value-0;

	str = "<table cellpadding=3 cellspacing=1 border=0 bgcolor=silver style='font:10px Arial' class=results><tr bgcolor=#eeeeee><td></td><td colspan=2 class=borderline><b>Loan details</b></td><td colspan=7 class=borderline><b>Buying (cash out)</b></td><td class=borderline colspan=3><b>House value</b></td><td class=borderline colspan=3><b>Renting</b></td><td colspan=3><b>Rent vs. Buy</b></td></tr>        <tr bgcolor=#eeeeee><td>Year</td><td>Interest</td><td class=borderline>Loan<br>Balance</td><td>Pmts.</td><td>PMI</td><td>Taxes<br>+Ins.</td><td>Maint.</td><td>Tax<br>Savings</td><td>Cash<br>out</td><td class=borderline>Total<br>Cash out</td><td>Paid<br>Equity</td><td>Apprec-<br>iation</td><td class=borderline>Total<br>Value</td><td>Rent</td><td>Total<br>Rent</td><td class=borderline>Return on<br>Invest.</td><td>Buying<br>Net</td><td>Rent net</td><td>Rent<br>vs.<br>Buy</td></tr>\n";


// ===========================================================
// Spin the wheel!

	for (termCounter=1; termCounter<=40; termCounter++) {

	// Period-specific
		yearlyInterest=0;
		for (counter=1; counter<=12; counter++) {
			monthlyInterest = balance*rate;
			yearlyInterest+= monthlyInterest;
			balance-= (pmt-monthlyInterest);
		}
		interest+= yearlyInterest;

		if (deduction && yearlyInterest>deductibleExclusion) taxSavings=(yearlyInterest+pmi-deductibleExclusion)*taxBracket;
		else {taxSavings='';}
		if (termCounter==1 && taxCredit) {taxSavings+=taxCredit;}

		cashSpentPeriod = (pmt*12+pmi+maintenance+taxesInsurance-taxSavings);
		if (termCounter==1) {
			cashSpentPeriod+= initialMaintenance+downPayment;
			if (!rolled) cashSpentPeriod+= closingCosts;
		}

	// Running balances
		cashSpent+=cashSpentPeriod;
		paidEquity+= (pmt*12-yearlyInterest) * paidEquityRate; // Account for the portion that repays the closing costs isn't building equity
		houseValue	*= appRate;

	// Rent and investment
		paidRent += periodRent;
		extraCashSpent = (cashSpentPeriod-periodRent);
		if (extraCashSpent>0) {investmentPrincipal+= extraCashSpent; investment+= extraCashSpent;}
		if (investment>0) investment *= RoR;
		else if (investment<0) investment="0"; // Could be negative if savings from rent never overcome DP and/or closing costs paid in cash
		netInvestment = (investment-investmentPrincipal) * (1-cgbracket);

	// Prep the Results
		if (termCounter==1) payments=pmt*12+downPayment; else payments=pmt*12;
		if (taxSavings>0) taxSavings = "("+addCommas(taxSavings)+")";
		if (cashSpentPeriod < periodRent) highlight=" style='background:#C0FFC0'"; else highlight="";
		paidEquityNet = paidEquity * (1-saleCommissionRate);
		appreciationNet = (houseValue-price) * (1-saleCommissionRate);
		houseValueNet = houseValue * (1-saleCommissionRate);
		
		if (homeSaleExclusion >0 && appreciationNet > homeSaleExclusion) {
			taxOnSale = (houseValueNet-price) * cgbracket;
			paidEquityNet -= taxOnSale * (paidEquityNet/(paidEquity+houseValue-price));
			appreciationNet -= taxOnSale * (appreciationNet/(paidEquity+houseValue-price));
			houseValueNet -= taxOnSale;
		}

		houseSide = houseValueNet - balance - cashSpent;
		rentSide  = netInvestment - paidRent;
		rentVsBuy = houseSide - rentSide;

		if (rentVsBuy<0) {
			rentVsBuy="("+addCommas(-rentVsBuy)+")";
			//firstYearOfProfit=0; // In case we had been profitable, but then became unprofitable.
			rowColor = 'FFF3F3';
		}
		else {
			rentVsBuy = addCommas(rentVsBuy);
			if (!firstYearOfProfit) firstYearOfProfit = termCounter;
			rowColor = 'E5FFE1';
		}

		// Build the big results table
		str+= "<tr style=background:#"+rowColor+"><td><b>"+termCounter+"</b></td><td>"+addCommas(yearlyInterest)+"</td><td class=borderline>"+addCommas(balance)+"</td><td>"+addCommas(payments)+"</td><td>"+addCommas(pmi)+"</td><td>"+addCommas(taxesInsurance)+"</td><td>"+addCommas(maintenance)+"</td><td>"+taxSavings+"</td><td"+highlight+">"+addCommas(cashSpentPeriod)+"</td><td class=borderline>"+addCommas(cashSpent)+"</td><td>"+addCommas(paidEquityNet)+"</td><td>"+addCommas(appreciationNet)+"</td><td class=borderline>"+addCommas(houseValueNet)+"</td><td"+highlight+">"+addCommas(periodRent)+"</td><td>"+addCommas(paidRent)+"</td><td class=borderline>"+addCommas(netInvestment)+"</td><td>"+addCommas(houseSide)+"</td><td>"+addCommas(rentSide)+"</td><td>"+rentVsBuy+"</td></tr>\n";

		// Increment period amounts for next iteration
		if (balance<pmt*12/2) {balance=0; pmt=0;}
		if (paidEquity/price >= 0.22) {pmi=0;}
		maintenance *= maintenanceInflation;
		deductibleExclusion *= maintenanceInflation;
		homeSaleExclusion *= maintenanceInflation;
		taxesInsurance *= appRate;
		periodRent *= (1+rentInflation); // inflate for next year


		// Show the results summary if selected year

		if (termCounter==resultsYear) {
			houseTotal = cashSpent-paidEquityNet-appreciationNet;
			houseTotalDisplay = addCommas(houseTotal);
			rentTotal  = paidRent-netInvestment;
			rentTotalDisplay = addCommas(rentTotal);
			if (firstYearOfProfit && rentTotal < houseTotal) switchback=1; else switchback=0;

			if (firstYearOfProfit) {
				summary="<b>Buying becomes profitable in year <span style='color:maroon'>"+firstYearOfProfit+"</span>.</b> ";

				if (cashSpent>paidRent && houseTotal<rentTotal) { summary+="<p>You will spend more money to buy the house than you'll pay in rent, but you'll have the value of the house.";}
				
				if (switchback) summary+= "But oddly enough, renting becomes a better deal in later years.";
			}
			else {
				summary="<b>Buying does not become better than renting during the first "+termCounter+" years.</b> ";
				noProfitInSummary=1;
			}

			investmentNote = "<p>If you rent and religiously invest the difference between what you would have paid for a house and what you're paying in rent, you can earn a return of "+addCommas(netInvestment)+" (after taxes). ";
			if (firstYearOfProfit && !switchback) investmentNote+="However, that's not enough to make renting a better deal.";
			else investmentNote+="This helps make renting a better deal. ";

			if (houseTotal>0 && rentTotal>0) {
				if (houseTotal<rentTotal) summary+= "<p>The bottom line is that you'd spend a net of only "+houseTotalDisplay+" to buy the house, vs. "+rentTotalDisplay+" to rent.";
				else summary+= "<p>The bottom line is that you'd spend "+houseTotalDisplay+" to buy the house, but only "+rentTotalDisplay+" to rent.";
			}
			else if (houseTotal<0 && rentTotal<0) {
				summary += "<p>Since the Net Spent figures on the bottom line are negative, that means that whether buying or renting, your costs are so low in this case that you basically live for 'free'.  That's because the return on your investment is greater than the cash you paid out of pocket.";
			}
			else if (houseTotal>0 && rentTotal<0) {
				summary += "<p>Not only is renting a better deal than buying in this case, but by renting you'd basically live for free, since the return on your investment is more than you'd spend in rent.";
			}

			if (noProfitInSummary && firstYearOfProfit) {
				summary+= "However, buying does become profitable after "+firstYearOfProfit+" years.";
				investmentNote+= "However, buying becomes profitable after "+firstYearOfProfit+" years.";
			}

			summary += investmentNote;
			document.getElementById('resultsDiscussion').innerHTML= summary;

			document.getElementById('CashSpentHouse').innerHTML = addCommas(cashSpent);
			document.getElementById('PaidEquity').innerHTML = addCommas(paidEquityNet);
			document.getElementById('Appreciation').innerHTML = addCommas(appreciationNet);
			document.getElementById('HouseTotal1').innerHTML = houseTotalDisplay;

			document.getElementById('CashSpentRent').innerHTML = addCommas(paidRent);
			document.getElementById('RentTotal1').innerHTML = addCommas(paidRent);

			document.getElementById('ROI').innerHTML = addCommas(netInvestment);
			document.getElementById('HouseTotal2').innerHTML = houseTotalDisplay;

			document.getElementById('RentTotal2').innerHTML = rentTotalDisplay;
		}

	} // Stop the iterations

	str +="</table>";
	document.getElementById('foo').innerHTML = str;
}

//----------------------------------------
// Utility subroutines
//----------------------------------------
function fix(stringToFix) {
	return stringToFix.replace(/[^0-9.]/g,"")-0;
}

function setYear(yearToSet) {
	fld = frm.ShowYear;

	yearToSet = frm.Term.options[frm.Term.selectedIndex].value;
	for (counter=0; counter<fld.options.length; counter++) {
		if (fld.options[counter].value==yearToSet) {
			fld.selectedIndex=counter;
			break;
		}
	}
}

function addCommas(originalValue) {
	if (!originalValue) { return '';}
	theString = Math.round(originalValue);
	theString +=''; // convert to string
	pattern = /(\d+)(\d{3})/;
	while (pattern.test(theString)) {
		theString = theString.replace(pattern, '$1,$2');
	}
	if (originalValue>0) return "$"+theString;
	else return "-$" + theString.substring(1,theString.length); // all chars except the 1st
}

function chooseCustom(message,theDefault,format,field,previousValue) {
	answer=fix(prompt(message,theDefault));
	theField = document.getElementById(field);
	length = theField.options.length;

	if (answer) {
		if (format=='$') {
			if (field=="DownPayment") {
				price = fix(frm.Price.value);
				if (answer<=100) {alert("Down payment must be more than $100.  Setting down payment to $101."); answer=101;}
				if (answer > price) alert("Down payment can't exceed the price of the home. Setting down payment to 100%.");
				if (answer/price <0.2) frm.PMI.checked=1;
			}
			theField.options[length] = new Option(addCommas(answer),answer);
		}
		else if (format=="%") {
			percent = Math.round(answer*100) /100;
			if (field=='Rate' && percent<0.1) {alert("Minimum interest rate is 0.1%. Setting the rate to 0.1% now."); percent=0.1;}
			theField.options[length] = new Option(percent+"%",percent/100);
		}
		theField.selectedIndex=length;
	}
	else { theField.selectedIndex = previousValue;}
}

function Taxy(deductionOn) {
	taxis = getElementsByClass('taxy'); // an array
	if (deductionOn) theColor='black'; else theColor='silver';
	for (counter=0; counter<taxis.length; counter++) {
		taxis[counter].style.color=theColor;
		frm.DeductibleExclusion.disabled=!deductionOn;
		frm.TaxBracket.disabled=!deductionOn;		
	}
}

function getElementsByClass( searchClass, domNode, tagName) {
	if (domNode == null) domNode = document;
	if (tagName == null) tagName = '*';
	var el = new Array();
	var tags = domNode.getElementsByTagName(tagName);
	var tcl = " "+searchClass+" ";
	for(i=0,j=0; i<tags.length; i++) {
		var test = " " + tags[i].className + " ";
		if (test.indexOf(tcl) != -1)
			el[j++] = tags[i];
	}
	return el;
}