function chkNumber(input, min, max, fieldName, mayBeBlank) {
	msg = 'The ' + fieldName + ' field';
	if (input.value == null || input.value.length == 0) {
		if (mayBeBlank == "yes") {
			return true;
		}
		alert(msg + ' must be filled in!');
		input.focus();
		input.select();
		return false;
	}
	var str = input.value;
	for (var i = 0; i < str.length; i++) {
		var ch = str.substring(i, i + 1);
		if ((ch < "0" || "9" < ch) && ch != '.') {
			if (ch != '%' || i != str.length-1) {
				alert(msg + ' has a non-numeric character');
				input.focus();
				input.select();
				return false;
			}
		}
	}
	var num = parseFloat(str)
	if (num < min || max < num) {
		alert(msg + ' must be between [' + min + ".." + max + "]");
		input.focus();
		input.select();
		return false;
	}
	return true;
}

function adjRate(input) {
	if (input.value < 1.00) input.value *= 100;
}

function round(value, places) {
	var chars = (places == 0 ? 0 : places + 1);
	var str = "" + value;
	for (var i = 0; (str.substring(i, i + 1) != "." && i < str.length); ++i) {
	}
	if (i == 0) {
		return str;
	}
	if (i < 4) {
		return(str.substring(0, i + chars));
	}
	var retstr = "";
	for (j = 0; j < i; ++j) {
		if (j != 0 && (i - j) % 3 == 0) {
			retstr = retstr + ",";
		}
		retstr = retstr + str.substring(j, j+1);
	}
	retstr = retstr + str.substring(i, i+chars);
	return retstr;
}

function power(rate, years) {
	var pow = 1.0;
	rate /= 100;
	if (rate < 0.0 || years <= 0) {
		return 1.0;
	}
	for (var i = 0; ++i <= years;) {
		pow *= (1 + rate);
	}
	return pow;
}

function sumpower(rate, years) {
	var factor = 0.0;
	var pow = 1.0;
	rate /= 100;
	if (rate < 0.0 || years <= 0) {
		return 1.0;
	}
	for (var i = 0; ++i <= years;) {
		factor += pow;
		pow *= (1 + rate);
	}
	return factor;
}

function dblsumpower(rate, inf, years) {
	var factor = 0.0;
	var pow = power(inf, years);
	rate /= 100;
	inf  /= 100;
	if (rate < 0.00 || inf < 0.00 || years <= 0) {
		return 1.0;
	}
	for (var i = 0; ++i <= years;) {
		factor += pow;
		pow *= 1 + rate;
		pow /= 1 + inf;
	}
	return factor;
}

function lumpNeeded(payout, postyears, postreturn, posttax, inflation) {
	postreturn *= (1 - posttax / 100);
	return (payout * dblsumpower(postreturn, inflation, postyears)) / (power(postreturn, postyears));
}

function highestPayout(savings, postyears, postreturn, posttax, inflation) {
	postreturn *= (1 - posttax / 100);
	return (savings * power(postreturn, postyears)) / (dblsumpower(postreturn, inflation, postyears));
}

function yearsLeft(savings, payout, postreturn, posttax, inflation) {
	for (i = 0; savings >= 0 && ++i <= 100;) {
		savings = (savings - payout) * (1 + postreturn / 100 * (1 - posttax / 100));
		payout *= (1 + inflation / 100);
	}
	return i - 1;
}

function currentLumpNeeded(lumpsum, preyears, prereturn, pretax) {
	return lumpsum / power(prereturn * (1 - pretax / 100), preyears);
}

function yearlySavingsNeeded(lumpsum, savings, preyears, prereturn, pretax, inflation) {
	lumpsum -= savings * power(prereturn * (1 - pretax / 100), preyears);
	return lumpsum / sumpower(prereturn * (1 - pretax / 100), preyears);
}

function computeForm(form,name) {
	if (!chkNumber(form.age, 1, 100, "Current Age", "no") ||
       !chkNumber(form.savings, 0, 9999999, "Current Savings", "no") ||
       !chkNumber(form.retage, 35, 100, "Retirement Age", "no") ||
       !chkNumber(form.lastage, 35, 200, "Life Expectancy", "no") ||
       !chkNumber(form.retincome, 1000, 9999999, "Desired Income", "no") ||
       !chkNumber(form.inflation, 0, 19.99, "Inflation Rate", "no") ||
       !chkNumber(form.prereturn, 0, 19.99, "Pre-Retirement Return Rate", "no") ||
       !chkNumber(form.pretax, 0, 99.99, "Pre-Retirement Tax Rate", "no") ||
       !chkNumber(form.postreturn, 0, 19.99, "Post-Retirement Return Rate", "no") ||
       !chkNumber(form.posttax, 0, 99.99, "Post-Retirement Tax Rate", "no")) {
        return;
	}
	adjRate(form.inflation);
	adjRate(form.prereturn);
	adjRate(form.pretax);
	adjRate(form.postreturn);
	adjRate(form.posttax);
	var postyears = form.lastage.value - form.retage.value;
	var preyears  = form.retage.value - form.age.value;
	if (form.retage.value < form.age.value) {
		alert('Your retirement age can not be less than your current age');
		return false;
	}
	if (preyears < 0) {
		postyears = form.lastage.value - form.age.value;
	}
    if (postyears < 0) {
		alert('Your life expectancy must be greater than your retirement age and your current age');
		return;
	}
	var savings = (form.savings.value == null || form.savings.length == 0) ? 0.0 : parseFloat(form.savings.value);
    var lumpsum = lumpNeeded(form.retincome.value * power(form.inflation.value, preyears),
							 postyears,
							 form.postreturn.value, form.posttax.value,
							 form.inflation.value);
	var docmessage;
	if (preyears > 0) {
		docmessage = "To retire with an inflation-adjusted retirement income of $" + round(form.retincome.value, 2) + " for " + postyears + " years would require <strong>$" + round(lumpsum, 2) + "</strong> in savings by the time you retired at " + form.retage.value + ".";
		currlump = currentLumpNeeded(lumpsum, preyears, form.prereturn.value, form.pretax.value);
		if (savings > currlump) {
            docmessage = docmessage + "<p><strong>Congratulations!</strong> You already have $" + round(savings-currlump,2) + " more than you need in savings.</p>";
		} else {
			var addsavings = yearlySavingsNeeded(lumpsum, savings, preyears,
												 form.prereturn.value, form.pretax.value,
												 form.inflation.value);
			docmessage = docmessage + "<p>You need to save an additional <strong>$" + round(addsavings, 2) + "</strong> each year to reach your retirement goal.</p>";
		}
	} else {
		var adjage = form.age.value - -yearsLeft(savings, form.retincome.value,
												 form.postreturn.value,
												 form.posttax.value,
												 form.inflation.value);
		var adjincome = highestPayout(savings, postyears,
									  form.postreturn.value,
									  form.posttax.value,
									  form.inflation.value);
		if (savings >= lumpsum) {
			docmessage = docmessage + "<p>You have enough in savings to continue to enjoy an (inflation-adjusted) income of $" + round(form.retincome.value, 2) + " until you reach " + form.lastage.value + ". In fact your savings won't run out until you are at least " + round(adjage, 0) + " or you can increase your retirement income to <strong>$" + round(adjincome, 2) + "</strong>.</p>";
		} else {
			docmessage = docmessage + "<p>You need an <strong>additional $" + round(lumpsum-savings, 2) + "</strong> in savings if you wish to enjoy an (inflation-adjusted) income of $" + round(form.retincome.value, 2) + " until you reach " + form.lastage.value + ". Right now, either your savings will run out when you reach <strong>" + round(adjage, 0) + "</strong> or you will have to decrease your income to <strong>$" + round(adjincome, 2) + "</strong>.</p>";
		}
	}
	result.innerHTML = docmessage;
}