// $Id: date.js,v 1.3 2009-11-02 16:58:16 smulcahy Exp $
// � 2004 Orbis Technology Ltd. All rights reserved.
Package.provide("date");

// various date prototype to extend date handling in javascript

Date.nameOfMonth  = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
Date.nameOfDay    = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
Date.correction   = 0;

// compare two dates, returns true is they are equal
Date.prototype.equalDate = function (d) {
	return this.getFullYear() == d.getFullYear() && this.getMonth() == d.getMonth() && this.getDate() == d.getDate();
}
Date.prototype.equalTime = function (d) {
	return this.getHours() == d.getHours() && this.getMinutes() == d.getMinutes() && this.getSeconds() == d.getSeconds();
}
Date.prototype.equals = function (d) {
	return (this.compare(d) == 0);
}
Date.prototype.compare = function (d) {
	return d.getSeconds() - this.getSeconds();
}

// returns the number of days in the month
Date.getDaysInMonth = function(year, month) {
	return (new Array(31, (year % 4 == 0 ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31))[month];
}

// return a new date based on the informix string
Date.fromInformixString = function(inf) {
	if (inf == "")
		return null;
		
	var d = new Date();
	d.fromInformixString(inf);
	return d;
}

// returns the number of days in a month
Date.prototype.getDaysInMonth = function () {
	return Date.getDaysInMonth(this.getFullYear(), this.getMonth());
}

// gets the name of a date
Date.prototype.nameOfMonth = function () {
	return Date.nameOfMonth[this.getMonth()];
}

// get the name of a day
Date.prototype.nameOfDay = function () {
	return Date.nameOfMonth[this.getDay()];
}

// sets the value of a date
Date.prototype.set = function (year, month, date) {
	month = Math.max(month, 0);
	month = Math.min(month, 11);

	date  = Math.max(date, 1);
	date  = Math.min(date, Date.getDaysInMonth(year, month));

	this.setDate(date);
	this.setMonth(month);
	this.setFullYear(year);
}

// sets just the time part of the date
Date.prototype.setTimePart = function (hours, minutes, seconds) {
	hours = Math.max(hours, 0);
	hours = Math.min(hours, 23);

	minutes  = Math.max(minutes, 0);
	minutes  = Math.min(minutes, 59);

	seconds  = Math.max(seconds, 0);
	seconds  = Math.min(seconds, 59);

	this.setHours(hours);
	this.setMinutes(minutes);
	this.setSeconds(seconds);
}

// changes the date, but instead of limiting the date
// moves the month, year on or back
Date.prototype.bump = function (year, month, date, hour, minute, second) {
	if (second == null)
		second = this.getSeconds();
	if (hour == null)
		hour = this.getHours();
	if (minute == null)
		minute = this.getMinutes();

	if (second < 0) {
		minute--;
		second = 59;
	} else if (second > 59) {
		minute++;
		second = 0;
	}

	if (minute < 0) {
		hour--;
		minute = 59;
	} else if (minute > 59) {
		hour++;
		minute = 0;
	}

	if (hour < 0) {
		date--;
		hour = 23;
	} else if (hour > 23) {
		date++;
		hour = 0;
	}
	
	if (date < 0) {
		month--;
		date = this.getDaysInMonth();
	}
	if (date > this.getDaysInMonth()) {
		month++;
		date = 1;
	}
	if (month < 0) {
		year--;
		month = 11;
	}
	if (month > 11) {
		year++;
		month = 0;
	}

	this.set(year, month, date);
	this.setTimePart(hour, minute, second);
}

// bump the hour
Date.prototype.prevHour = function () {
	this.bump(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours() - 1 );
}

Date.prototype.nextHour = function () {
	this.bump(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours() + 1);
}

// changes the date to the previous date
Date.prototype.prevDate = function () {
	this.bump(this.getFullYear(), this.getMonth(), this.getDate() - 1 );
}

// changes the date to the next date
Date.prototype.nextDate = function () {
	this.bump(this.getFullYear(), this.getMonth(), this.getDate() + 1);
}

// changes the date to the previous month
Date.prototype.prevMonth = function () {
	this.bump(this.getFullYear(), this.getMonth() - 1, this.getDate());
}

// changes the date to the next month
Date.prototype.nextMonth = function () {
	this.bump(this.getFullYear(), this.getMonth() + 1, this.getDate());
}

// changes the date to the previous year
Date.prototype.prevYear = function () {
	this.bump(this.getFullYear() - 1,  this.getMonth(), this.getDate());
}

// changes the date to the next years
Date.prototype.nextYear = function () {
	this.bump(this.getFullYear() + 1, this.getMonth(), 1);
}

// conversion function to change dates into informix format, if full is specified
// the whole date is converted
Date.prototype.toInformixString = function (full) {
	var year    = this.getFullYear();
	var month   = (this.getMonth()  + 1 < 10 ? "0" : "") + (this.getMonth() + 1)
	var date    = (this.getDate()    < 10 ? "0" : "") + this.getDate()

	var hours   = (this.getHours()   < 10 ? "0" : "") + this.getHours();
	var minutes = (this.getMinutes() < 10 ? "0" : "") + this.getMinutes();
	var seconds = (this.getSeconds() < 10 ? "0" : "") + this.getSeconds();

	var inf =  year + "-" + month + "-" + date;
	if (full) {
		inf += " " + hours + ":" + minutes + ":" + seconds;
	}

	return inf;
}
// set this from an informix date, automatically detects the length
Date.prototype.fromInformixStringDate = function (inf) {
	if (inf.length != 10) {
		return false;
	}

	var year    = parseInt(inf.substring(0, 4));
	var dash1   =          inf.substring(4, 5);
	var month   = parseInt(inf.substring(5, 7));
	var dash2   =          inf.substring(7, 8);
	var date    = parseInt(inf.substring(8, 10));

	if (isNaN(year) || dash1 != "-" || isNaN(month) || dash2 != "-" || isNaN(date)) {
		return false;
	}

	month--;

	this.set(year, month, date);

	return true;
}


Date.prototype.fromInformixStringTime = function (inf) {
	if (inf.length != 8 & inf.length != 5) {
		return false;
	}

	var hours   = parseInt(inf.substring(0, 2));
	var colon1  =          inf.substring(2, 3);
	var minutes = parseInt(inf.substring(3, 5));
	if (inf.length == 8) {
		var colon2  =          inf.substring(5, 6);
		var seconds = parseInt(inf.substring(6, 8));
	} else {
		var colon2  = ":";
		var seconds = 0;
	}

	if (isNaN(hours) || colon1 != ":" || isNaN(minutes) || colon2 != ":" || isNaN(seconds)) {
		return false;
	}

	this.setTimePart(hours, minutes, seconds);

	return true;
}


Date.prototype.fromInformixString = function (inf) {
	if (inf.length == 8) {
		return this.fromInformixStringTime(inf)
	} else if (inf.length == 10) {
		return this.fromInformixStringDate(inf);
	} else if (inf.length == 19 && inf.substring(10, 11) == " ") {
		return this.fromInformixStringDate(inf.substring(0,10)) && this.fromInformixStringTime(inf.substring(11,19));
	} else {
		return false;
	}
}

// a utility function to show a sort format date
Date.prototype.toShortFormat = function () {
	return this.nameOfDay().substring(0,2) + " " + this.getDate() + " " + this.nameOfMonth() + " " + (this.getFullYear()+"").substring(2);
}


// Correct discrepancy between server and client
Date.prototype.correct = function() {
	this.setTime(this.getTime() + Date.correction);
}


// Add a zero
Date._addZero = function(n) {
	return ((n < 10) ? "0" : "") + n
} 

// Format a date
//
//   %a - day of week
//   %b - month
//   %Y - full year
//   %y - year
//   %m - month
//   %d - date
//   %H - hour
//   %M - minute
//   %S - second
//
Date.prototype.format = function(fmt) {
	if (!fmt) {
		fmt = "%a %b %m %H:%M:%S %Y";
	}
	// Make into a string so we can get a substring.
	var tmp_year = this.getFullYear() + "";

	fmt = fmt.replace(/%Y/g, tmp_year);
	fmt = fmt.replace(/%y/g, tmp_year.substr(2,2));
	fmt = fmt.replace(/%m/g, Date._addZero(this.getMonth() + 1));
	fmt = fmt.replace(/%b/g, Date.nameOfMonth[this.getMonth()]);
	fmt = fmt.replace(/%d/g, Date._addZero(this.getDate()));
	fmt = fmt.replace(/%a/g, Date.nameOfDay[this.getDay()]);
	fmt = fmt.replace(/%H/g, Date._addZero(this.getHours()));
	fmt = fmt.replace(/%M/g, Date._addZero(this.getMinutes()));
	fmt = fmt.replace(/%S/g, Date._addZero(this.getSeconds()));

	return fmt;
}

