/**
 * Description				: Take-home pay calculator
 * Author							: Stephen Lewis (stephen.lewis@meetmanifest.com)
 * Date								: 1st August 2006
 * Version						: 1.0
 */

// Tax bands
var tax_bands;		

/**
 * Initialise the tax bands.
 */
function initTaxBands() {
	tax_bands = {};

	// PAYE
	tax_bands["paye"] = new Array();
	tax_bands["paye"].push({min: 0, max: 5035, rate: 0});
	tax_bands["paye"].push({min: 5035, max: 7185, rate: 0.1});
	tax_bands["paye"].push({min: 7185, max: 38335, rate: 0.22});
	tax_bands["paye"].push({min: 38335, max: 10000000, rate: 0.4});		// Arbitrarily high maximum

	// NIC - Employee
	tax_bands["nic_employee"] = new Array();
	tax_bands["nic_employee"].push({min: 0, max: 5044, rate: 0});
	tax_bands["nic_employee"].push({min: 5044, max: 33540, rate: 0.11});
	tax_bands["nic_employee"].push({min: 33540, max: 10000000, rate: 0.01});		// Arbitrarily high maximum

	// NIC - Employer
	tax_bands["nic_employer"] = new Array();
	tax_bands["nic_employer"].push({min: 0, max: 5044, rate: 0});
	tax_bands["nic_employer"].push({min: 5044, max: 10000000, rate: 0.128});		// Arbitrarily high maximum
} // initTaxBands


/**
 * Initialise the calculator
 */
function initCalc() {
	var form;
	
	// Check that the browser supports our required methods
	if (!document.getElementById) return (false);
	if (!document.createElement) return (false);
	if (!document.createTextNode) return (false);
	if (!document.insertBefore) return (false);
	if (!document.appendChild) return (false);
	if (!document.removeChild) return (false);
	
	// Check that the page contains the required elements
	if (!document.getElementById("tax_calculator")) return (false);
	if (!document.getElementById("daily_rate")) return (false);
	if (!document.getElementById("accommodation_required")) return (false);
	
	// Initialise the tax bands
	initTaxBands();
	
	// Attach the event listener
	form = document.getElementById("tax_calculator")
	form.onsubmit = handleTaxCalcSubmit;
	
	// Display the form
	form.style.display = "block";
} // initCalc


/**
 * Destroy the error message.
 */
function destroyCalcErrorWrapper() {
	var error;
	
	error = document.getElementById("calculator_error");
	if (error) error.parentNode.removeChild(error);
} // destroyCalcErrorWrapper


/**
 * Destroy the calculation result.
 */
function destroyCalcResultWrapper() {
	var result;
	
	result = document.getElementById("calculator_result");
	if (result) result.parentNode.removeChild(result);
} // destroyCalcResultWrapper


/**
 * Handle the form submission
 */
function handleTaxCalcSubmit() {
	var daily_rate;
	var accomm_reqd;
	var currency_pattern;
	
	// Destroy any previous error message or calculation result
	destroyCalcErrorWrapper();
	destroyCalcResultWrapper();
	
	// Retrieve the data
	daily_rate = document.getElementById("daily_rate").value;
	accomm_reqd = document.getElementById("accommodation_required").checked;
	
	// Validate the daily rate
	currency_pattern = /^[0-9,]+\.?\d{0,2}?$/;
	if (daily_rate.match(currency_pattern) == null) {
		displayTaxCalcError();
		return (false);
	} // if
	
	// Need to remove any formatting. This is targetted at a UK audience, so the period is used as
	// a decimal point, and commas are used to group numbers.
	daily_rate = daily_rate.replace(/,/, "");
	daily_rate = parseInt(daily_rate);				// Discard the pence
	
	if (isNaN(daily_rate)) {
		displayTaxCalcError();
		return (false);
	} else {
		take_home = calcTakeHome(daily_rate, accomm_reqd);
		displayTaxCalcResult(take_home);
		return (false);
	} // if - else
} // handleTaxCalcSubmit


/**
 * Perform the Tax Calculations
 */
function calcTakeHome(daily_rate, accomm_reqd) {
	var expenses, net_pay, gross_pay;	
	var paye_total, nic_employer;
	
	// Cut off point
	if (daily_rate <= 50) return (0);
	
	// Earning a reasonable daily rate, so do the calculations
	paye_total = daily_rate * 260;
	paye_total *= 0.96;				// 4% management fee
	expenses = (accomm_reqd ? 35976 : 12028);		// Expense are hard coded

	if (accomm_reqd) {
		// Accommodation required
		paye_total = (daily_rate <= 188.5) ? 11085 : paye_total -= expenses;
	} else {
		// No accommodation required
		paye_total = (daily_rate <= 92.6) ? 11085 : paye_total -= expenses;
	} // if - else
	
	/* ++ CALCULATE THE TAX ++ */
	// Employer National Insurance.  This is done separate because of the percentage shenanigans.
	if (paye_total <= 5044) {
		nic_employer = 0;
	} else {
		nic_employer = (paye_total - 5044) * (12.8 / 112.8);
	} // if - else
	
	// Employee NI and PAYE.
	gross_pay = paye_total - roundNumber(nic_employer, 2);
	net_pay = gross_pay;	
	net_pay -= calcTax(gross_pay, tax_bands["nic_employee"], false);
	net_pay -= calcTax(gross_pay, tax_bands["paye"], false);
	
	// If the daily rate is below a certain threshold, 
	if ((accomm_reqd) && (daily_rate <= 188.5)) {
		net_pay += (expenses - (11085 - (daily_rate * 260 * 0.96)) - expenses);
	} else if ((!accomm_reqd) && (daily_rate <= 92.6)) {
		net_pay += (expenses - (11085 - (daily_rate * 260 * 0.96)) - expenses);
	} else {
		net_pay += expenses;
	} // if - else
	
	return (net_pay / 12);
} // calcTakeHome


/**
 * Calculate the tax payable on the specified amount.
 *
 * @param			gross					Number. The taxable amount.
 * @param			bands					An Array containing the tax bands to use in the calculations.
 * @param			monthly				Boolean. Is the taxable amount a monthly income? Default is false.
 * @return		An Integer containing the PAYE payable.
 */
function calcTax(gross, bands, monthly) {
	var tax_band;
	var ret;
	var loop_count, loop_length;
	
	// If we're calculating on a monhtly basis, we need to reduce the allowances accordingly
	if (monthly) {
		loop_length = bands.length;
		for (loop_count = 0; loop_count < loop_length; loop_count++) {
			bands[loop_count].min /= 12;
			bands[loop_count].max /= 12;
		} // for
	} // if

	// Calculate the tax that needs to be paid for each band
	ret = 0;
	loop_length = bands.length;
	for (loop_count = 0; loop_count < loop_length; loop_count++) {
		tax_band = bands[loop_count];
		if (gross > tax_band.min) {ret += (Math.min(tax_band.max, gross) - tax_band.min) * tax_band.rate;}
	} // for
	
	return (roundNumber(ret, 2));		
} // calcTax


/**
 * Display the Tax Calculator error message
 */
function displayTaxCalcError() {
	var form, error, heading, message, anchor;
	
	// Create the wrapper
	form = document.getElementById("tax_calculator");
	error = document.createElement("div");
	error.setAttribute("id", "calculator_error");
	error.className = "form_error";
	form.parentNode.insertBefore(error, form);
	
	// Heading
	heading = document.createElement("h3");
	heading.appendChild(document.createTextNode("Oops"));
	error.appendChild(heading);
	
	// Message
	message = document.createElement("p");
	message.appendChild(document.createTextNode("The data you entered was invalid, please check it and re-submit the form. If you keep seeing this message, drop us a line at "));
	
	anchor = document.createElement("a");
	anchor.setAttribute("title", "Send us an email");
	anchor.setAttribute("href", "mailto:enquiries@alternet.co.uk");
	anchor.appendChild(document.createTextNode("enquiries@alternet.co.uk"));
	
	message.appendChild(anchor);
	message.appendChild(document.createTextNode(", and we'll find out what the problem is."));
	
	error.appendChild(message);
	
	// Fade in the field result
	Fat.fade_element(error.id, 30, 1000, "#EEEEEE", "#FFFFFF");
} // displayTaxCalcError


/**
 * Display the Tax Calculator result
 */
function displayTaxCalcResult(result) {
	var result_array, result_pounds, result_pence;
	var form, divs, submit_div;
	var dl, dt, dd, span;
	
	result = formatNumberAsCurrency(result, "£");
	
	form = document.getElementById("tax_calculator");
	divs = form.getElementsByTagName("div");
	loop_length = divs.length;
	
	for (loop_count = 0; loop_count < loop_length; loop_count++) {
		if (divs[loop_count].className == "submit_row") {
			submit_div = divs[loop_count];
			break;
		} // if
	} // for
	
	// Create the result
	dl = document.createElement("dl");
	dl.setAttribute("id", "calculator_result");
	dl.className = "clearfix";
	
	dt = document.createElement("dt");
	span = document.createElement("span");
	span.appendChild(document.createTextNode("Net monthly take home"));
	dt.appendChild(span);
	
	dd = document.createElement("dd");
	span = document.createElement("span");
	span.appendChild(document.createTextNode(result));
	dd.appendChild(span);
	
	dl.appendChild(dt);
	dl.appendChild(dd);
	
	if (submit_div) {
		insertAfter(dl, submit_div);
	} else {
		// Emergency fallback
		insertAfter(answer, form);
	} // if - else
	
	// Fade in the result
	Fat.fade_element(dl.id, 30, 1000, "#EEEEEE", "#FFFFFF");
} // displayTaxCalcResult


/**
 * Round a given number to the specified number of decimal places, and return the result.
 */
function roundNumber(to_round, places) {
	return (Math.round(to_round * Math.pow(10, places)) / Math.pow(10, places));
} // roundNumber


/**
 * Format a number for display as currency.
 *
 * @param				amount			A Number containing the amount to format
 * @param				symbol			A String containing the currency symbol to use
 * @return			A String
 */
function formatNumberAsCurrency(amount, symbol) {
	var ret, am_array, am_pounds, am_pence;
	
	ret = roundNumber(amount, 2);
	
	// Format the number
	ret				= ret.toString();
	am_array	= ret.split(".");
	am_pounds	= am_array[0];
	am_pence	= am_array[1];
	
	if (am_pence) {
		if (am_pence.length == 1) am_pence += "0";
	} else {
		am_pence = "00";
	} // if - else
	
	ret = "£" + am_pounds + "." + am_pence;
	return (ret);
} // formatNumberAsCurrency


// Attach the onload event handler
addLoadEvent(initCalc);
