
/*
COMPONENT NAME:
- EliasCalendar - v1.0 August 7th 2006
- EliasCalendar - v1.1 Dec 2009, customized for eliax.com

AUTHOR:
- Jose C. Elias, (c)2006 all rights reserved except for those given below. 
- Permission to use granted so long as you place a link somewhere pointing to http://www.eliax.com
  and that you do not modify this notice. The author is not responsible for any problems arrising
  from the use of this component; use at your own risk.

NOTES:
- Yes, I could have used charAt instead of indexOf, and also I could have declared variables outside FOR-loops, etc,
  but since this component will most likely be instantiated once or twice per page, its performance will be more than enough.
- Note that you can have multiple instances of this component on the same page, which can come handy when you want to ask
  a user to select a start and/or ending date of something

OUTPUT:
- This returns a string with all the HTML that renders a calendar on the requested date.
- In each date, it returns the URL you pass it below, plus the following variables on the URL:
  - year (4-digits) - i.e.: 2006
  - month (1 or 2 digits), i.e.: 1=January, 2=February, 3=March, etc
  - day (1 or 2 digits), i.e.: 31

INPUT PARAMS
- targetDIV is the element ID where the calendar will be drawn
- newInstance is a boolean true or false which means to either create a new instance of this calendar or not. End-user will want to set this to true (the false value is used internally for redraws of the same component)
- year is a 4-digit year to display first (i.e.: 2006)
- month is the month to display first, a number representing the ordinal number of the month (i.e.: 1 for January, 2 for February, etc...)
- day is the day of the month to display first, a the number of the day (i.e.: 31)
- startYear is the first year to show in the year drop-down box
- endYear is the last year to show in the year drop-down box
- urlToShow is a string representing the URL to show on the links of each day of the calendar.
  So for example if you pass in this value "foo.php", then you will get back on each day on the calendar a link similar to this "foo.php?year=2006&month=8&day=6",
  and similarly, if you pass in something like "foo.php?id=123" you will get back "foo.php?id=123&year=2006&month=8&day=6".
  NOTE that this url can be either a normal URL (absolute or relative), a javascript function to call, or none. You must start the value of urlToShow with
  the string 'url:', 'javascript:' or 'none' to specify which - see examples below.
- highlightRequestedDate is a boolean true or false. True means to highlight the requested date on the calendar.
- highlightTodaysDate is a boolean true or false. True means to highlight the todays date on the calendar.
- displayLinks is a boolean true or false. True means to display links, false means to never display links.
- displayLinksForOlderDates is a boolean true or false. True means to also display links for dates older than today.
- goToURLWhenMonthOrYearDropDownChanges is a boolean true or false. True means to call the URL specified in 'url:' when a month/year is selected from the dropdown.
  Note that this only applies when the urlToShow value starts with 'url:'

SAMPLE USSAGE:
The following example creates 3 calendars on 3 different pre-defined DIVs called calendarDIV0, calendarDIV1 and calendarDIV2
- The first calendar has links on the day cells.
- The second calendar calls a javascript function called setDate when you click on the day cells.
- The third callendar simply shows the dates.
<body onLoad="EliasCalendar('calendarDIV0', true, 2006, 08, 7, 2006, 2008, 'url:index_process.cfm?id=123', false, true, true, true, true); 
              EliasCalendar('calendarDIV1', true, 2006, 08, 7, 2006, 2010, 'javascript:setDate,123,456', false, true, true, false, false); 
			  EliasCalendar('calendarDIV2', true, 2008, 03, 9, 2005, 2009, 'none', true, true, false, false, false);">
*/
var theTargetDIV = "";
var theStartYear = "";
var theEndYear = "";
var theUrlToShow = "";
var doHighlightRequestedDate = true;
var doHighlightTodaysDate = true;
var doShowLinks = true;
var doDisplayLinksForOlderDates = true;

var instances = new Array();
var instancesCount = 0;
var currentInstanceID = 0; // The current instance of this component we're working on now


function EliasCalendar(targetDIV, newInstance, year, month, day, startYear, endYear, urlToShow, highlightRequestedDate, highlightTodaysDate, displayLinks, displayLinksForOlderDates, goToURLWhenMonthOrYearDropDownChanges)
{
	// If this is a new instance, save the instance and work with it
	if (newInstance == true)
	{
		// Create a new instance of this component by saving its state into the "instances" multi-dimensional array.
		instances[instancesCount] = new Array();
		instances[instancesCount][0]  = targetDIV;
		instances[instancesCount][1]  = year;
		instances[instancesCount][2]  = month;
		instances[instancesCount][3]  = day;
		instances[instancesCount][4]  = startYear;
		instances[instancesCount][5]  = endYear;
		instances[instancesCount][6]  = urlToShow;
		instances[instancesCount][7]  = highlightRequestedDate;
		instances[instancesCount][8]  = highlightTodaysDate;
		instances[instancesCount][9]  = displayLinks;
		instances[instancesCount][10] = displayLinksForOlderDates;
		instances[instancesCount][11] = goToURLWhenMonthOrYearDropDownChanges;
		
		currentInstanceID = instancesCount;
		
		//alert(instances[currentInstanceID][0] + ' ' + instances[currentInstanceID][1] + ' ' + instances[currentInstanceID][2]);
		
		// Prepare the instancesCount variable for the next instance we might create
		instancesCount = instancesCount + 1;
	}
	else // else this is an existing instance, so load values from it to work with it.
	{
		targetDIV 					= instances[currentInstanceID][0];
		//year 						  = instances[currentInstanceID][1];
		//month 					  = instances[currentInstanceID][2];
		//day 						  = instances[currentInstanceID][3];
		startYear 					= instances[currentInstanceID][4];
		endYear 					= instances[currentInstanceID][5];
		urlToShow 					= instances[currentInstanceID][6];
		highlightRequestedDate 		= instances[currentInstanceID][7];
		highlightTodaysDate 		= instances[currentInstanceID][8];
		displayLinks				= instances[currentInstanceID][9];
		displayLinksForOlderDates   = instances[currentInstanceID][10];
		
	}


	
    theTargetDIV = targetDIV;
	theStartYear = startYear;
	theEndYear = endYear;
	theUrlToShow = urlToShow;
	doHighlightRequestedDate = highlightRequestedDate;
	doHighlightTodaysDate = highlightTodaysDate;
	doDisplayLinks = displayLinks;
	doDisplayLinksForOlderDates = displayLinksForOlderDates;

	month = month - 1; // We do this to set months as a zero-offset value (i.e.: January = 0, February =1, instead of Jan = 1, Feb = 2; because this is how Javascript uses dates)
	
	//var week = new Array("D", "L", "M", "M", "J", "V", "S");
	//var week = new Array("Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa");
	//var week = new Array("Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab"); // for offset = 1
	var week = new Array("Lun", "Mar", "Mie", "Jue", "Vie", "Sab", "Dom"); // fot offset = 0
	//var week = new Array('Su','Mo','Tu','We','Th','Fr','Sa');
	
	// For 29-day February, we do a leap-year check below
	var monthdays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	
	var monthNames = new Array("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre");
    //var monthNames= new Array('January','February','March','April','May','June','July','August','September','October','November','December');
	
	//var today = new Date();
	var requestedDate = new Date(year, month, day);
	var month = requestedDate.getMonth();
	var day = requestedDate.getDay();
	var dayN = requestedDate.getDate();
	var days = monthdays[month];
	if (month == 1)
	{
	  var year = requestedDate.getFullYear();
	  if (isLeapYear(year) == true)
	  	days = 29;
	}
	
	var theCalString = "<table border='0' cellspacing='0' cellpadding='0' bgcolor='#333333'>";
	
	var selectedValue = "selected";
    
	// Display the drop-down controls
	theCalString = theCalString + "<tr>";
	
    theCalString = theCalString + "<td bgcolor='#FFFFFF' align='center' nowrap>";
	
		  theCalString = theCalString + "<select name='select' onChange='changeCalendar(" + currentInstanceID + ");' id='calendarMonth" + currentInstanceID + "'>";
		  for (monthToShow=0; monthToShow<=11; monthToShow++)
		  {
				if (month == monthToShow) selectedValue = "selected"; else selectedValue = "";
				theCalString = theCalString + "<option value='" + (monthToShow+1) + "' " + selectedValue + ">" + monthNames[monthToShow] + "</option>";
		  }
		  theCalString = theCalString + "</select>";
		  theCalString = theCalString + " <select name='select' onChange='changeCalendar(" + currentInstanceID + ");' id='calendarYear" + currentInstanceID + "'>";
		  for (yearToShow=startYear; yearToShow<=endYear; yearToShow++)
		  {
				if (year == yearToShow) selectedValue = "selected"; else selectedValue = "";
				theCalString = theCalString + "<option value='" + yearToShow + "' " + selectedValue + ">" + yearToShow + "</option>";
		  }
		  theCalString = theCalString + "</select>";
		  
	theCalString = theCalString + "</td>";
    theCalString = theCalString + "</tr>";
	
	
	
	theCalString = theCalString + "<tr>";
    theCalString = theCalString + "<td bgcolor='#FFFFFF'>";
	
	theCalString = theCalString + "<table border='0' cellspacing='0' cellpadding='3'>";
	
	// Display the name of the month
	/*
	theCalString = theCalString + "<tr align='center' valign='middle'>";
    theCalString = theCalString + "<td colspan='7' bgcolor='#E9D5A8'><font face='Arial, Helvetica, sans-serif' size='3px' color='#6F3C09'><b>" + monthNames[month] + "</b> " + year + "</font></td>";
    theCalString = theCalString + "</tr>";
	*/
	
	// Display day of the week abreviations
	theCalString = theCalString + "<tr align='center' valign='middle'>";
	for (var i=0; i<7; i++)
	{
	  theCalString = theCalString + "<td bgcolor='#DDDDDD'><b><font size='2px' face='Arial, Helvetica, sans-serif'>" + week[i] + "</font></b></td>";
	}
	theCalString = theCalString + "</tr>";
	
	var jumped = 0;
	var dayToInsertInCell = 1;
	var offset = 0; // if this is 1 we draw the calendar starting on a Sunday, but if it is 0 we start on a Monday
	var start = day - dayN%7 + offset;
	
	if (start < 0) 
		start += 7;
	
	var weeks = parseInt((start + days)/7);
	
	if ((start + days)%7 != 0) 
		weeks++;
	
	for (var i=weeks; i>0; i--)
	{
		  theCalString = theCalString + "<tr>";
		  for (var j=7; j>0; j--)
		  {
				if (jumped<start || dayToInsertInCell>days)
				{
					  // Display a blank cell
					  theCalString = theCalString + "<td></td>";
					  jumped++;
				}
				else
				{
					  var cellStyle = "style='background-color:#FFFFFF; color:#0000FF';";
					  
					  var boldStart = "<b>";
					  var boldEnd = "</b>";
					  
					  
					  // If we want to show links on day cells, show them depending on their type
					  if (doDisplayLinks == true)
					  {
						  	  // Show a hand pointer and a bright yellow on the cell background
					  		  var cellInOutColorChangeEvents = "onMouseOver='changeCellColor(this, '#FFFF00'); this.style.cursor='pointer'' onMouseOut='changeCellColor(this, '#FFFFFF'); this.style.cursor='pointer''";
					  
					  
							  // Find out if this calendar will be calling a URL
							  if (urlToShow.indexOf("url:") == 0)
							  {
								  // Strip out the "url:" part
								  var aUrlToShow = urlToShow.substring(4, urlToShow.length);
							  
								  // Find out if the aUrlToShow has a "?" character in it, because if it does it means there is already a parameter being passed, so we'll then append the date using the "&" character instead of the "?" characters
								  var paramAppendChar = "?";
								  if (aUrlToShow.indexOf("?") > -1)
									  paramAppendChar = "&";
								  
								  var linkRaw = aUrlToShow + paramAppendChar + "year=" + year + "&month=" + (month+1) + "&day=" + dayToInsertInCell;
								  var linkStart = "<a style='color:#0000FF' href='../../TESTS/EliasCalendar/" + linkRaw + "'>";
								  var linkEnd = "</a>";
								  var cellOnClickURL = "OnClick=location.href='" + linkRaw + "'";
							  }
							  else // Find out if this calendar will be calling a Javascript function
							  if (urlToShow.indexOf("javascript:") == 0)
							  {
								  // Strip out the "javascript:" part
								  var aUrlToShow = urlToShow.substring(11, urlToShow.length);
								  
								  // Now aUrlToShow holds in its first element the name of the Javascript function to call, and on subsecuent elements (separated by commas) optional parameters to pass to it, so decode this information.
								  var stringTokensArray = aUrlToShow.split(",");
								  var functionToCall = stringTokensArray[0]; // This is the javascript function name to call
								  
								  // If there are more than 1 tokens, grab the next two
								  var functionArguments = "";
								  if (stringTokensArray.length > 1)
								  {
									  for (token=1; token<stringTokensArray.length; token++)
										  functionArguments = functionArguments + ", " + stringTokensArray[token];
								  }
								  
								  var linkRaw = "javascript:" + functionToCall + "(" + year + ", " + (month+1) + ", " + dayToInsertInCell + functionArguments + ");";
								  var linkStart = "<a style='color:#0000FF' href='" + linkRaw + "'>";
								  var linkEnd = "</a>";
								  var cellOnClickURL = "OnClick=javascript:" + functionToCall + "(" + year + "," + (month+1) + "," + dayToInsertInCell + functionArguments + ");";
							  }
							  else // Unknown type, so simply pass it "as is"
							  {
									var linkRaw = urlToShow;
									var linkStart = "<a style='color:#0000FF' href='" + linkRaw + "'>";
									var linkEnd = "</a>";
									var cellOnClickURL = "OnClick=" + linkRaw;
							  }
					  }
					  else // Do not place a link on day cells
					  {
						  	var cellInOutColorChangeEvents = "";
							
							var linkStart = "";
							var linkEnd = "";
							var cellOnClickURL = "";
					  }
					  
					  /* ----   XXX commeted for eliax.com ------ */
					  
					  // Find out if we should hightlight the "requested date" cell or draw it without highlight
					  if (dayToInsertInCell == dayN)
					  {
							var cellStyle = "style='background-color:#E3E3E3; border-width:1px; border-color:#E3E3E3; border-style:solid; color:#000000'";
							cellInOutColorChangeEvents = "";
					  }
					  
					  /* highlight today regardless... eliax.com change XXX */
					  if (isToday(year, month+1, dayToInsertInCell) == true)
					  {
						  var cellStyle = "style='background-color:#E3E3E3; border-width:1px; border-color:#BBBBBB; border-style:solid; color:#000000'";
							cellInOutColorChangeEvents = "";
					  }
					  
					  
					  
					 
					  /*
					  // Find out if we should hightlight the "today date" cell or draw it without highlight
					  if (highlightTodaysDate == true && isToday(year, month+1, dayToInsertInCell) == true)
					  {
							var cellStyle = "style='background-color:#CCCCFF; color:#CCCCFF'";
							cellInOutColorChangeEvents = "";
					  }
					 */
					  
					  // If the cell is earlier than today AND displayLinksForOlderDates is false, then do not display a link on the date
					  /*
					  if (isEarlierThanToday(year, month, dayToInsertInCell) == true)
					  {
							  var boldStart = "";
							  var boldEnd = "";
							
							  if (displayLinksForOlderDates == false)
							  {
									var linkStart = "";
									var linkEnd = "";
									cellOnClickURL = "";
									// Do not show hand pointer and show a washed-out yellow on the cell
									cellInOutColorChangeEvents = "onMouseOver='changeCellColor(this, &#39;#FFFF99&#39;);' onMouseOut='changeCellColor(this, &#39;#FFFFFF&#39;);'; this.style.cursor=&#39;pointer&#39;";
							  }
					  }
					  */
					  
					  // XXX If the cell is later than today do NOT display links!!! - XXX eliax.com change
					  if (isEarlierThanToday(year, month, dayToInsertInCell) == false && isToday(year, month+1, dayToInsertInCell) == false)
					  {
							var boldStart = "";
							var boldEnd = "";
							
							var linkStart = "";
							var linkEnd = "";
							cellOnClickURL = "";
							// Do not show hand pointer and show a washed-out yellow on the cell
							//cellInOutColorChangeEvents = "onMouseOver='changeCellColor(this, &#39;#FFFF99&#39;);' onMouseOut='changeCellColor(this, &#39;#FFFFFF&#39;);'; this.style.cursor=&#39;pointer&#39;";
							cellInOutColorChangeEvents = "";
							 
					  }
					  else //if earlier than today, draw yellow back on mouse over
					  {
							cellInOutColorChangeEvents = "onMouseOver='changeCellColor(this, &#39;#FFFF99&#39;);' onMouseOut='changeCellColor(this, &#39;#FFFFFF&#39;);'; this.style.cursor=&#39;pointer&#39;";  
					  }
					  
					  
				  
					  // Draw the cell with all selected options
					  theCalString = theCalString + "<td " + cellStyle + " " + cellOnClickURL + " " + cellInOutColorChangeEvents + " align='center'><font size='2px' face='rial, Helvetica, sans-serif'>" + linkStart + boldStart + dayToInsertInCell + boldEnd + linkEnd + "</a></font></td>";
					
					  // Get the next day of the month to draw into a cell
					  dayToInsertInCell++;
				}
		  }
		  theCalString = theCalString + "</tr>";
	}
	theCalString = theCalString + "</table>";
	
	theCalString = theCalString + "</td>";
    theCalString = theCalString + "</tr>";
    theCalString = theCalString + "</table>";
	
	
	// Change the inner HTML of the targetDIV element to display the theCalString HTML string we have constructed
	drawCalendar(theCalString);
	
}


// This function finds an object by its element ID
function getObject(id,d)
{
	var i, x;  
	if(!d) d=document; 
	if(!(x=d[id])&&d.all) 
		x=d.all[id]; 
	for (i=0;!x&&i<d.forms.length;i++) 
		x=d.forms[i][id];
	for(i=0;!x&&d.layers&&i<d.layers.length;i++) 
		x=getObject(id,d.layers[i].document);
	if(!x && document.getElementById) 
		x=document.getElementById(id); 
	return x;
};

// This function writes html code inside an html tag
function drawCalendar(htmlcode) 
{
    var layerid = instances[currentInstanceID][0];
	var statement = '';
   
	if (document.all) 
	  statement += "document.all['" + layerid + "'].innerHTML = \"" + htmlcode + "\";";
	else if (document.getElementById)           
	  statement += "document.getElementById('" + layerid + "').innerHTML = \"" + htmlcode + "\";"; 
 
	eval(statement);    
}

// This changes the style of a cell specified in cellTarget
function changeCellColor(cellTarget, myColor)
{
     cellTarget.style.background = myColor;
	 cellTarget.style.color = '#0000FF';
}

// This is the function that gets called everything one of the month or year drop-down boxes changes
function changeCalendar(instanceID)
{
	currentInstanceID = instanceID;
	
	var calendarMonthValue = document.getElementById("calendarMonth" + instanceID).value;
	var calendarYearValue = document.getElementById("calendarYear" + instanceID).value;

	EliasCalendar(theTargetDIV, false, calendarYearValue, calendarMonthValue, 1, theStartYear, theEndYear, theUrlToShow, doHighlightRequestedDate, doHighlightTodaysDate, doDisplayLinksForOlderDates);
	
	if (instances[instanceID][11] == true)
	{
		if (theUrlToShow.substring(0, 4) == 'url:')
		{
			var basicURL = theUrlToShow.substring(4, theUrlToShow.length);
			
			var urlToGoTo = basicURL + '&year=' + calendarYearValue + '&month=' + calendarMonthValue + '&day=1';
			
			//parent.window.location=urlToGoTo; // This calls a URL on the top frame
			document.location=urlToGoTo; // This calls a URL in the current document/frame
		}
		// else do nothing
	}
	
}

// This function returns true if the provided year is a leap year
function isLeapYear(Year)
{
	if (((Year % 4)==0) && ((Year % 100)!=0) || ((Year % 400)==0))
	{
		return (true);
	} 
	else 
	{ 
		return (false); 
	}
}

// This function returns true if the provided date is earlier today
function isEarlierThanToday(Year, Month, Day)
{

	var aDate = new Date(Year, Month, Day);
	var today = new Date();
	var diff = today - aDate;	
	
	if (diff > 86400000)
		return true;
	else
		return false;
}

// This function returns true if the provided date is the same as today
function isToday(Year, Month, Day)
{
	var today = new Date();

	var yearToday  = today.getYear();
	if(yearToday < 2000) // This needs to be done for browser compatibility reasons
	   yearToday = yearToday + 1900;
	
	var monthToday = today.getMonth() + 1;
	var dayToday   = today.getDate();
	
	//alert("Year = " + Year + ", Month = " + Month + ", Day = " + Day + ", yearToday = " + yearToday + ", monthToday = " + monthToday + ", dayToday = " + dayToday);
	
	if ( (Year == yearToday) && (Month == monthToday) && (Day == dayToday) )
		return true;
	else
		return false;
}



