/*
 * Based on code written by Lea Smart (www.totallysmartit.com)
 * Modified by Peter Frandsen, pfrandsen@gmail.com
 *
 */

var timeoutDelay = 3000; // milliseconds, set to 0 for the calendar to never auto disappear
var g_startDay = 0; // 0=sunday, 1=monday
	
// preload images
var imgUp = new Image(8,12);
imgUp.src = 'calendar/images/up.png';
var imgDown = new Image(8,12);
imgDown.src = 'calendar/images/down.png';
	
// used by timeout auto hide functions
var timeoutId = false;
	
function Browser(){
  this.dom = document.getElementById ? 1 : 0;
  this.ie  = (this.dom && document.all) ? 1 : 0;
}
var browser = new Browser();
var g_Calendar;  // global to hold the calendar reference, set by constructor
	
function calendarTimeout() {
  timeoutId = setTimeout('g_Calendar.hide();',timeoutDelay);
}
	
// constructor for calendar class
// Valid positions: "top-right", "bottom-left", "mouse"
// 'attacheToID' is the ID of the element that the calendar widget will be positioned next
// to if position != "mouse"
// 'daysOfWeek' and 'months' are for localization
//
function Calendar(initialDate, attacheToID, position, daysOfWeek, months) {
  g_Calendar = this;
  this.initialDate = initialDate;
  this.attacheToID = attacheToID;
  this.position = position;

  this.daysOfWeek = new Array("Su","Mo","Tu","We","Th","Fr","Sa");
  this.months = new Array("January","February","March","April","May","June","July",
                          "August","September","October","November","December");
  this.daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  this.containerLayer = document.getElementById('container');
  if (daysOfWeek) {this.daysOfWeek = daysOfWeek;}
  if (months) {this.months = months;}
}
	
Calendar.prototype.setCurrent = function() {
  g_Calendar = this;
}

Calendar.prototype.getFirstDOM = function() {
  var thedate = new Date();
  thedate.setDate(1);
  thedate.setMonth(this.month);
  thedate.setFullYear(this.year);
  return thedate.getDay();
}

Calendar.prototype.getDaysInMonth = function() {
  if (this.month != 1) {
    return this.daysInMonth[this.month];
  } else {
    // is it a leap year?
    return Date.isLeapYear(this.year) ? 29 : 28;
  }
}
	 
Calendar.prototype.buildString = function() {
  var src = new Array();
  src[src.length] = '<form onSubmit="this.year.blur();return false;" style="margin: 0px; padding: 0px;">\n';
  src[src.length] = '<table width="100%" border="0" cellspacing="0" cellpadding="2" class="calBorderColor">\n';
  src[src.length] = '<tbody>\n';
  src[src.length] = '<tr><td valign="top">\n';
  src[src.length] = '<table width="100%" border="0" cellspacing="0" cellpadding="1" class="calBgColor">\n';
  src[src.length] = '<tr>\n';
  if (this.hasDropDown) {
    src[src.length] = '<td width="50%" class="cal" align="left">\n';
    src[src.length] = '<select class="month" name="month" onchange="g_Calendar.selectChange(this.selectedIndex);">\n';
    for (var i=0;i<this.months.length;i++){
      src[src.length] = '<option value="' + i + '"' 
      if (i == this.month) {src[src.length] = ' selected';}
      src[src.length] = '>' + this.months[i] + '</option>\n';
    }
    src[src.length] = '</select>\n';
  } else {
    src[src.length] = '<td width="60%" class="cal" align="left">\n';
    src[src.length] = '<table border="0" cellspacing="0" cellpadding="0"><tr>\n';
    src[src.length] = '<td><a href="javascript: g_Calendar.changeMonth(-1);">';
    src[src.length] = '<img name="calendar" src="calendar/images/down.png" width="8" height="12" border="0" alt="">';
    src[src.length] = '</a></td>\n';
    src[src.length] = '<td class="cal" width="100%" align="center">' + this.months[this.month] + '</td>\n';
    src[src.length] = '<td class="cal"><a href="javascript: g_Calendar.changeMonth(+1);">\n';
    src[src.length] = '<img name="calendar" src="calendar/images/up.png" width="8" height="12" border="0" alt="">';
    src[src.length] = '</a></td>\n';
    src[src.length] = '</tr>\n</table>\n';
  }
  src[src.length] = '</td>\n';
  /* observation : for some reason if the below event is changed to 'onChange' rather
     than 'onBlur' it totally crashes IE (5)!
  */
  if (this.hasDropDown) { 
    src[src.length] = '<td class="cal"><a href="javascript: g_Calendar.changeYear(-1);">';
    src[src.length] = '<img name="calendar" src="calendar/images/down.png" width="8" height="12" border="0" alt="">';
    src[src.length] = '</a></td>\n';
    src[src.length] = '<td align="center" class="cal">';
    src[src.length] = '<input class="year" type="text" size="4" name="year" maxlength="4" ';
    src[src.length] = ' onBlur="g_Calendar.inputChange(this.value);" value="' + this.year + '">';
    src[src.length] = '</td>\n';
    src[src.length] = '<td class="cal"><a href="javascript: g_Calendar.changeYear(+1);">';
    src[src.length] = '<img name="calendar" src="calendar/images/up.png" width="8" height="12" border="0" alt="">';
    src[src.length] = '</a></td>\n';
  } else {
    src[src.length] = '<td width="40%" align="right" class="cal">\n';
    src[src.length] = '<table border="0" cellspacing="0" cellpadding="0">\n';
    src[src.length] = '<tr>\n<td class="cal"><a href="javascript: g_Calendar.changeYear(-1);">';
    src[src.length] = '<img name="calendar" src="calendar/images/down.png" width="8" height="12" border="0" alt="">';
    src[src.length] = '</a></td>\n';
    src[src.length] = '<td class="cal" width="100%" align="center">' + this.year + '</td>\n';
    src[src.length] = '<td class="cal"><a href="javascript: g_Calendar.changeYear(+1);">';
    src[src.length] = '<img name="calendar" src="calendar/images/up.png" width="8" height="12" border="0" alt="">';
    src[src.length] = '</a></td>\n</tr>\n</table>\n'
    src[src.length] = '</td>\n';
  }
  src[src.length] = '</tr>\n';
  src[src.length] = '</table>\n';
  var iCount = 1;
  var iFirstDOM = (7 + this.getFirstDOM() - g_startDay) % 7;
  var iDaysInMonth = this.getDaysInMonth();
	  
  src[src.length] = '<table width="100%" border="0" cellspacing="0" cellpadding="1" class="calBgColor">\n';
  src[src.length] = '<tr>\n';
  for (var i=0; i<7; i++) {
    src[src.length] = '<td align="center" class="calDaysColor">' + this.daysOfWeek[(g_startDay+i)%7] + '</td>\n';
  }
  src[src.length] = '</tr>\n';
  var tmpFrom = parseInt('' + this.dateFromYear + this.dateFromMonth + this.dateFromDay,10);
  var tmpTo = parseInt('' + this.dateToYear + this.dateToMonth + this.dateToDay,10);
  var tmpCompare;
  for (var j=1;j<=6;j++){
    if (j == 6) {if (iCount > iDaysInMonth) {break;}} // do not output empty last row
    src[src.length] = '<tr>\n';
    for (var i=1; i<=7; i++) {
      src[src.length] = '<td width="16" align="center" '
      if ( (7*(j-1) + i) >= iFirstDOM + 1  && iCount <= iDaysInMonth) {
        if (iCount == this.day && this.year == this.oYear && this.month == this.oMonth) {
          src[src.length] = 'class="calHighlightColor"';
        } else {
          if (i==7-g_startDay || i==((7-g_startDay)%7)+1) src[src.length] = 'class="calWeekend"';
          else src[src.length] = 'class="cal"';
        }
        src[src.length] = '>\n';
        /* could create a date object here and compare that but probably more efficient to
           convert to a number and compare number as numbers are primitives */
        tmpCompare = parseInt('' + this.year + padZero(this.month) + padZero(iCount),10);
        if (tmpCompare >= tmpFrom && tmpCompare <= tmpTo) {
          src[src.length] = '<a class="cal" href="javascript: g_Calendar.clickDay(' + iCount + ');">' + iCount + '</a>';
        } else {
          src[src.length] = '<span class="disabled">' + iCount + '</span>';
        }
        iCount++;
      } else {
        if  (i==7-g_startDay || i==((7-g_startDay)%7)+1) {
          src[src.length] = 'class="calWeekend"';
        } else {
          src[src.length] ='class="cal"';
        }
        src[src.length] = '>&nbsp;';
      }
      src[src.length] = '</td>\n'
    }
    src[src.length] = '</tr>\n'
  }
  src[src.length] = '</table>\n</td>\n</tr>\n</tbody>\n</table>\n</form>\n';
  return src.join("");
}
	
Calendar.prototype.selectChange = function(theValue) {
  this.month = theValue;
  this.writeString(this.buildString());
}
	
Calendar.prototype.inputChange = function(theValue) {
  if (theValue >= 1900 || theValue <= 2100) {
    this.year = theValue;
  }
  this.writeString(this.buildString());
}

Calendar.prototype.changeYear = function(incr) {
  (incr==1) ? this.year++ : this.year--;
  this.writeString(this.buildString());
}

Calendar.prototype.changeMonth = function(incr) {
  if (this.month == 11 && incr == 1){
    this.month = 0;
    this.year++;
  } else {
    if (this.month == 0 && incr == -1) {
      this.month = 11;
      this.year--;
    } else {
      (incr == 1) ? this.month++ : this.month--;
    }
  }
  this.writeString(this.buildString());
}

Calendar.prototype.clickDay = function(day) {
  var target = document.getElementById(this.targetID);
  if (target) {
    target.value = this.formatDateAsString(day, this.month, this.year);
  }
  this.containerLayer.style.visibility='hidden';
}
	
Calendar.prototype.formatDateAsString = function(day, month, year) {
  switch (this.dateFormat.replace(/[\/\-]/g,"")) {
    case 'ddmmmyyyy':
      return padZero(day) + this.dateDelim + this.months[month].substr(0,3) + this.dateDelim + year;
    case 'ddmmyyyy':
      return padZero(day) + this.dateDelim + padZero(month+1) + this.dateDelim + year;
    case 'mmddyyyy':
      return padZero((month+1)) + this.dateDelim + padZero(day) + this.dateDelim + year;
    case 'yyyymmdd':
      return year + this.dateDelim + padZero(month+1) + this.dateDelim + padZero(day);
    default: alert('unsupported date format');
  }
}

Calendar.prototype.writeString = function(str) {
  if (browser.dom || browser.ie) {
    this.containerLayer.innerHTML = str;
  }
}
	
Calendar.prototype.show = function(event, targetID, bHasDropDown, dateFormat, dateFrom, dateTo) {
  // calendar can restrict choices between 2 dates, if however no restrictions
  // are made, let them choose any date between 1900 and 3000
  this.setCurrent();
  this.targetID = targetID;
  this.dateFrom = dateFrom || new Date(1900,0,1);
  this.dateFromDay = padZero(this.dateFrom.getDate());
  this.dateFromMonth = padZero(this.dateFrom.getMonth());
  this.dateFromYear = this.dateFrom.getFullYear();
  this.dateTo = dateTo || new Date(3000,0,1);
  this.dateToDay = padZero(this.dateTo.getDate());
  this.dateToMonth = padZero(this.dateTo.getMonth());
  this.dateToYear = this.dateTo.getFullYear();
  this.hasDropDown = bHasDropDown;
  this.dateFormat = dateFormat || 'dd-mmm-yyyy';
  switch (this.dateFormat){
    case 'dd-mmm-yyyy':
    case 'dd-mm-yyyy':
    case 'yyyy-mm-dd':
      this.dateDelim = '-';
      break;
    case 'dd/mm/yyyy':
    case 'mm/dd/yyyy':
    case 'dd/mmm/yyyy':
      this.dateDelim = '/';
      break;
  }
	
  if (browser.dom || browser.ie){
    if (this.containerLayer.style.visibility == 'visible') {
      this.containerLayer.style.visibility = 'hidden';
      return;
    }  
  }

  if ( ! event ) { event = window.event; }
  var posOffset = [event.pageX, event.pageY];
  if (this.position != "mouse") {
    var posElement = document.getElementById(this.attacheToID);
    if (posElement) {
      posOffset = positionedOffset(posElement);
      switch (this.position) {
        case "top-right" :
          posOffset[0] += posElement.offsetWidth;
          break;
        case "bottom-left" :
          posOffset[1] += posElement.offsetHeight;
          break;
        default:
          posOffset = [event.pageX, event.pageY];
      }
    }
  }
  this.containerLayer.style.left = posOffset[0];
  this.containerLayer.style.top  = posOffset[1];
try {
  var target = document.getElementById(this.targetID);
  var value = target ? "" + target.value : "";
  var tmpArray = value.split(this.dateDelim);
  if (tmpArray.length == 3) {
    switch (this.dateFormat) {
      case 'dd-mmm-yyyy':
      case 'dd/mmm/yyyy':
        for (var i=0; i<this.months.length; i++) {
          if (tmpArray[1].toLowerCase() == this.months[i].substr(0,3).toLowerCase()) {
            this.month = this.oMonth = i;
            break;
          }
        }
        this.day = parseInt(tmpArray[0],10);
        this.year = this.oYear = parseInt(tmpArray[2],10);
        break;
      case 'dd/mm/yyyy':
      case 'dd-mm-yyyy':
        this.month = this.oMonth = parseInt(tmpArray[1]-1,10); 
        this.day = parseInt(tmpArray[0],10);
        this.year = this.oYear = parseInt(tmpArray[2],10);
        break;
      case 'mm/dd/yyyy':
      case 'mm-dd-yyyy':
        this.month = this.oMonth = parseInt(tmpArray[0]-1,10);
        this.day = parseInt(tmpArray[1],10);
        this.year = this.oYear = parseInt(tmpArray[2],10);
        break;
      case 'yyyy-mm-dd':
        this.month = this.oMonth = parseInt(tmpArray[1]-1,10);
        this.day = parseInt(tmpArray[2],10);
        this.year = this.oYear = parseInt(tmpArray[0],10);
        break;
    }
  } else if (this.initialDate) {
	     this.year = this.oYear = this.initialDate.getFullYear();
	     this.month = this.oMonth = this.initialDate.getMonth();
	     this.day = this.oDay = this.initialDate.getDate();
	  } else { // no date set, default to today
	    var theDate = new Date();
	     this.year = this.oYear = theDate.getFullYear();
	     this.month = this.oMonth = theDate.getMonth();
	     this.day = this.oDay = theDate.getDate();
	  }
} catch(e) {
}

	  this.writeString(this.buildString());
	  
	  // and then show it!
	  if (browser.dom || browser.ie) {
	      this.containerLayer.style.visibility = 'visible';
	  }
	}
	
Calendar.prototype.hide = function() {
  try {
    this.containerLayer.style.visibility = 'hidden';
  } catch(e) {}
}

Calendar.prototype.showIt = function(show) {
  try {
    this.containerLayer.style.visibility = show ? 'visible' : 'hidden';
  } catch(e) {}
}
	
function handleDocumentClick(e) {
  try {
    if (browser.ie) {e = window.event;}
    var posX = pointerX(e);
    var posY = pointerY(e);
    var posLeft = parseInt(g_Calendar.containerLayer.style.left, 10);
    var posTop  = parseInt(g_Calendar.containerLayer.style.top,  10);
    var width   = g_Calendar.containerLayer.offsetWidth;
    var height  = g_Calendar.containerLayer.offsetHeight;
    var inside = (posX >= posLeft) && (posX <= posLeft + width);
    inside = inside && (posY >= posTop) && (posY <= posTop + height);
    if ( ! inside ) {
      if (browser.dom) {
        var name = e.target.name;
        if (name != 'imgCalendar' && name != 'month' && name != 'year' && name != 'calendar') {
          g_Calendar.hide();
        }
      } else if (browser.ie) {
        var name = e.srcElement.name;
        if (name != 'imgCalendar' && name != 'month' && name != 'year' & typeof(e.srcElement) != 'object') {
          g_Calendar.hide(); 
        }
      }
    }
  } catch (e) {
  }
}
	
function padZero(num) {
  return ((num <= 9) ? ("0" + num) : num);
}

Date.isLeapYear = function(year) {
  return year % 4 == 0 && ((year % 100 != 0) || (year % 400 == 0));
}

Date.daysInYear = function(year) {
  return Date.isLeapYear(year) ? 366 : 365;
}

Date.prototype.addDays = function(num){
  return new Date((num * (1000*60*60*24)) + this.valueOf());
}	

// pointerX, pointerY, positionedOffset
// based on code from http://wiki.script.aculo.us

function pointerX(event) {
  return event.pageX || (event.clientX +
    (document.documentElement.scrollLeft || document.body.scrollLeft));
}

function pointerY(event) {
  return event.pageY || (event.clientY +
    (document.documentElement.scrollTop || document.body.scrollTop));
}

function positionedOffset(element) {
  var valueT = 0, valueL = 0;
  do {
    valueT += element.offsetTop  || 0;
    valueL += element.offsetLeft || 0;
    element = element.offsetParent;
    if (element) {
      var p = element.style.position;
      if (p == 'relative' || p == 'absolute') break;
    }
  } while (element);
  return [valueL, valueT];
}
	  
// events capturing, careful you don't override this by setting something in the onload event of 
// the body tag
window.document.onclick = handleDocumentClick;



    window.onerror = function(msg,url,line){
	  alert('******* an error has occurred ********' +
	  + '\nError details'
	  + '\nText:' + msg + '\nurl:' + url + '\nline:' + line);
	}

