/**
 * Author: Chris Wetherell
 * Calendar (object)
 *
 * A Calendar class that can create a calendar XML grid
 * and transform it into HTML as needed.
 *
 * Typical usage:
 * var cal = new Calendar();
 * cal.makeCalendarXML(TODAYS_DATE);
 * cal.transformCalendarXML();
 */

function Calendar() 
{

	// properties (with default values)
		
	this.id="DefaultCalendarId";
	this.XSLPath="defaultCalendar.xsl";
	this.setTitles = this.setDefaultAbbreviations;
	this.DataXSLPath = null;
	
	// properties	
	
	this.xml;
	this.html;
	this.date;
	this.destinationObj;
	this.HTMLElement;
	this.monthAbbreviations;
	this.weekdayAbbreviations;
	
	
	/**
	 * getCalendar()
	 *
	 * Get the calendar as an HTML element.
	 *
	 * args: none
	 * returns: an HTML element
	 */	
	this.getCalendar = function(day,month,year)
	{	
		var TODAYS_DATE = new Date();
		
		if(day) {
			TODAYS_DATE.setDate(day);
			TODAYS_DATE.setMonth(month);
			TODAYS_DATE.setYear(year);
		}
		
		// store the number of calendars created
		// in a globally accessible variable
		if (!window._calCount) window._calCount=0; 
		window._calCount++;
	
		// set the month and weekday names
		//this.setTitles();
		this.setLongNames()
		
		// create the calendar XML and store it (this.xml)
		this.makeCalendarXML(TODAYS_DATE);
		
		// transform the calendar XML into HTML and store it (this.HTMLElement)
		this.transformCalendarXML();
		
		// store this calendar in a globally accessible
		// variable that is unique to the calendar type
		eval("window._"+this.id+" = this");
		
		return this.HTMLElement;
	}
	
	/**
	 * setDefaultAbbreviations()
	 *
	 * Set the names of the months and days of the week to
	 * abbrieviated versions.
	 *
	 * args: none
	 * returns: none
	 */	
	this.setDefaultAbbreviations = function() {
		this.monthAbbreviations = new Array("Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez");
		this.weekdayAbbreviations = new Array("D","S","T","Q","Q","S","S");
	}
	
	/**
	 * setLongNames()
	 *
	 * Set the names of the months and days of the week to
	 * longer names.
	 *
	 * args: none
	 * returns: none
	 */	
	this.setLongNames = function() {
		//this.monthAbbreviations = new Array("Janeiro","Fevereiro","Mar&#231;o","Abril","Maio","Junho","Julho",
												//"Agosto","Setembro","Outubro","Novembro","Dezembro");
		//this.weekdayAbbreviations = new Array("Domingo","Segunda","Ter&#231;a","Quarta","Quinta","Sexta","Sabado");
		this.monthAbbreviations = months;
		this.weekdayAbbreviations = weekdays;
	}
	
	/**
	 * transformCalendarXML()
	 *
	 * Transform the Calendar XML to HTML and store it
	 * as a property.
	 *
	 * args: none
	 * returns: none
	 */	
	this.transformCalendarXML = function() {
		objXML = CreateXMLFromString(this.xml);
		objXSL = GetXMLViaHTTP(this.XSLPath); //see xml.js
		//alert(objXSL)
		this.HTMLElement = TransformNodeToHTMLObject(objXML,objXSL);
	}
	
	/**
	 * makeAndReplaceCalendar()
	 *
	 * Make a new Calendar XML document, transform it to HTML, and replace
	 * the calendar object's HTML element.
	 *
	 * args: none
	 * returns: none
	 */	
	this.makeAndReplaceCalendar = function() {
		this.makeCalendarXML(this.date);
		this.transformCalendarXML();
		this.replaceCalendar();
	}
	
	/**
	 * replaceCalendar()
	 *
	 * Replace the calendar object's appended-to-page HTML element 
	 * with the stored HTML element property.
	 *
	 * args: none
	 * returns: none
	 */	
	this.replaceCalendar = function() {
		thisObj = document.getElementById(this.id);
		thisObj.parentNode.replaceChild(this.HTMLElement,thisObj);
	}
	
	/**
	 * changeDateToNextMonth()
	 *
	 * Set the date property one month ahead.
	 *
	 * args: none
	 * returns: none
	 */	
	this.changeDateToNextMonth = function() {
		thisMonth = this.date.getMonth();
		thisYear = this.date.getFullYear();
		nextMonth = (thisMonth==11 ? 0 : thisMonth+1);
		nextMonthsYear = (nextMonth==0 ? thisYear+1 : thisYear);
		this.date = new Date(nextMonthsYear,nextMonth,1);
	}
	
	/**
	 * changeDateToPreviousMonth()
	 *
	 * Set the date property one month previous.
	 *
	 * args: none
	 * returns: none
	 */	
	this.changeDateToPreviousMonth = function() {
		thisMonth = this.date.getMonth();
		thisYear = this.date.getFullYear();
		previousMonth = (thisMonth==0 ? 11 : thisMonth-1);
		previousMonthsYear = (previousMonth==11 ? thisYear-1 : thisYear);
		this.date = new Date(previousMonthsYear,previousMonth,1);
	}
	
	/**
	 * forwardOneMonth()
	 *
	 * Set the calendar one month ahead.
	 *
	 * args: none
	 * returns: none
	 */	
	this.forwardOneMonth = function() {
		this.changeDateToNextMonth();
		this.makeAndReplaceCalendar();
		try {
			document.getElementById(this.id+"_thisdate").style.display="block";
		} catch(e) {}
	}
	
	/**
	 * backOneMonth()
	 *
	 * Set the calendar one month previous.
	 *
	 * args: none
	 * returns: none
	 */	
	this.backOneMonth = function() {
		this.changeDateToPreviousMonth();
		this.makeAndReplaceCalendar();
		try {
			document.getElementById(this.id+"_thisdate").style.display="block";
		} catch(e) {}
	}
	
	/**
	 * toTodaysDate()
	 *
	 * Set the calendar to this month.
	 *
	 * args: none
	 * returns: none
	 */	
	this.toTodaysDate = function() {
		this.date = new Date();
		this.makeAndReplaceCalendar();
	}
	
	this.makeCalendarXML = makeCalendarXML;
}




function makeCalendarXML(date) {
	this.date = date;
	var now = this.date;
	var todaysdate = new Date();
	var month = now.getMonth();
	var year = now.getFullYear();
	var feb = 28;
	
	if (year % 400 == 0) {  
     	feb = 29;  
     } 
     else {  
     	if(year%4 == 0 && year%100!=0){  
        	feb = 29;  
        }  
    }  
	
	var daysinmonth = new Array(31,feb,31,30,31,30,31,31,30,31,30,31);
	
	//if ( ( (year%4 == 0)&&(year%100 != 0) ) || (year%400 == 0) ) {
		//daysinmonth[2] = 28;
	//}
	
	var StartDay;
	var currDate = new Date(year,month,1);
	var prevDate = new Date(year,month-1,1);
	var thisMonthStartsOnWeekDay = currDate.getDay();
	if (thisMonthStartsOnWeekDay>0) {
		StartDay = daysinmonth[prevDate.getMonth()] - (thisMonthStartsOnWeekDay - 1);
	}
	/*set header*/
	var xml="";
	xml+="<weekdays>\n";
	for (var i=0;i<this.weekdayAbbreviations.length;i++) {
		xml+="<day abbr=\"";
		xml+=this.weekdayAbbreviations[i];
		xml+="\" />\n";
	}
	xml+="</weekdays>\n";

	/*set grid*/
	c=0;
	var grid = new Array();
	for (var i=StartDay;i<=daysinmonth[prevDate.getMonth()];i++) {
		grid[c]=new Array(i,"outOfMonth");
		c++;
	}
	for (var i=1;i<=daysinmonth[now.getMonth()];i++) {
		var dayType="";
		if (
			i==todaysdate.getDate()
			&& month==todaysdate.getMonth()
			&& year==todaysdate.getFullYear()
			) dayType="today";
		grid[c]=new Array(i,dayType);
		c++;
	}
	var daysLeft = 42-grid.length;
	for (var i=1;i<=daysLeft;i++) {
		grid[c]=new Array(i,"outOfMonth");
		c++;
	}


	/*transform grid*/
	for (var i=0;i<grid.length;i++) {
		var date = grid[i][0];
		var type = grid[i][1];
		var IsWeekStart = (i%7 == 0);
		var IsWeekEnd = ((i+1)%7 == 0)
		
		if (IsWeekStart) {
			if (type!="outOfMonth") type = "weekendStart";
			xml+="<week>\n";
		}
		if (IsWeekEnd) {
			if (type!="outOfMonth") type = "weekendEnd";
		}
		
		if(type == '') type = "weekDay";
		
		xml+="<date";
		if (type.length>0) xml+=" type=\""+type+"\"";
		xml+=" day=\""+date+"\" />\n";
		if (IsWeekEnd) {
			xml+="</week>\n";
		}
	}


	xml="<calendar" +
		" name=\""+this.monthAbbreviations[month]+" "+year+"\">\n"
		+ xml +
		"</calendar>\n";
		
	
	// add data as needed
	if (this.DataXSLPath!=null) {
		try {
			var objXML = CreateXMLFromString(xml);
			var objXSL = GetXMLViaHTTP(this.DataXSLPath); //see xml.js
			//alert(objXML.xml)
			var doc = TransformNodeToDocumentObject(objXML,objXSL);
			xml = doc.xml;	
		} catch(e) {
alert(e)
			// mensagem de erro
			//alert("Couldn't find Data XSL at "+this.DataXSLPath);
			alert("Serviço indisponível.");
		}
	}

	this.xml=xml;
}
