function floor(number)
{
  return Math.floor(number*Math.pow(10,2))/Math.pow(10,2);
}

function formatDollarsCents(x)
{
    var d = Math.floor(x);
    var c = x - d;
    c = c * 100;
    c = Math.round(c);
    var cs;
    if ( c < 10 )
        cs = "0" + c;
    else
        cs = "" + c;
    var ds = getDollarString(d);
    return ds + "." + cs;
}

function formatDollars(x)
{
    x = Math.round(x);
    return getDollarString(x);
}

function getDollarString(x)
{
	var p = "";
	if ( x < 0 )
	{
		x *= -1;
		p = "-";
	}
    var digits = 0;
    var ret = "";
    while ( x >= 10 )
    {
        var y = x % 10;
        ret = y + ret;
        digits++;
        if ( digits % 3 == 0 )
           ret = "," + ret;
        x = (x-y) / 10;
    }
    ret = x + ret;
    ret = p + "$" + ret;
    return ret;
}

function fixNumber(x)
{
    x = x.replace(/\$/g, "");
    x = x.replace(/\%/g, "");
    x = x.replace(/,/g, "");
    return x;
}


function formatPercent(decimalAmount) {
	decimalAmount *= 100;

	// make sure we only get 2 decimals
	decimalAmount = decimalAmount.toFixed(2);

	// if the number is even, we don't need decimals
	var count = 0;
	while(decimalAmount.charAt(count) != '.') {
		count++;
	}
	if(decimalAmount.charAt(count+1) == '0' && decimalAmount.charAt(count+2) == '0')
		decimalAmount = Math.round(decimalAmount);
	return "" + decimalAmount + "%";
}

function DollarDate()
{
}

function getMonthString(m)
{
   switch (m)
   {
       case 1:
	return "January";
       case 2:
	return "February";
       case 3:
	return "March";
       case 4:
	return "April";
       case 5:
	return "May";
       case 6:
	return "June";
       case 7:
	return "July";
       case 8:
	return "August";
       case 9:
	return "September";
       case 10:
	return "October";
       case 11:
	return "November";
       case 12:
	return "December";
   }
}


function getDaysInMonth(m, y)
{
   switch (m)
   {
       case 1:
	return 31;
       case 2:
		if( y % 4 == 0) {
			if( y % 100 == 0) {
				if ( y  % 400 == 0)
					return 29;
				else
					return 28;
			}
			else
				return 29;
		}
		else return 28;
       case 3:
	return 31;
       case 4:
	return 30;
       case 5:
	return 31;
       case 6:
	return 30;
       case 7:
	return 31;
       case 8:
	return 31;
       case 9:
	return 30;
       case 10:
	return 31;
       case 11:
	return 30;
       case 12:
	return 31;
   }
}

// returns
//     1 -  d1 is later than d2
//     -1 - d2 is later than d1
//     0 - the dates are the same
function isLater(d1, d2)
{
    if ( d1.year > d2.year )
        return 1;
    if ( d1.year < d2.year )
        return -1;

    if ( d1.month > d2.month )
        return 1;
    if ( d1.month < d2.month )
        return -1;

    if ( d1.day > d2.day )
        return 1;
    if ( d1.day < d2.day )
        return -1;

    return 0;
}

function getDollarDateForToday()
{
	var date = new DollarDate();
	var today = new Date();
	date.year = today.getFullYear();
	date.month = today.getMonth() + 1;
	date.day = today.getDate();
	return date;
}


// returns a DollarDate parsed from a mm-dd-yyyy string
function getDollarDateFromString(s)
{
	var date = new DollarDate();

	date.correctFormat = false;

	var splits = s.split("-");
	if ( splits.length != 3 )
	{
		date.errorMessage = "Date must be in format : mm-dd-yyyy";
		return date;
	}

	var m = removeLeadingZeroes( splits[0] );
	m = parseInt(m);
	if ( isNaN(m) )
   	{
		date.errorMessage = "Please enter the month as a number.";
		return date;
   	}
	if ( m < 1 || m > 12 )
	{
		date.errorMessage = "Please enter a month between 1 and 12.";
		return date;
	}

	var y = removeLeadingZeroes( splits[2] );
	y = parseInt(y);
	if ( isNaN(y) )
   	{
		date.errorMessage = "Please enter the year as a number.";
		return date;
   	}
	if ( y < 1 || y > 9999 )
	{
		date.errorMessage = "Please enter a year between 1 and 9999.";
		return date;
	}

	var d = removeLeadingZeroes( splits[1] );
	d = parseInt(d);
	if ( isNaN(d) )
   	{
		date.errorMessage = "Please enter the day as a number."
		return date;
   	}
	var maxd = getDaysInMonth(m, y);
	if ( d < 1 || d > maxd )
	{
		date.errorMessage = getMonthString(m) + ", " + y + " has " + maxd + " days.  Enter a day between 1 and " + maxd + ".";
		return date;
	}

	date.day = d;
	date.month = m;
	date.year = y;
	date.correctFormat = true;
	return date;
}

// returns a string representation of x.  if the string is shorter than length, will pad zeroes
function padToLength(x, len)
{
	var s = x + "";
	while ( s.length < len )
		s = "0" + s;
	return s;
}

// gets a mm-dd-yyy formatted string for a date d.
function getFormattedString(d)
{
	return padToLength(d.month,2) + "-" + padToLength(d.day,2) + "-" + padToLength(d.year, 4);
}

// removes any leading zeroes from string s
function removeLeadingZeroes(s)
{
	var i = 0;
	while ( s[i] == '0' && i < s.length ) i++;
	if ( i == s.length )
		return "0";
	return s.substring(i);
}


// calculates the approximate difference in days between two date objects
// this function assumes all months are 30.5 days.
function getDayDifference(date1, date2) {
	var days = 365 * (date2.year - date1.year);
	days += ((date2.month - date1.month) * 30.5) + (date2.day - date1.day);
	return Math.round(days);
}

/* isFloat() and TimeObj() added by Per
 *
 */

function isFloat(n)
{
	return ( n - Math.floor(n) ) > 0;
}

// Time Object.
// Constructor:
//  converts seconds over 60 to minutes + rest seconds;
//	converts minutes over 60 to hours + rest minutes;
// 	converts fractions of hours to minutes.
function TimeObj(h, m, s)
{
	this.h = h > 0 ? h : 0;
	this.m = m > 0 ? m : 0;
	this.s = s > 0 ? s : 0;

	// add seconds over 60 to minutes
	if ( this.s > 59 )
	{
		this.m += Math.floor(this.s / 60);
		this.s = this.s % 60;
	}

	// add minutes over 60 to hours
	if ( this.m > 59 )
	{
		this.h += Math.floor(this.m / 60);
		this.m = this.m % 60;
	}

	this.getHours = function()
	{
		return this.h;
	}

	this.getMinutes = function()
	{
		return this.m;
	}

	this.getSeconds = function()
	{
		return this.s;
	}

	this.getFormattedTime = function(format)
	{
		// format as strings.
		// mins, secs: add heading 0 if under 10
		var hStr = this.h.toString();
		var mStr = this.m < 10 ? '0' + this.m.toString() : this.m.toString();
		var sStr = this.s < 10 ? '0' + this.s.toString() : this.s.toString();
		var ret;

		if( format == 'table' )
		// return as html table row (without <tr></tr>)
		{
			ret = "<td>" + hStr + ":</td>\n";
			ret += "\t<td>"+ mStr +":</td>\n";
			ret += "\t<td>"+ sStr +"</td>\n";
		}
		// hh:mm:ss am/pm
		else if ( format == 'clock' )
			// hours : minutes
		{
			if( this.h > 12 ) // pm time
			{
				ret = (this.h - 12).toString() + ':' + mStr + ':' + sStr + ' pm';
			}
			else if( this.h == 12 ) // 12pm
			{
				ret = (this.h).toString() + ':' + mStr + ':' + sStr + ' pm';
			}
			else
			{
				ret = hStr + ':' + mStr + ':' + sStr  + ' am';
			}
		}
		else
			// hh:mm:ss
		{
			ret = hStr + ':' + mStr + ':' + sStr;
		}
		return ret;
	}

	/* Compares this TimeObj to another TimeObj.
	 * Treats hours and minutes as time of day.
	 * Uses 24-hour time.
	 * This time has to be earlier than time compared to (that).
	 * @return false if non-valid times, otherwise new TimeObj:difference in hours, minutes.*/
	this.compareClockTimes = function(that)
	{
		if ( this.getHours() + (this.getMinutes() / 60) + (this.getSeconds() / 3600) >=
		 	 that.getHours() + (that.getMinutes() / 60) + (that.getSeconds() / 3600))
		{
			alert("Start-time ("+this.getFormattedTime('clock')+") is either the same, or later than end-time ("+that.getFormattedTime('clock')+"). Please enter a start-time that is earlier than the end-time.");
			return false;
		}

	 	// adjust minutes if toSeconds < fromSeconds
		if ( that.getSeconds() < this.getSeconds() )
		{
			this.m += 1;
			that.s += ( 60 - this.getSeconds() )
			this.s = 0;
		}

		// adjust hours if toMinutes < fromMinutes
		if ( that.getMinutes() < this.getMinutes() )
		{
			this.h += 1;
			that.m += ( 60 - this.getMinutes() )
			this.m = 0;
		}

		return new TimeObj(that.h - this.h, that.m - this.m, that.s - this.s)
	}
}


// millionaire calculator

function calculate_millionaire(savings,deposits,rateofreturn,age,results)
{
	var savings = $(savings).value;
	if ( savings.length == 0 )
	{
		 alert("Please enter your current savings");
		 return;
	}
	savings = fixNumber(savings);
	savings = parseFloat(savings);

	if ( isNaN(savings) )
	{
		 alert("Please enter your current savings as a number");
		 return;
	}
	if ( savings >= 1000000 )
	{
		var x = $(results);
		x.innerHTML = "You are already a millionaire.  Congratulations!";
		x.style.display = "block";
		return;
	}

	var deposits = $(deposits).value;
	if ( deposits.length == 0 )
	{
		 alert("Please enter your monthly deposits");
		 return;
	}
	deposits = fixNumber(deposits);
	deposits = parseFloat(deposits);
	if ( isNaN(deposits) )
	{
		 alert("Please enter your monthly deposits as a number");
		 return;
	}
	if ( deposits < 0 )
	{
		alert("Please enter monthly deposits >= 0");
	}

	var rate = $(rateofreturn).value;
	if ( rate.length == 0 )
	{
		 alert("Please enter your rate of return");
		 return;
	}
	rate = fixNumber(rate);
	rate = parseFloat(rate);
	if ( isNaN(rate) )
	{
		 alert("Please enter your rate of a return as a number");
		 return;
	}
	if ( rate < 0 )
	{
		alert("Please enter an interest rate >= 0");
	}


	var age = $(age).value;
	if ( age.length == 0 )
	{
		 alert("Please enter your age");
		 return;
	}
	age = fixNumber(age);
	age = parseInt(age);
	if ( isNaN(age) )
	{
		 alert("Please enter your age as a number");
		 return;
	}
	if ( age < 0 )
	{
		alert("Please enter an age >= 0");
	}


	var m;
	var r = 1 + (rate / 100);
	var mr = Math.pow( r, (1/12) );
	var d = savings;

	for ( m=0; m<1200; m++ )
	{
		d = d * mr + deposits;
		if ( d >= 1000000 )
			break;
	}

	var x = $(results);
	var results;
	if ( d < 1000000 )
	{
		results = "Sorry, at this rate you won't be a millionaire in the next hundred years.";
	}
	else
	{
		var y = Math.floor(m / 12);
		results = "At this rate, you will be a millionaire in " + y + " years and " + (m%12) + " months.  You are now " + age + ", so you will be a millionaire by age " + (age + y) + ".";
	}
	x.innerHTML = results;
	x.style.display = "block";

}

// calculate interest

function calculate_interest(interest_rate,start_balance,monthly_contributions,end_balance,total_gain)
{
  var mi = $('interest_rate').value / 1200;
  var base = $('start_balance').value;
  var pp = 0;
  var yr = 0;
  for (i=0; i< $('num_months').value; i++)
  {
    base = base * (1 + mi) + 1 * $('monthly_contributions').value;
    pp++;
    if (pp == 12)
    {
      yr++;
      if (yr < 10) { sp = " " } else { sp = "" }
      //document.temps.FA.value = document.temps.FA.value + "\n" + sp + yr + " : " + floor(base)
      pp = 0;
    }
  }
  var total_gain = base - ($('monthly_contributions').value * $('num_months').value) - $('start_balance').value;

  $('end_balance').innerHTML = numberFormat(floor(base),'$');
  $('total_gain').innerHTML = numberFormat(floor(total_gain),'$');
}


// calculate credit card payment

function calculate_credit_card_payment(balance,interestrate,monthlyamount,monthlypayment,results)
{
	var p = $(balance).value;
	if ( p.length == 0 )
	{
		alert("Please enter your current credit card balance");
		return;
	}

	p = fixNumber(p);
	p = parseFloat(p);
	if ( isNaN(p) )
	{
		alert("Please enter the current balance as a number");
		return;
	}
	if ( p < 0 )
	{
		alert("Please enter a balance >= 0");
		return;
	}

	var rate = $(interestrate).value;
	if ( rate.length == 0 )
	{
		alert("Please enter an interest rate");
		return;
	}
	rate = fixNumber(rate);
	rate = parseFloat(rate);
	if ( isNaN(rate) )
	{
		alert("Please enter the interest rate as a number");
		return;
	}
	if ( rate <= 0 || rate >= 35 )
	{
		alert("Please enter a interest rate greater than 0 and less than 35");
		return;
	}

	var spending = $(monthlyamount).value;
	if ( spending.length > 0 )
	{
		spending = fixNumber(spending);
		spending = parseFloat(spending);
		if ( isNaN(spending) )
		{
			alert("Please enter the monthly spending as a number");
			return;
		}
	}
	else spending = 0;

	if ( spending < 0 )
	{
		alert("Please enter a positive monthly spending");
		return;
	}

	var x = $(monthlypayment).value;
	if ( x.length == 0 )
	{
		alert("Please enter a down payment");
		return;
	}
	x = fixNumber(x);
	x = parseFloat(x);
	if ( isNaN(x) )
	{
		alert("Please enter the monthly payment as a number");
		return;
	}
	if ( x < 0 )
	{
		alert("Please enter a monthly payment >= 0");
		return;
	}

	// monthly rate:
	var m = rate / 1200;

	// you don't pay back what you spend
	x -= spending;
	if(x < 0) {
		alert("You are charging more on your card than you are paying back. With this spending pattern, you won't pay back your credit card debt.");
		return;
	}

	// make sure payment is not too small i.e. smaller than the balance is growing
	if(x <= (m * p))
	{
		alert("Your monthly payment of " + formatDollars(x+spending) + " is smaller than your monthly charges and financing cost of " + formatDollars(m * p + spending) + ". You will never pay off your debt!");
		return;
	}

	// calculate
	var nom = ( (-1 * p * m) / x ) + 1 ;
	var denom = 1 + m;
	var months = -1 * ( Math.log ( nom ) / Math.log ( denom )	);
	var interest = (months * x)- p;

	var resel = $(results);

	var results = "With the information you have given, it will take <b>" + Math.ceil(months) + "</b> months to pay off your credit card balance.";

	results += "<p>You will pay a total of <b>" + formatDollars(interest) + "</b> in interest.";

	resel.innerHTML = results;
	resel.style.display = "block";
}
