// Enhancement: Add rental income
// Enhancement: Add discount points & deductibility for year 1

// 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
window.lastAppRate = 9;
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) {
	show('debuggo', (document.getElementById('debuggo').innerHTML+'; '+theVal) );
}


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

// Clear the debugger
	show('debuggo','');

// Get the LOAN input
	price = fix(frm.Price.value)-0;
	downPaymentRate = frm.DownPayment.options[frm.DownPayment.selectedIndex].value-0;
	if (downPaymentRate<=1) downPayment = price*downPaymentRate;
	else { downPayment = downPaymentRate; downPaymentRate = downPayment/price; } // Custom DP
	show('downPaymentText', 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;

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

// Get the EXPENSES input

	initialMaintenance = fix(frm.InitialMaintenance.value)-0;
	if (!frm.MaintenanceLock.checked) frm.Maintenance.value = Math.round(price*0.01);
	maintenance = fix(frm.Maintenance.value)-0;
	extraExpenses = fix(frm.ExtraExpenses.value)*12; // Convert to yearly
	expensesInflation = (frm.ExpensesInflation.options[frm.ExpensesInflation.selectedIndex].value-0)+1;

	if (!frm.PropertyTaxesLock.checked) frm.PropertyTaxes.value = Math.round(price*0.0138);
	propertyTaxes = fix(frm.PropertyTaxes.value)-0;

	if (!frm.InsuranceLock.checked) frm.Insurance.value = Math.round(price*0.005);
	insurance = fix(frm.Insurance.value)-0;

// Get the HOUSE VALUE input

	appRate = (frm.AppRate.options[frm.AppRate.selectedIndex].value-0)+1;

	saleCommissionRate = frm.SaleCommissionRate.options[frm.SaleCommissionRate.selectedIndex].value-0;


// Get the FEDERAL TAXES input

	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;



// 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;

	PriceRentRatio = price/(rent*12);
	show('PRratio', PriceRentRatio.toFixed(1) );

// 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;
	}
	else pmi=''; // Must explicitly set to nothing or zero, else 100% DP causes an undefined error.
debug(pmt+' '+pmi+' '+propertyTaxes+' '+insurance);
	show('PMT', addCommas(pmt-0+pmi-0+propertyTaxes/12+insurance/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;

	MDT = "<table align=center 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>";

	MDT += "<tr bgcolor=#eeeeee><td>Yr.</td><td>Interest</td><td class=borderline bgcolor=gainsboro><a href=# title='The outstanding balance includes some closing costs, if you chose to roll the closing costs into the mortgage.  In that case, Sale Price - Paid Equity &ne; Loan Balance, because a portion of your loan payments are repaying the closing costs.' onclick='alert(this.title); return false'>Loan<br>Balance</a></td><td>Pmts.</td><td>PMI</td><td>Taxes<br>+Ins.</td><td>Maint.+<br>Exp.</td><td>Tax<br>Savings</td>";

	MDT +="<td><a href=# title='Usually you will have more out-of-pocket expenses when buying vs. renting, at least for the first several years.  But usually at some point, your cash out from buying is less than for renting.  The reason is that rent goes up every year with inflation, while your mortgage payment is locked in for 30 years.  When yearly buying expenses become less than rent, I show that by shading the cell in a darker green.  Note that it is usually a better deal to buy than to rent even before this happens, because you also enjoy the value of the home.' onclick='alert(this.title); return false'>Cash<br>out</td>";

	MDT +="<td class=borderline bgcolor=gainsboro>Total<br>Cash out</td><td bgcolor=gainsboro>Paid<br>Equity</td><td bgcolor=gainsboro><a href=# title='This amount has been reduced by any taxes you would pay if you sold the house.' onclick='alert(this.title); return false'>Apprec-<br>iation</a></td><td class=borderline bgcolor=gainsboro><a href=# title='This amount has been reduced by any sales commission and taxes you would pay if you sold the home.' onclick='alert(this.title); return false'>Total<br>Value</td>";
	
	MDT +="<td><a href=# title='Usually you will have more out-of-pocket expenses when buying vs. renting, at least for the first several years.  But usually at some point, your cash out from buying is less than for renting.  The reason is that rent goes up every year with inflation, while your mortgage payment is locked in for 30 years.  When yearly buying expenses become less than rent, I show that buy shading the cell in a darker green.  Note that it is usually a better deal to buy than to rent even before this happens, because you also enjoy the value of the home.' onclick='alert(this.title); return false'>Rent</a></td>";

	MDT +="<td bgcolor=gainsboro>Total<br>Rent</td><td class=borderline bgcolor=gainsboro>Return on<br>Invest.</td><td bgcolor=gainsboro><a href=# title='This is how much you laid out to buy your home.  The formula is: TOTAL VALUE - LOAN BALANCE - TOTAL CASH OUT' onclick='alert(this.title); return false'>Buying<br>Net</a></td><td bgcolor=gainsboro>Rent net</td><td bgcolor=gainsboro><a href=# title='This is the difference between buying and renting.  Negative numbers (pink) mean renting is a better deal for that year, and positive numbers (green) mean that buying is a better deal at that point.  The amount shown is the amount you save (or lose) by going with one method over the other.' onclick='alert(this.title); return false'>Rent<br>vs.<br>Buy</a></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+propertyTaxes-deductibleExclusion)*taxBracket;
		else {taxSavings='';}
		if (termCounter==1 && taxCredit) {taxSavings+=taxCredit;}

		cashSpentPeriod = (pmt*12+pmi+maintenance+extraExpenses+propertyTaxes+insurance-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; // No longer deducting the sale commission here, only in the Total Value column;  previous formula was: paidEquity *= (1-saleCommissionRate);
		appreciation = houseValue-price;
		appreciationNet = (houseValue-price); // No longer deducting the sale commission here, only in the Total Value column; previous formula had this at the end: * (1-saleCommissionRate);
		houseValueNet = houseValue * (1-saleCommissionRate);

		// FIGURE TAXES ON SALE
		taxOnSale=0; // Must prime in case we don't run the IF
		if (homeSaleExclusion >0 && appreciation > homeSaleExclusion) {
			taxOnSale = (houseValueNet-price) * cgbracket;
			appreciationNet -= taxOnSale;
			houseValueNet -= taxOnSale;
		}

		// GENERAL COMPARISON
		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
		MDT+= "<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(propertyTaxes+insurance)+"</td><td>"+addCommas(maintenance+extraExpenses+'')+"</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 *= expensesInflation;
		extraExpenses *= expensesInflation;
		deductibleExclusion *= expensesInflation;
		homeSaleExclusion *= expensesInflation;
		propertyTaxes *= appRate;
		insurance *= appRate;
		periodRent *= (1+rentInflation); // inflate for next year


		// Show the results summary if selected year

		if (termCounter==resultsYear) {
			commission = fix(houseValue * saleCommissionRate +'');
//			houseTotal = (cashSpent+commission+taxOnSale) -paidEquity-appreciation;
//			rentTotal  = paidRent-netInvestment;
			houseTotal = -houseSide;
			rentTotal  = -rentSide;
			houseTotalDisplay = addCommas(houseTotal);
			  if (houseTotal>0) houseTotalDisplay2 = "<span style='color:#600'>("+houseTotalDisplay+")</span>";
			  else houseTotalDisplay2 = houseTotalDisplay.substring(1,houseTotalDisplay.length); // Kill the minus sign
			rentTotalDisplay = addCommas(rentTotal);
			  if (rentTotal>0) rentTotalDisplay2 = "<span style='color:#600'>("+rentTotalDisplay+")</span>";
			  else rentTotalDisplay2 = rentTotalDisplay.substring(1,rentTotalDisplay.length); // Kill the minus sign
			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 if (houseTotal > paidRent) {
				summary="<b>Buying does not become better than renting during the first "+termCounter+" years</b>";
				if (RoR>1) {summary+=", even if you don't invest your monthly savings from renting instead of buying.";}
				else {summary+=".";}
				noProfitInSummary=1;
			}
			else {
				summary = "<b>Buying does not become better than renting during the first "+termCounter+" years</b>";
				if (RoR>1) {summary+="(assuming that you religously invest your monthly savings from renting instead of buying).";}
				else {summary+=".";}
				noProfitInSummary=1;
			}

			if (RoR>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. ";
			}
			else {investmentNote='';}

			if (houseTotal>0 && rentTotal>0) {
				summary+= "<p>Here's how much you're out under each scenario:<br>";
				summary+= "&nbsp;<b>"+houseTotalDisplay+"</b> to buy the house.<br>";
				summary+= "&nbsp;<b>"+rentTotalDisplay+"</b> from renting ";
				if (RoR>1) {
					summary+= "if you invest the difference.<br>";
					summary+= "&nbsp;<b>"+addCommas(paidRent)+"</b> from renting if you don't invest.";
				}
			}
			else if (houseTotal<0 && rentTotal<0) {
				summary += "<p>Since the Net Spent figures on the bottom line are actually positive, 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;
			show('resultsDiscussion', summary);

			show('CashSpentHouse', addCommas(cashSpent) );
			show('Commission', addCommas(commission) );

			if (taxOnSale) {
				show('SalesTax',addCommas(taxOnSale));
				document.getElementById('salesTaxRow').style.display='table-row';
			}
			else {document.getElementById('salesTaxRow').style.display='none';}

			if (balance) {
				show('LoanBalance',addCommas(balance));
				document.getElementById('balanceRow').style.display='table-row';
			}
			else {document.getElementById('balanceRow').style.display='none';}

			show('HouseValue',addCommas(houseValue));
			show('HouseTotal1',houseTotalDisplay2);

			show('CashSpentRent',addCommas(paidRent));
			show('RentTotal1',addCommas(paidRent));

			show('ROI', addCommas(netInvestment));
			show('HouseTotal2',houseTotalDisplay2);

			show('RentTotal2',rentTotalDisplay2);
		}

	} // Stop the iterations

	MDT +="</table>";
	show('MegaDataTable', MDT);

}

//----------------------------------------
// Utility subroutines
//----------------------------------------
function show(id,value) { document.getElementById(id).innerHTML = value}

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) {
	theField = document.getElementById(field);
	length = theField.options.length;

	answer=prompt(message,theDefault);
	if (answer) answer=fix(answer); // Running it twice, b/c might be empty after stripping bad chars
	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;
}
