Calendar.prototype.getToday = Today;
Calendar.prototype.getMonthName = MonthName;

Date.prototype.getDayOfYear = DayOfYear;
Date.prototype.getWeekOfYear = WeekOfYear;
Date.prototype.getWeekOfMonth = WeekOfMonth;
Date.prototype.isLeapYear = LeapYear;
Date.prototype.addDays = AddDays;
Date.prototype.addMonths = AddMonths;
Date.prototype.addYears = AddYears;
Date.prototype.getDaysInMonth = DaysInMonth;

function Calendar(date){
	var testDate;
	
	if(date != null){
		testDate = Date.parse(date);
		if(!isNaN(testDate)){
			this.Date = new Date(testDate);
		}
		else{
			this.Date = new Date();
		}
	}
	else{
		this.Date = new Date();
	}
	
	this.WeekDays = new Array("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
	this.Months = new Array("January","February","March","April","May","June","July","August","September","October","November","December");
}

function DayOfYear(){
	var firstDayOfYear = new Date(this.getFullYear(), this.getMonth(), this.getDate());
	var today = new Date(this.getFullYear(), this.getMonth(), this.getDate());
	var dayOfYear;
	
	firstDayOfYear.setDate(1);
	firstDayOfYear.setMonth(0);
	
	dayOfYear = Math.floor((today - firstDayOfYear) / 1000 / 60 /60 / 24);
	
	return dayOfYear;
}

function LeapYear(){
	var year = this.getFullYear();
	if (year % 4 != 0){
		return false;
	}
	else if  (year % 400 == 0){
		return true;
	}
	else if (year % 100 == 0){
		return false;
	}
	else{
		return true;
	}
}
function DaysInMonth(){
	var month = this.getMonth();
	var year = this.getFullYear();
	switch(month){
		case 0:
		case 2:
		case 4:
		case 6:
		case 7:
		case 9:
		case 11:
			return 31;
			break;
		case 3:
		case 5:
		case 8:
		case 10:
			return 30;
			break;
		case 1:
			if(this.isLeapYear()){
				return 29;
			}
			else{
				return 28;
			}
			break;
	}
}
function Today(){
	var date = new Date();
	
	date = date.setHours(0, 0, 0, 0);
	
	return new Date(date);
}
function WeekOfYear(){
	var firstDayOfYear = new Date(this.getFullYear(), this.getMonth(), this.getDate());
	var today = new Date(this.getFullYear(), this.getMonth(), this.getDate());
	var weekOfYear;
	
	firstDayOfYear.setDate(1);
	firstDayOfYear.setMonth(0);
	
	weekOfYear = Math.floor((today - firstDayOfYear) / 1000 / 60 /60 / 24 / 7);
	
	return weekOfYear;
}
function WeekOfMonth(){
	var firstDayOfMonth = new Date(this.getFullYear(), this.getMonth(), 1);
	
	return Math.ceil((this.getDate() + firstDayOfMonth.getDay()) / 7);
}
function MonthName(){
	return this.Months[this.Date.getMonth()];
}

function AddDays(numOfDays){
	var time;
	var days;
	var date;
	
	days = numOfDays * 24 * 60 * 60 * 1000;
	time = this.getTime() + days;
	date = new Date(time);
	
	if(date.getHours() == 1){
		date.setHours(0);
	}
	else if(date.getHours() == 23){
		date.setDate(date.getDate() + 1);
		date.setHours(0);
	}
	
	return new Date(date);
}
function AddMonths(numOfMonths){
	var years = Math.floor(Math.abs(numOfMonths) / 12);
	var months;
	var newMonth;
	
	if(numOfMonths < 0){
		years = years * -1;
	}
	if(numOfMonths < 12 && numOfMonths > -12){
		newMonth = this.getMonth() + numOfMonths;
	}
	else{
		newMonth = this.getMonth() + (numOfMonths % 12);
	}
	
	if(newMonth > 11){
		years++;
		newMonth = newMonth - 12;
	}
	else if(newMonth < 0){
		years--;
		newMonth = newMonth + 12;
	}

	this.setFullYear(this.getFullYear() + years);
	this.setMonth(newMonth);
}
function AddYears(numOfYears){
	this.setFullYear(this.getFullYear() + numOfYears);
}

function getHolidays(year){
	var holidays = new Array();
	var workingDate;
	
	/*********** Calculate Thanksgiving Day ***************************/
	workingDate = new Date(year, 10, 1);
	workingDate = workingDate.addDays(-workingDate.getDay() + 4);
	
	if(workingDate.getWeekOfMonth() == 1){
		workingDate = workingDate.addDays(21);
	}
	else{
		workingDate = workingDate.addDays(28);
	}
	addHoliday(holidays, workingDate, "Thanksgiving Day");
	/******************************************************************/

	/********** Calculate Memorial Day ***************************************************/
	workingDate = new Date(year, 4, 31);
	workingDate = workingDate.addDays(-workingDate.getDay() + 1);

	if(workingDate.getMonth() != 4){
		workingDate = workingDate.addDays(-7);
	}
	addHoliday(holidays, workingDate, "Memorial Day");
	/*************************************************************************************/
	
	/******************* Calculate Labor Day *********************************************/
	workingDate = new Date(year, 8, 1);
	workingDate = workingDate.addDays(-workingDate.getDay() + 1);
	if(workingDate.getMonth() != 8){
		workingDate = workingDate.addDays(7);
	}
	addHoliday(holidays, workingDate, "Labor Day");
	/*************************************************************************************/
	
	/****************** Calculate Daylight Savings Time ***************************/
//	workingDate = new Date(year, 3, 1);
//	
//	workingDate = workingDate.addDays(-workingDate.getDay());
//	if(workingDate.getMonth() != 3){
//		workingDate = workingDate.addDays(7);
//	}
//	addHoliday(holidays, workingDate, "Daylight Savings Time Begins");
//	
//	workingDate = new Date(year, 9, 31);
//	workingDate = workingDate.addDays(-workingDate.getDay());
//	
//	addHoliday(holidays, workingDate, "Daylight Savings Time Ends");
	/*************************************************************************************/
	
	/******************** Calculate Easter ***********************************************/
	var FirstDig, Remain19, temp //intermediate results
	var tA, tB, tC, tD, tE       //table A to E results

	FirstDig = parseInt(year / 100)    //first 2 digits of year
	Remain19 = year % 19               //remainder of year / 19

	// calculate PFM date
	temp = parseInt((FirstDig - 15) / 2) + 202 - (11 * Remain19)

	if(FirstDig == 21 || FirstDig == 24 || FirstDig == 25 || FirstDig == 34 || FirstDig == 35 || FirstDig == 38){
		temp--;
	}
	else if(FirstDig >= 27 && FirstDig <= 32){
		temp--;
	}
	else if(FirstDig == 33 || FirstDig == 36 || FirstDig == 37 || FirstDig == 39 || FirstDig == 40){
		temp -= 2;
	}
	temp = temp % 30;
	
	tA = temp + 21
	if(temp == 29){
		tA -= 1;
	}
	else if(temp == 28 && Remain19 > 10){
		tA -= 1;
	}
	
	//find the next Sunday
	tB = (tA - 19) % 7
		
	tC = (40 - FirstDig) % 4
	if(tC == 3){tC = tC + 1}
	if(tC > 1){tC = tC + 1}
		    
	temp = year % 100
	tD = (temp + temp / 4) % 7
		
	tE = ((20 - tB - tC - tD) % 7) + 1
	d = Math.ceil(tA + tE);

	//return the date
	if(d > 31){
		d = d - 31
		m = 3
	}
	else{
		m = 2
	}

	addHoliday(holidays, new Date(year, m, d), "Easter");
	/*************************************************************************************/
	
	/***************** Calculate Parents' Day ********************************************/
	// calculate Father's Day
	workingDate = new Date(year, 5, 1);	
	workingDate = workingDate.addDays(-workingDate.getDay());	
	if(workingDate.getMonth() != 5){
		workingDate = workingDate.addDays(7);
	}
	workingDate = workingDate.addDays(14);
	
	addHoliday(holidays, workingDate, "Fathers' Day");
	
	//Calculate Mother's Day
	workingDate = new Date(year, 4, 1);
	workingDate = workingDate.addDays(-workingDate.getDay());
	if(workingDate.getMonth() != 4){
		workingDate = workingDate.addDays(7);
	}
	workingDate = workingDate.addDays(7);
	
	addHoliday(holidays, workingDate, "Mothers' Day");
	
	workingDate = new Date(year, 6, 1);
	workingDate = workingDate.addDays(-workingDate.getDay());
	if(workingDate.getMonth() != 6){
		workingDate = workingDate.addDays(7);
	}
	workingDate = workingDate.addDays(21);

	addHoliday(holidays, workingDate, "Parents' Day");
	/*************************************************************************************/
	
	/******************* Calculate Columbus Day *********************************************/
	workingDate = new Date(year, 9, 8);
	
	if(workingDate.getDay() == 0){  
        workingDate = workingDate.addDays(1);
    } 

    if(workingDate.getDay() == 6){
        workingDate = workingDate.addDays(2);
    }
	
	addHoliday(holidays, workingDate, "Columbus Day");
	/*************************************************************************************/
		 
    /******************* Calculate Veterans Day ******************************************/ 
    workingDate = new Date(year, 10, 11); 

    if(workingDate.getDay() == 0){  
        workingDate = workingDate.addDays(1);
    } 

    if(workingDate.getDay() == 6){
        workingDate = workingDate.addDays(2);
    } 

    addHoliday(holidays, workingDate, "Veteran's Day"); 
    /*************************************************************************************/ 
	
	/*************************************************************************************/
	
	addHoliday(holidays, new Date(year, 0, 1), "New Year's Day");
	addHoliday(holidays, new Date(year, 1, 14), "Valentine's Day");
	addHoliday(holidays, new Date(year, 2, 17), "St. Patrick's Day");
	addHoliday(holidays, new Date(year, 5, 14), "Flag Day");
	addHoliday(holidays, new Date(year, 6, 4), "Independence Day");
	addHoliday(holidays, new Date(year, 9, 31), "Halloween");
	addHoliday(holidays, new Date(year, 11, 25), "Christmas");
	addHoliday(holidays, new Date(year, 1, 2), "Ground Hog Day");

	return holidays;	
}

function addHoliday(container, date, holiday){
	if(container[date.getTime()] != null){
		container[date.getTime()] += " ~~ " + holiday;
	}
	else{
		container[date.getTime()] = holiday;
	}
}