function contactInfoOK ()
{
	var email = document.getElementById("contactEmail").value;
	
	if (document.getElementById("contactName").value.length <= 0)
		return "<p>Please enter your name, in the Contact " +
		"Information form above.</p>";
	
	if (email.length <= 0)
		return "<p>Please enter your email address, in the " +
		"Contact Information form above.</p>";
	
	if (document.getElementById("clientName").value.length <= 0 )
		return "<p>Please enter the name of your organization, in the " +
		"Contact Information form above.</p>";
	
	if (!(/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)))
		return "<p>Please enter a valid email address in the Contact " +
		"Information form above.</p>";
		
	return "OK";

}

function updatePercent(res)
{
	var asset = parseFloat(document.getElementById("asset").value);
	var down = parseFloat(document.getElementById("down").value);
  var category = parseFloat(document.getElementById("category").value);
	var residual = parseFloat(res);
	if (isNaN(asset) || isNaN(category) || isNaN(residual)) return;
	
  var assetAmount = round(asset) - round(down);
	residual = round(residual);
	
	var percent = (residual/assetAmount)*100;
	
  document.getElementById("asset").value = asset.toFixed(2);
	document.getElementById("down").value = down.toFixed(2);
	document.getElementById("residual").value = residual.toFixed(2);
  document.getElementById("residualPercent").value = percent.toFixed(11);	
	document.getElementById("residualNote").value = "";
	document.getElementById("residualNoteRows").style.display = "none";
}

function updateResidual(per)
{
	var asset = parseFloat(document.getElementById("asset").value);
	var down = parseFloat(document.getElementById("down").value);
	var category = parseFloat(document.getElementById("category").value);
	var percent = parseFloat(per);
	if (isNaN(asset) || isNaN(category) || isNaN(percent)) return;
  
  var assetAmount = round(asset) - round(down);  	
	var residual = assetAmount * percent/100;
	
	document.getElementById("asset").value = asset.toFixed(2);
	document.getElementById("residual").value = residual.toFixed(2);
	document.getElementById("residualPercent").value = percent.toFixed(11);
	document.getElementById("residualNote").value = "";
	document.getElementById("residualNoteRows").style.display = "none";
}

function applyForLeaseClick ()
{
	var ret = contactInfoOK();
	if (ret == "OK")
		xmlSave();
	else
		document.getElementById('applyHelp1').innerHTML = ret;

}

//
// This function formats a dollar amount nicely.
// Separates thousands with commas.
//
function fmtCur (x)
{
	x = x.toFixed(2);

	var len = 6;
	while (x.length > len) {
		x = x.slice(0,-len) + "," + x.slice(-len);
		len += 4;
	}
	
	return x;
}

//
// This function formats a percent nicely.
//
function fmtRate (x)
{
	x = x.toFixed(2);
		
	x = x + " %";
		
	return x;
}

//
// This function changes the GST according to the checkbox value.
//
function toggleGST (apply, gstValue)
{
	var gst = document.getElementById("gst");
	if (apply)
	{
		gst.value = gstValue.toFixed(1);
	}
	else
	{
		gst.value = "0.0";	
	}
}

//
// This function changes the PST according to the checkbox value.
//
function togglePST (apply, pstValue)
{
	var pst = document.getElementById("pst");
	if (apply)
	{
		pst.value = pstValue.toFixed(1);
	}
	else
	{
		pst.value = "0.0";
	}
}
//
// This function calculates the residual
//
function residualNoteOK ()
{
	if (document.getElementById("residualNote").value.length > 0)
	{
		document.getElementById("residualNoteError").innerHTML = "";
		document.getElementById("residualOK").value = true;
		return true;
	}
	else
	{
		document.getElementById("residualNoteError").innerHTML =
		"Sorry, a reason is required.";
		document.getElementById("residualOK").value = false;
		return false;
	}
}

function toggleHelp ()
{
	var help = document.getElementById('helpSaveAndExport');
	if (help.style.display == 'block')
		help.style.display = 'none';
	else
		help.style.display = 'block';
}

function calculateResidual()
{
	var asset = parseFloat(document.getElementById("asset").value);
	var down = parseFloat(document.getElementById("down").value);
	var category = parseFloat(document.getElementById("category").value);
  if (isNaN(asset) || isNaN(down) || isNaN(category)) return;
  
  var assetAmount = round(asset) - round(down);
	var residual = assetAmount * category / 100;
	
  document.getElementById("residual").value = residual.toFixed(2);
	document.getElementById("residualNote").value = "";
	document.getElementById("residualNoteRows").style.display = "none";	
}

function checkResidual()
{
	var residual = parseFloat(document.getElementById("residual").value);
	var asset = parseFloat(document.getElementById("asset").value);
	var down = parseFloat(document.getElementById("asset").value);
	var category = parseFloat(document.getElementById("category").value);
  if (isNaN(residual) || isNaN(asset) || isNaN(down) || isNaN(category)) return;
	
	var assetAmount = round(asset) - round(down);
	
	if (round(residual) == round(assetAmount * category / 100)) {
		document.getElementById("residualNote").value = "";
		document.getElementById("residualNoteRows").style.display = "none";			
	}
	else {
		//document.getElementById("residualNoteRows").style.visibility = "visible";
		document.getElementById("residualNoteRows").style.display = "block";	
	}
}


//
// This function rounds a dollar amount to the nearest penny.
//
function round(x)
{
	return Math.round(x * 100) / 100;
}

// Convert from a column number (like "218") to a column reference ("HJ").
//
function numberToReference(excel, number)
{
	var reference = excel.Cells(1, number).Address(true, false, 1);
	reference = reference.replace(/\$.*/, "");
	return reference;
}


function LeaseReference()
{
//
// This function returns the monthly payment amount for a lease given
// the essential parameters of the lease.  Uses a method of successive
// approximation to arrive at the best payment.
//
this.getLeasePayment = function(principal, residual, rate, term)
{
	var min, max, payment, balance, interest, error, prev_error, i, j;
	var testSched;
	
	if (principal == 0 || term == 0)
		return 0;
		
	error = 0;
	min = 0;
	max = principal;

	for (j = 0; j < 50; j++) {
		prev_error = error;
		payment = round((min + max) / 2);
		testSched = this.attemptSchedule(principal, term, rate, payment);
		error = residual - testSched[term - 1][2];	
		if (Math.abs(error - prev_error) < 0.0001)
				return payment;
		if (error > 0)
				max = payment;
		else
				min = payment;		
	}

	// Algorithm did not converge
	throw "Unable to calculate lease payment.";
}

this.attemptSchedule = function(p, t, r, payment)
{
	var schedule = new Array();
	var interest = 0;
	var principal = 0;
	var balance = p;
	
	for (var i = 0;i < t; i++)
	{
			interest = round(balance*r/100/12)
			principal = payment - interest;
			balance = balance - principal;
			schedule[i] = new Array(3);
			schedule[i][0] = interest;
			schedule[i][1] = principal;
			schedule[i][2] = balance;		
	}
	return schedule;
}

	//
	// Holds the schedule data that was generated upon the last "update".


	// 
	this.schedule = new Array(60);
	for (var i = 0; i < 60; i ++)
	{
		this.schedule[i] = new Array(5);
	}	

	//
	// Generates and displays the lease summary and lease amortization schedule.
	//
	this.display = function()
	{
		// Get the input values and convert them to numbers
		var asset = parseFloat(document.getElementById("asset").value);
		var nonAsset = parseFloat(document.getElementById("nonAsset").value);
		var down = parseFloat(document.getElementById("down").value);
		var docFees = parseFloat(document.getElementById("docFees").value);
		var assetFees = parseFloat(document.getElementById("assetFees").value);
		var term = parseInt(document.getElementById("term").value);
		var rate = parseFloat(document.getElementById("annualRate").value);
		var gst = parseFloat(document.getElementById("gst").value);
		var pst = parseFloat(document.getElementById("pst").value);
		var residual = parseFloat(document.getElementById("residual").value);
		var residualNoteVisible =
		(document.getElementById("residualNoteRows").style.visibility == "visible");
		var residualNote = document.getElementById("residualNote").value;

		// Get a couple of controls
		var sched = document.getElementById("sched");
		var error = document.getElementById("error");
		var saveAndExport = document.getElementById("saveAndExport");
	
		// Calculate total fees
		var fees = docFees + assetFees;
	
		// Turn GST and PST into a percent.
		var gstRate = gst/100;
	  	var pstRate = pst/100;
			
		// Check inputs for correctness
		try {
			// Check client name
			if (isNaN(asset))
				throw "Asset value amount is not valid.";
			if (asset < 0)
				throw "Asset value amount cannot be negative.";
			if (isNaN(nonAsset))
				throw "Non-asset value amount is not valid.";
			if (nonAsset < 0)
				throw "Non-asset value amount cannot be negative.";
			// Check down payment
			if (isNaN(down))
				throw "Down payment/trade-in amount is not valid.";
			if (down < 0)
				throw "Down payment/trade-in amount cannot be negative.";
			if (down > (asset + fees))
				throw "Down payment/trade-in amount is too large.";
			// Check docFees
			if (isNaN(docFees))
				throw "Document fees amount is not valid.";
			if (docFees < 0)
				throw "Document fees amount cannot be negative.";
			if (docFees > principal)
				throw "Document fees amount is too large.";
			// Check assetFees
			if (isNaN(assetFees))
				throw "Asset fees amount is not valid.";
			if (assetFees < 0)
				throw "Asset fees amount cannot be negative.";
			if (assetFees > principal)
				throw "Asset fees amount is too large.";
			// Check term
			if (isNaN(term))
				throw "Term is not valid.";
			if (term < 0)
				throw "Term cannot be a negative number.";
			if (term > 60)
				throw  "Term cannot exceed 60 months.";
			// Check rate
			if (isNaN(rate))
				throw "Interest rate is not valid.";
			if (rate < 0)
				throw "Interest rate cannot be negative.";
			if (rate > 500)
				throw "Interest rate is too large.";
			// Check residual amount
			if (isNaN(residual))
				throw "Residual amount is not valid.";
			if (residual < 0)
				throw "Residual amount cannot be negative.";
			if (residual > (asset - down))
				throw "Residual amount is too large.";
			if (residualNoteVisible && residualNote.length < 1)
				throw "Reason for adjusting residual amount cannot be blank.";		
		}
		catch (msg) {
			sched.innerHTML = "<div class='error'>Unable to generate schedule.</div>";
			error.innerHTML = msg;
			return;
		}

		// Calculate the principal amount
		var principal = asset;
		principal += nonAsset;
		principal -= down;
		principal += fees;
			
		// Get the lease payment amount
		payment = this.getLeasePayment(principal, residual, rate, term);
	
		// Generate the amortization schedule
		// ----------------------------------
	
		// Generate the heading row of the table
		var html = "";
		    html += "<table class='schedule'>";
		    html += "<tr>";
		    html += "<th>MONTH</th>";
		    html += "<th>PAYMENT</th>";
		    html += "<th>INTEREST</th>";
		    html += "<th>PRINCIPAL</th>";
		    html += "<th>BALANCE</th>";
		    html += "</tr>";
				// The table's first data row shows the starting balance
		    html += "<tr>";
		    html += "<td class='white'></td>";
		    html += "<td class='white'></td>";
		    html += "<td class='white'></td>";
		    html += "<td class='white'></td>";
		    html += "<td class='white'>" + fmtCur(principal) + "</td>";
		    html += "</tr>";    
    		// Save the values a global array, so that if the user wishes
    		// to export to Excel, these values can be easily inserted in the
    		// spreadsheet. Don't need to format - Excel does it.
    		// Give the array three extra rows, for headers, start balance,
				// and totals.
		this.schedule = new Array(term);
		this.schedule[0]= new Array("", "", "", "", principal);

		var balance = principal;
		var interestPart;
		var principalPart;
		var totalInterest = 0;
		var totalPrincipal = 0;
		var totalPayment = 0;
		var finPayment = 0;
		var monthlyPayment = 0;

		// Generate the main rows of the schedule
		for (i = 0; i < term; i++) {
		
			// Calculate the values for this row
			interestPart = round(balance * rate / 100 / 12);
			if (i == term - 1) {
				// Make corrections for the final payment
				principalPart = balance - residual;
				finPayment = payment = interestPart + principalPart;
			}
			else
			{
				monthlyPayment = payment;
				principalPart = payment - interestPart;
			}
			balance -= principalPart;
	
			// The background color of the rows alternates between green and white
			cssClass = (i % 2 == 0) ? "green" : "white";
	
			// Produce the row
			html += "<tr>";
			html += "<td class='" + cssClass + "' style='text-align:center'>"
								+ (i + 1)		+	"</td>";
			html += "<td class='" + cssClass + "'>" + fmtCur(payment)       +	"</td>";
			html += "<td class='" + cssClass + "'>" + fmtCur(interestPart)  +	"</td>";
			html += "<td class='" + cssClass + "'>" + fmtCur(principalPart) +	"</td>";
			html += "<td class='" + cssClass + "'>" + fmtCur(balance)       +	"</td>";
			html += "</tr>";
	
			// Update the totals
			totalInterest += interestPart;
			totalPrincipal += principalPart;
			totalPayment += payment;
			
			// Add row to global array.
			// Skip the first row in the array; we already filled it in.
			this.schedule[i + 1]= new Array(i + 1, payment, interestPart,
			principalPart,balance);
		}

		// Generate the totals row of the schedule
		html += "<tr>";
		html += "<td class='total'></td>";
		html += "<td class='total'>" + fmtCur(totalPayment)   + "</td>";
		html += "<td class='total'>" + fmtCur(totalInterest)  + "</td>";
		html += "<td class='total'>" + fmtCur(totalPrincipal) + "</td>";
		html += "<td class='total'></td>";
		html += "</tr>";
		html += "</table>";
  
		// Add final row to the global array.
		this.schedule[term + 1] = new Array("", totalPayment, 
		totalInterest, totalPrincipal, "");

		//
		// Populate the lease summary
		// --------------------------
  
		// Calculate the values we haven't calculated previously.
		var ttlRepaid = round(principal + totalInterest);
		var monthlyRate = rate/12;
		var gstPerMonth = round(monthlyPayment*gstRate);
		var pstPerMonth = round(monthlyPayment*pstRate);
		var ttlPayment = round(monthlyPayment + gstPerMonth + pstPerMonth);		
		var subFinPayment = round(finPayment + residual);
		var finGST = round(subFinPayment*gstRate);
		var finPST = round(subFinPayment*pstRate);
		var ttlFinPayment = round(subFinPayment + finGST + finPST);
		var fixedPayments = ((term - 1)> 0 ? term -1 : 0);
		
		// Get the current date
		var date = new Date();
		var genDate = date.getYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();

		document.getElementById("requestDate").value = genDate;
		document.getElementById("lsAsset").innerHTML = "$ " + fmtCur(asset);
		document.getElementById("lsNonAsset").innerHTML = "$ " + fmtCur(nonAsset);
		document.getElementById("lsDown").innerHTML = "$ " + fmtCur(down);
		document.getElementById("lsDocFees").innerHTML = "$ " + fmtCur(docFees);
		document.getElementById("lsAssetFees").innerHTML = "$ " + fmtCur(assetFees);
		document.getElementById("lsPrin").innerHTML = "$ " + fmtCur(principal);
		document.getElementById("lsTerm").innerHTML = term;
		document.getElementById("lsAnnualRate").innerHTML = rate.toFixed(2);
		document.getElementById("lsGSTRate").innerHTML = gst.toFixed(2);
		document.getElementById("lsPSTRate").innerHTML = pst.toFixed(2);
		document.getElementById("lsTtlRepaid").innerHTML = "$ " + fmtCur(ttlRepaid);
		document.getElementById("lsTtlInterest").innerHTML = "$ " + fmtCur(totalInterest);
		document.getElementById("lsFixedPayments").innerHTML = fixedPayments;
		document.getElementById("lsMonthlyRate").innerHTML = monthlyRate.toFixed(4);
		document.getElementById("lsPayment").innerHTML = "$ " + fmtCur(monthlyPayment);
		document.getElementById("lsGSTPerMonth").innerHTML = "$ " + fmtCur(gstPerMonth);
		document.getElementById("lsPSTPerMonth").innerHTML = "$ " + fmtCur(pstPerMonth);
		document.getElementById("lsTtlPayment").innerHTML = "$ " + fmtCur(ttlPayment);
		document.getElementById("lsFinPayment").innerHTML = "$ " + fmtCur(finPayment);
		document.getElementById("lsResidual").innerHTML = "$ " + fmtCur(residual);
		document.getElementById("lsSubFinPayment").innerHTML = "$ " + fmtCur(subFinPayment);
		document.getElementById("lsFinGST").innerHTML = "$ " + fmtCur(finGST);
		document.getElementById("lsFinPST").innerHTML = "$ " + fmtCur(finPST);
		document.getElementById("lsTtlFinPayment").innerHTML = "$ " + fmtCur(ttlFinPayment);
					
		// Show the lease amortization schedule
		sched.innerHTML = html;
		// Show no error
		error.innerHTML = "";
	}

}



