/**
 * This file contains the PhotoBiz Calendar JavaScript Interface 
 * for adding Calendar functionality to HTML pages 
 *
 * The file contains two JavaScript Classes that provide the said 
 * functionality. class pmCalendar is the base calendar class. The 
 * navCalendar class extends the pmCalendar class and provides year and 
 * month based navigation options
 *
 * Language: JavaScript
 * Depenedancies: MooTools 1.11
 *
 * LICENSE: This source file is subject to version 1.11 of the MooTools creative 
 * Commons license that is available through the world-wide-web at the following URI:
 * http://creativecommons.org/licenses/by-nc-sa/3.0/  
 *
 * @package    pmSlideshow
 * @author     ProjectMiso.net <email@projectmiso.net>
 * @copyright  2009 PhotoBiz, LLC
 * @version    1.0
 * @since      August 03, 2009
 * @deprecated N/A
*/

 
/**
* Properties - Public Variables for pmCalendar: 
		container:			null,			//ID of the element where the calendar should be inserted - REQUIRED
		startYear:			null,			//starting year - integer
		startMonth: 		null,			//starting month - integer or string
		monthLabels:	{
			textcase: 			"mixed", 	//mixed, upper, lower
			abbreviation:		null		//3 chars or or null for showing full name
		},
		weekLabels:	{
			textcase: 			"mixed", 	//mixed, upper, lower
			abbreviation:		3,			//1,2,3 charts or null for showing full name
		},
		showTitleBar:		true,			//show or hide the title bar on top of the dates
		disablePastDates:	false,			//if set to true, will make past dates non clickable
		validDateRange:		[],				//two dates setting the left and right limits of valid (clickable) dates
		markedDates:		[],				//array containing dates that are highlighted
		invalidDates:		[],				//array containing dates users cannot click
		
		//styling options
		titleBarCSS:		"calTitleBar",				//CSS for the title bar containing the navigation and year/month label
		monthLabelCSS:		"calLblMonth",				//CSS for the label in the title bar showing the month name
		yearLabelCSS:		"calLblYear",				//CSS for the label in the title bar showing the year name
		weekContainerCSS: 	"calWeekContainer",			//CSS for the container (row) that holds the week day names 
		dayBoxCSS: 			"calDayBox",				//CSS for each box containing the week day name
		dateContainerCSS: 	"calDateContainer",			//CSS for the container that holds all the dates for hte month
		dateBoxCSS:			"calDatesBox",				//CSS for the individual date boxes 
		blankDatesBoxCSS:	"calBlankDatesBox",			//CSS for the individual date boxes that are blank
		todayDateBoxCSS:	"calTodayDateBox",			//CSS for the individual date boxe with today's date
		markedDateBoxCSS:	"calMarkedDateBox",			//CSS for the individual date boxes that have special highlight or marking
		invalidDateBoxCSS:	"calInvalidDateBox",		//CSS for the individual date boxes that are made invalid for any reason
		
		//events
		onDateChange: 		function(month, year){},		//event when a month is changed
		onDateClick: 		function(date){}		//event when a month is changed

* Properties - Public Variables for navCalendar: 
		//extra options for configuring the navigation stuff
		navYearPrev:	null,		//ID of navigation element to move to the previous year
		navYearNext:	null,		//ID of navigation element to move to the next year
		navYearLabel:	null,		//ID of the year display label element
		navMonthPrev:	null,		//ID of navigation element to move to the previous month
		navMonthNext:	null,		//ID of navigation element to move to the next month
		navMonthLabel:	null,		//ID of the month display label element
		navMonthsCSS:	null		//css names for the month links/buttons
*/


 
/**
* Public Methods: 
 	--------------------------
	nextMonth()
	
	Description:
		Loads the next month (relative to the current month in display).
	
	Syntext:
		classInstanceName.nextMonth()
			
	Arguments:
		None
	--------------------------
	
	previousMonth()
	
	Description:
		Loads the previous month (relative to the current month in display).
	
	Syntext:
		classInstanceName.previousMonth()
			
	Arguments:
		None
	--------------------------
	
	nextYear()
	
	Description:
		Loads the next year (keeping the current month in display).
	
	Syntext:
		classInstanceName.nextYear()
			
	Arguments:
		None
	--------------------------
	
	previousYear()
	
	Description:
		Loads the previous year (keeping the current month in display).
	
	Syntext:
		classInstanceName.previousYear()
			
	Arguments:
		None
	--------------------------
	
	showMonth(month)
	
	Description:
		Loads the specified month for the already selected year.
	
	Syntext:
		classInstanceName.showMonth(month)
			
	Arguments:
		'month' is an integer or string. Integer values can be 1 to 12 for each month of the year. String values can be 
		full month name or hte first three characters such as 'January' or 'Jan'. 
	--------------------------
	
	showYear(year)
	
	Description:
		Loads the specified year for the already selected month.
	
	Syntext:
		classInstanceName.showYear(year)
			
	Arguments:
		'year' is an integer in 'yyyy' format such as 2009.
	--------------------------
	
	showMonthYear(month, year)
	
	Description:
		Loads the specified month and year.
	
	Syntext:
		classInstanceName.showMonth(month, year)
			
	Arguments:
		'month' is an integer or string. Integer values can be 1 to 12 for each month of the year. String values can be 
		full month name or hte first three characters such as 'January' or 'Jan'. 
		
		'year' is an integer in 'yyyy' format such as 2009.
 	
*/

 
/**
* Events: 
 	--------------------------
	onDateChange
	
	Syntext:
		onDateChange: customFunctionName
			[or]
		onDateChange: function(month, year){
			... custom code here ....
		}
		
	Arguments:
		'month' is a string with month name in full or first three characters.
		'year' is an integer in 'yyyy' format such as 2009.
		
	
 	--------------------------
	
	onDateClick
	
	Syntext:
		onComplete: customFunctionName
			[or]
		onComplete: function(date){
			... custom code here ....
		}
		
	Arguments:
		'date' is a JavaScript date object
		
		 
*/

var pmCalendar = new Class({	
	options: {
		container:			null,			//ID of the element where the calendar should be inserted
		startYear:			null,			//starting year - integer
		startMonth: 		null,			//starting month - integer or string
		monthLabels:	{
			textcase: 			"mixed", 	//mixed, upper, lower
			abbreviation:		null		//3 chars or or null for showing full name
		},
		weekLabels:	{
			textcase: 			"mixed", 	//mixed, upper, lower
			abbreviation:		3			//1,2,3 charts or null for showing full name
		},
		showTitleBar:		true,			//show or hide the title bar on top of the dates
		disablePastDates:	false,			//if set to true, will make past dates non clickable
		validDateRange:		[],				//two dates setting the left and right limits of valid (clickable) dates
		markedDates:		[],				//array containing dates that are highlighted
		invalidDates:		[],				//array containing dates users cannot click
		
		//styling options
		titleBarCSS:		"calTitleBar",				//CSS for the title bar containing the navigation and year/month label
		monthLabelCSS:		"calLblMonth",				//CSS for the label in the title bar showing the month name
		yearLabelCSS:		"calLblYear",				//CSS for the label in the title bar showing the year name
		weekContainerCSS: 	"calWeekContainer",			//CSS for the container (row) that holds the week day names 
		dayBoxCSS: 			"calDayBox",				//CSS for each box containing the week day name
		dateContainerCSS: 	"calDateContainer",			//CSS for the container that holds all the dates for hte month
		dateBoxCSS:			"calDatesBox",				//CSS for the individual date boxes 
		blankDatesBoxCSS:	"calBlankDatesBox",			//CSS for the individual date boxes that are blank
		todayDateBoxCSS:	"calTodayDateBox",			//CSS for the individual date boxe with today's date
		markedDateBoxCSS:	"calMarkedDateBox",			//CSS for the individual date boxes that have special highlight or marking
		invalidDateBoxCSS:	"calInvalidDateBox",		//CSS for the individual date boxes that are made invalid for any reason
		
		//events
		onDateChange: 		function(month, year){},		//event when a month is changed
		onDateClick: 		function(date){}		//event when a month is changed
	},
	initialize: function (options){
		var clss = this;
		this.setOptions(options);
		this.parseOptions(this.options);
		
		//the main container
		if (this.container){
			this.container = $(this.container);
		} else {
			return;
			alert("ERROR: calendar container name is missing.");
		}
		this.elementContainer = new Element("div").inject(this.container);
		
		//set some needed values
		this.months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
		this.days	= ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
		this.monthLength = [31,0,31,30,31,30,31,31,30,31,30,31];
		
		//get the current date
		this.todaydate=new Date()
		if (this.startMonth == null){ this.startMonth = this.todaydate.getMonth()+1; }
		if (this.startYear == null){ this.startYear = this.todaydate.getFullYear(); }
		
		if ($type(this.startMonth) == "string"){
			this.startMonth = this.getMonthIndex(this.startMonth);
		}
		
		//create empty current month / year to be assigned values later
		this.currentMonth = this.months[this.startMonth - 1];
		this.currentYear = this.startYear;
		this.currentDate = null;
		
		//call the render function
		this.render(this.startMonth, this.startYear);
		
		
	},
	parseOptions: function(optionsObj, ignoreUndefinedProps){
		if (!optionsObj){ return; } else {
			for (var optionName in optionsObj){
				if (ignoreUndefinedProps && optionsObj[optionName] == undefined){ continue; } else { this[optionName] = optionsObj[optionName]; }
			}
		}
	},
	render: function(m, y){
		var cM='', cH='', cDW='', cD='', brdr='';
		var clss = this;
		
		this.currentDate = new Date(y, m-1, 1); //DD replaced line to fix date bug when current day is 31st
		this.currentDate.od=this.currentDate.getDay()+1; //DD replaced line to fix date bug when current day is 31st
		
		//set current month and year
		this.currentMonth = this.months[m-1];
		if (this.monthLabels.abbreviation){
			this.currentMonth = this.currentMonth.substr(0, this.monthLabels.abbreviation);
		}
		this.currentYear = y;
		
		//var todaydate=new Date() //DD added
		var scanfortoday=(y==this.todaydate.getFullYear() && m==this.todaydate.getMonth()+1)? this.todaydate.getDate() : 0 //DD added
		
		this.monthLength[1]=(((this.currentDate.getFullYear()%100!=0)&&(this.currentDate.getFullYear()%4==0))||(this.currentDate.getFullYear()%400==0))?29:28;
		
		//======== create the title bar
		if (this.showTitleBar){
			tmpString = "<div class='"+this.titleBarCSS+"'>";
			//create the month label
			tmp = this.currentMonth;
			if (this.monthLabels.textcase == "upper"){
				tmp = tmp.toUpperCase();
			} else if (this.monthLabels.textcase == "lower"){
				tmp = tmp.toLowerCase();
			}
			if (this.monthLabels.abbreviation){
				tmp = tmp.substr(0, this.monthLabels.abbreviation);
			}
			tmpString += "<span class='"+this.monthLabelCSS+"'>" + tmp + "</span>";
			tmpString += "<span class='"+this.yearLabelCSS+"'>" + this.currentYear + "</span>";
			tmpString += "</div>";
			
			tmpString += "<div class='"+this.weekContainerCSS+"'>";
		} else {
			tmpString = "<div class='"+this.weekContainerCSS+"'>";
		}
		
		//====== create the week container
		for (i=0;i<7;i++){
			tmp = this.days[i];
			if (this.weekLabels.textcase == "upper"){
				tmp = tmp.toUpperCase();
			} else if (this.weekLabels.textcase == "lower"){
				tmp = tmp.toLowerCase();
			}
			if (this.weekLabels.abbreviation){
				tmp = tmp.substr(0, this.weekLabels.abbreviation);
			}
			tmpString += "<span class='"+this.dayBoxCSS+"'>" + tmp + "</span>";
		}
		tmpString += "</div>";
		
		//======= create the date container
		tmpString += "<div class='"+this.dateContainerCSS+"'>";
		for(i=1;i<=42;i++){
			var x=((i-this.currentDate.od>=0)&&(i-this.currentDate.od<this.monthLength[m-1]))? i-this.currentDate.od+1 : '&nbsp;';
			var css = this.dateBoxCSS;
			var skipActive = false;
			
			if (x==scanfortoday){ //mark today's date 
				css += " " + this.todayDateBoxCSS; //DD added
			} else {
				//blank dates
				if (x=='&nbsp;'){ //mark blank dates
					css += " " + this.blankDatesBoxCSS; 
					skipActive = true;
				}
				//past dates - if they should be disabled
				if (this.disablePastDates && $type(x) == "number"){
					if (this.todaydate > new Date(y, m-1, x)){ //disable past dates
						css += " " + this.invalidDateBoxCSS; 
						skipActive = true;
					}
				}
			}
			//valid date ranges - clocking inside of bound only
			if ($type(x) == "number" && this.validDateRange.length == 2){
				var startRange = new Date(this.validDateRange[0]);
				var endRange = new Date(this.validDateRange[1]);
				if (new Date(y, m-1, x) < startRange){
					if (!css.contains(this.invalidDateBoxCSS)){
						css += " " + this.invalidDateBoxCSS; 
					}
					skipActive = true;
				}
				if (new Date(y, m-1, x) > endRange){
					if (!css.contains(this.invalidDateBoxCSS)){
						css += " " + this.invalidDateBoxCSS; 
					}
					skipActive = true;
				}
			}
			
			//invalid dates - no clicking
			if ($type(x) == "number" && this.invalidDates.length){
				this.invalidDates.each(function(date, j){
					if (new Date(y, m-1, x) - new Date(date) == 0){
						if (!css.contains(clss.invalidDateBoxCSS)){
							css += " " + clss.invalidDateBoxCSS; 
						}
						skipActive = true;
					}
				});
			}
			
			//special marked dates
			if ($type(x) == "number" && this.markedDates.length){
				this.markedDates.each(function(date, j){
					if (new Date(y, m-1, x) - new Date(date) == 0){
						if (!css.contains(clss.markedDateBoxCSS)){
							css += " " + clss.markedDateBoxCSS; 
						}
					}
				});
			}
			
			//marking the active dates active
			if (!skipActive){
				css += " active";
			}
			
			tmpString += "<span class='"+css+"'>" + x + "</span>";
		}
		tmpString += "</div>";
		
		this.elementContainer.setHTML(tmpString);
		
		var dateEl = this.elementContainer.getElements("span[class$=active]");
		dateEl.addEvent("click", function(event){
			var date = new Date(y, m-1, this.getText().toInt());
			clss.onDateClick(date);
		});
		
		//call the events
		this.onDateChange(this.currentMonth, this.currentYear);
		
		
	},
	getMonthIndex: function(param){
		var clss = this, index = null;
		
		if ($type(param) == "string"){
			this.months.each(function(month, i){
				if (param == month 
						|| param == month.substr(0, 3)
						|| param == month.toLowerCase() 
						|| param == month.toLowerCase().substr(0, 3) 
				){
					index = i + 1;
					return index;
				}
			});
		} else if ($type(param) == "number"){
			return param;
		}
		return index;
	},
	nextMonth: function(){
		//set the year and month
		var month = this.getMonthIndex(this.currentMonth) + 1, year = this.currentYear;
		if (month > 12){
			month = 1;
			year++;
		}
		
		//load the display
		this.render(month, year);
	},
	previousMonth: function(){
		//set the year and month
		var month = this.getMonthIndex(this.currentMonth) - 1, year = this.currentYear;
		if (month < 1){
			month = 12;
			year--;
		}
		
		//load the display
		this.render(month, year);
	},
	nextYear: function(){
		//set the year and month
		var month = this.currentMonth, year = this.currentYear + 1;
		//load the display
		this.render(this.getMonthIndex(month), year);
	},
	previousYear: function(){
		//set the year and month
		var month = this.currentMonth, year = this.currentYear - 1;
		//load the display
		this.render(this.getMonthIndex(month), year);
	},
	showYear: function(year){
		//set the year and month
		var month = this.currentMonth;
		//load the display
		this.render(this.getMonthIndex(month), year);
	},
	showMonth: function(month){
		//set the year and month
		var year = this.currentYear;
		//load the display
		this.render(this.getMonthIndex(month), year);
	},
	showMonthYear: function(month, year){
		//load the display
		this.render(this.getMonthIndex(month), year);
	}
});
// implementing the events and options to the color picker class
pmCalendar.implement(new Events, new Options);



var navCalendar = pmCalendar.extend({	
	options: {
		//extra options for configuring the navigation stuff
		navYearPrev:	null,		//ID of navigation element to move to the previous year
		navYearNext:	null,		//ID of navigation element to move to the next year
		navYearLabel:	null,		//ID of the year display label element
		navMonthPrev:	null,		//ID of navigation element to move to the previous month
		navMonthNext:	null,		//ID of navigation element to move to the next month
		navMonthLabel:	null,		//ID of the month display label element
		navMonthsCSS:	null		//css names for the month links/buttons
	},
	initialize: function (options){
		this.parent(options);
		var clss = this;
		
		//======= OPTIONAL NAVIGATION ====
		//navigate usign a list of months
		if (this.navMonths.length){
			this.navMonths.addEvent("click", function(event){
				var e = new Event(event).stop();
				var month = this.getText();
				clss.showMonth(month);
			});
		}
		//navigate using arrows for previous and next year
		if ($type(this.navYearPrev) == "element"){
			this.navYearPrev.addEvent("click", function(event){
				var e = new Event(event).stop();
				clss.previousYear();
				//set the label
				clss.updateLabel();
			});
		}
		//navigate using arrows for previous and next year
		if ($type(this.navYearNext) == "element"){
			this.navYearNext.addEvent("click", function(event){
				var e = new Event(event).stop();
				clss.nextYear();
				//set the label
				clss.updateLabel();
			});
		}
		//navigate using arrows for previous and next month
		if ($type(this.navMonthPrev) == "element"){
			this.navMonthPrev.addEvent("click", function(event){
				var e = new Event(event).stop();
				clss.previousMonth();
				//set the label
				clss.updateLabel();
			});
		}
		//navigate using arrows for previous and next month
		if ($type(this.navMonthNext) == "element"){
			this.navMonthNext.addEvent("click", function(event){
				var e = new Event(event).stop();
				clss.nextMonth();
				//set the label
				clss.updateLabel();
			});
		}
	},
	render: function(m, y){
		
		//======= the year navigation and label =====
		this.navMonths = [];
		if (this.navYearPrev){ 	this.navYearPrev = $(this.navYearPrev); }
		if (this.navYearNext){ 	this.navYearNext = $(this.navYearNext); }
		if (this.navYearLabel){ this.navYearLabel = $(this.navYearLabel); }
		if (this.navMonthPrev){ this.navMonthPrev = $(this.navMonthPrev); }
		if (this.navMonthNext){ this.navMonthNext = $(this.navMonthNext); }
		if (this.navMonthLabel){ this.navMonthLabel = $(this.navMonthLabel); }
		if (this.navMonthsCSS){ this.navMonths = $$("." + this.navMonthsCSS); }
		
		this.parent(m, y);
		this.updateLabel();
	},
	updateLabel: function(){
		
		if ($type(this.navYearLabel) == "element"){
			this.navYearLabel.setHTML(this.currentYear);
		}
		//set the month label
		if ($type(this.navMonthLabel) == "element"){
			this.navMonthLabel.setHTML(this.currentMonth);
		}
	}
});
