var dayArrayShort = new Array('S', 'M', 'T', 'W', 'T', 'F', 'S');
var dayArrayLong = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
var monthArrayLong = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
var defaultDateSeparator = "/";        // common values would be "/" or "."
var defaultDateFormat = "mdy";    // valid values are "mdy", "dmy", and "ymd"
var dateSeparator = defaultDateSeparator;
var dateFormat = defaultDateFormat;

Calendar = function(id, date, onSelect) {
	this.id = id;
	this.varName = id;
	this.grid = new Array(); // 6 rows of 7 days = 42 cells
	if (onSelect)
	{
		this.onSelect(onSelect);
	}
	if (date !== null)
	{
		this.setDate(date);
	}
};

Calendar.prototype.onSelect = function(callback)
{
	this.onSelectCallback = callback;
};

Calendar.prototype.getDate = function()
{
	return this.date;
};

Calendar.prototype.getDateString = function()
{
	return getDateString(this.date);
};

Calendar.prototype.getMonthName = function()
{
	return monthArrayLong[this.date.getMonth()];
};

Calendar.prototype.getDayNumber = function()
{
	return this.date.getDate();
};

Calendar.prototype.getDayName = function()
{
	return dayArrayLong[this.date.getDay()];
};

/**
Called when user clicks on a (pickable) date on the right side
*/
Calendar.prototype.selectDate = function(i)
{
	if (this.grid[i].click)
	{
		this.setDate(this.grid[i].date);

		if (this.onSelectCallback)
		{
			var formatted = getDateString(this.date);
			this.onSelectCallback(formatted, this.date, this);
		}
	}
};

Calendar.prototype.setDate = function(date)
{
	var dt = getFieldDate(date);
	this.date = dt;
	this.refreshDatePicker(dt.getFullYear(), dt.getMonth(), dt.getDate());

	// Update left side
	$$('div#' + this.id + ' .date .weekday')[0].innerHTML = this.getDayName();
	$$('div#' + this.id + ' .date .weekday-number')[0].innerHTML = this.getDayNumber();
};

/**
This is the function that actually draws the datepicker calendar.
*/
Calendar.prototype.refreshDatePicker = function(year, month, day)
{
  // if no arguments are passed, use today's date; otherwise, month and year
  // are required (if a day is passed, it will be highlighted later)
  var thisDay = new Date();
 
  if ((month >= 0) && (year > 0)) {
    thisDay = new Date(year, month, 1);
  } else {
    day = thisDay.getDate();
    thisDay.setDate(1);
  }

  // Currently showing this (month, year) on the right side
  this.showMonth = thisDay.getMonth();
  this.showYear = thisDay.getFullYear();

  var prevMonth = new Date(thisDay.getYear(), thisDay.getMonth(), 1);
  prevMonth.setTime(prevMonth.getTime() - 1);
  var prevLastDay = prevMonth.getDate();
  
  var month = monthArrayLong[thisDay.getMonth()] + " " + thisDay.getFullYear();
  var monthTD = $(this.id).getElementsByClassName('monthName')[0];
  monthTD.innerHTML = month;
 
  // first, the leading blanks
  var prev = prevLastDay - thisDay.getDay() + 1;
  var cell = 0;
  for (i = 0; i < thisDay.getDay(); i++, prev++)
  {
    this.grid[cell++] = { val: prev, style: 'date-gray', click: false };
  }
  
  // now, the days of the month
  var rowCount = 1;
  do {
    dayNum = thisDay.getDate();
    
    if (dayNum == day)
    {
		this.grid[cell++] = { val: dayNum, style: 'date-selected', date: getDateString(thisDay), click: false };
    }
    else
    {
		this.grid[cell++] = { val: dayNum, style: 'date-normal', date: getDateString(thisDay), click: true };
    }
    
    // if this is a Saturday, start a new row
    if (thisDay.getDay() == 6)
    {
      rowCount++;
    }
    // increment the day
    thisDay.setDate(thisDay.getDate() + 1);
  } while (thisDay.getDate() > 1)
 
	// fill in any trailing blanks
	var next = 1;
    for (i = 6; i >= thisDay.getDay(); i--, next++)
    {
	    this.grid[cell++] = { val: next, style: 'date-gray', click: false };
    }
  
	if (rowCount < 6)
	{
  		// Add another row with greyed-out values
  		for (i = 0; i < 7; i++, next++)
  		{
    		this.grid[cell++] = { val: next, style: 'date-gray', click: false };
  		}
	}

	var days = $$('div#' + this.id + ' .calendar .days a');
	for (i = 0; i < days.length; i++)
	{
		var text = this.grid[i].val;
		days[i].innerHTML = text;
		days[i].parentNode.className = this.grid[i].style;
	}
};

/**
Called when clicking on prev month (adjust=-1) or next month (adjust=1) icons.
*/
Calendar.prototype.changeMonth = function(adjust)
{
  var newMonth = (this.showMonth + adjust) % 12;
  var newYear = this.showYear + parseInt((this.showMonth + adjust) / 12);
  if (newMonth < 0) {
    newMonth += 12;
    newYear += -1;
  }
  this.refreshDatePicker(newYear, newMonth);
};

/**
Convert a JavaScript Date object to a string, based on the dateFormat and dateSeparator
variables at the beginning of this script library.
*/
function getDateString(dateVal)
{
  var dayString = "00" + dateVal.getDate();
  var monthString = "00" + (dateVal.getMonth()+1);
  dayString = dayString.substring(dayString.length - 2);
  monthString = monthString.substring(monthString.length - 2);
 
  switch (dateFormat) {
    case "dmy" :
      return dayString + dateSeparator + monthString + dateSeparator + dateVal.getFullYear();
    case "ymd" :
      return dateVal.getFullYear() + dateSeparator + monthString + dateSeparator + dayString;
    case "mdy" :
    default :
      return monthString + dateSeparator + dayString + dateSeparator + dateVal.getFullYear();
  }
}

/**
Convert a string to a JavaScript Date object.
*/
function getFieldDate(dateString)
{
  var dateVal;
  var dArray;
  var d, m, y;
 
  try {
    dArray = splitDateString(dateString);
    if (dArray) {
      switch (dateFormat) {
        case "dmy" :
          d = parseInt(dArray[0], 10);
          m = parseInt(dArray[1], 10) - 1;
          y = parseInt(dArray[2], 10);
          break;
        case "ymd" :
          d = parseInt(dArray[2], 10);
          m = parseInt(dArray[1], 10) - 1;
          y = parseInt(dArray[0], 10);
          break;
        case "mdy" :
        default :
          d = parseInt(dArray[1], 10);
          m = parseInt(dArray[0], 10) - 1;
          y = parseInt(dArray[2], 10);
          break;
      }
      dateVal = new Date(y, m, d);
    } else if (dateString) {
      dateVal = new Date(dateString);
    } else {
      dateVal = new Date();
    }
  } catch(e) {
    dateVal = new Date();
  }
 
  return dateVal;
}


/**
Try to split a date string into an array of elements, using common date separators.
If the date is split, an array is returned; otherwise, we just return false.
*/
function splitDateString(dateString)
{
  var dArray;
  if (dateString.indexOf("/") >= 0)
    dArray = dateString.split("/");
  else if (dateString.indexOf(".") >= 0)
    dArray = dateString.split(".");
  else if (dateString.indexOf("-") >= 0)
    dArray = dateString.split("-");
  else if (dateString.indexOf("\\") >= 0)
    dArray = dateString.split("\\");
  else
    dArray = false;
 
  return dArray;
}
