/******************************************************************

Library Calendar
(c) 2007 Websolvers, Inc.

By Michael Swain

These librarys may only be used with permission from Websolvers.

******************************************************************/

var monthName = new Array(
		new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"),
		new Array("Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"),
		new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
	);
var weekdayName = new Array(
		new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"),
		new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"),
		new Array("S", "M", "T", "W", "T", "F", "S")
	);
var todayName = "Today";
var calBaseId = "dhtmlCal";
var calBaseIdx = 0;
var calBaseTag = "INPUT";
var calApplyClass="calendar";
var calzIndex = 100;
var calIEzIndexFix = calzIndex-1;
var calShared = new Object();

{for(var i = 0; i < monthName.length; i++) {
	var w = 0;
	for(var j = 0; j < monthName[i].length; j++) {
		if(monthName[i][j].length > w) {
			w = monthName[i][j].length;
		}
	}
	monthName[i].maxLength = w;
}}
{for(var i = 0; i < weekdayName.length; i++) {
	var w = 0;
	for(var j = 0; j < weekdayName[i].length; j++) {
		if(weekdayName[i][j].length > w) {
			w = weekdayName[i][j].length;
		}
	}
	weekdayName[i].maxLength = w;
}}

if(!window.getElementFor) {
function getElementFor(elm) {
	if(!elm.htmlFor) {
		return elm.getAttribute("for");
	} else {
		return elm.htmlFor;
	}
}
}

if(!(new Array()).indexOf) {
  Array.prototype.indexOf = function(search) {
    for(var i = 0; i < this.length; i++)
      if(this[i] == search)
        return i;
        
    return -1;
  }
}

if(!window.getElementStyle) {
function getElementStyle(elm) {
  if(elm.currentStyle)
    return elm.currentStyle;
  else if(document.defaultView && document.defaultView.getComputedStyle)
    return document.defaultView.getComputedStyle(elm,null);
  else
    return elm.style;
}
}
if(!window.setElementClass) {
function setElementClass(elm, className) {
  if(!elm.className && elm.className != "")
    elm.setAttribute("class", className);
  else
    elm.className = className;
}
}

if(!window.getElementClass) {
function getElementClass(elm) {
  if(!elm.className)
    return elm.getAttribute("class");
  else
    return elm.className;
}
}

if(!window.addPageLoadHandler) {
function addPageLoadHandler(func) {
	if(window.addEventListener) {
	    window.addEventListener("load", func, false);
	} else if(window.attachEvent) {
	    window.attachEvent("onload", func);
	} else if(document.getElementById) {
		if(!runPageLoadHandler.handlers)
			runPageLoadHandler.handlers = array();
		if(window.onload && window.onload != runPageLoadHandler)
			runPageLoadHandler.handlers[runPageLoadHandler.handlers.length] = window.onload;
			
	    window.onload = runPageLoadHandler;
		
		runPageLoadHandler.handlers[runPageLoadHandler.handlers.length] = func;
	}
}

function runPageLoadHandler(e) {
	var ret = true;
	
	for(var i = 0; i < runPageLoadHandler.handlers.length; i++)
		if(runPageLoadHandler.handlers[i] && !runPageLoadHandler.handlers[i](e))
			ret = false;
	
	return ret;
}
}

if(!window.applyFuncByTagClass) {
function applyFuncByTagClass(aryTagNames, aryClassNames, funcBuilder) {
	if(!funcBuilder)
		return;

	if(!aryTagNames || !aryTagNames.length)
		return;
	else if(!aryTagNames.join)
		aryTagNames = new Array(aryTagNames);
		
	if(!aryClassNames || !aryClassNames.length)
		return;
	else if(!aryClassNames.join)
		aryClassNames = new Array(aryClassNames);
		
	var aryElms = new Array();
	var tagIdx = 0;
	for(var tag = 0; tag < aryTagNames.length; tag++) {
		var aryTagElms = document.getElementsByTagName(aryTagNames[tag]);
		for(var elm = 0; elm < aryTagElms.length; elm++) {
			var classNames = getElementClass(aryTagElms[elm]);
			if(classNames && classNames.length) {
				classNames = classNames.split(' ');
				
				var match = false;
				for(var cls = 0; cls < aryClassNames.length; cls++) {
					if(match)
						break;
					for(var elmCls = 0; elmCls < classNames.length; elmCls++) {
						if((classNames[elmCls] == aryClassNames[cls])
							|| (classNames[elmCls].substring(0, aryClassNames[cls].length+1) == aryClassNames[cls]+'-')) {
							var tagElm = new Object();
							
							tagElm.match = aryClassNames[cls];
							tagElm.element = aryTagElms[elm];
							tagElm.params = classNames[elmCls].substring(aryClassNames[cls].length+1, classNames[elmCls].length).split('-'); 
							
							aryElms[aryElms.length] = tagElm;
							match = true;
							break;
						}
					}
				}
			}
		}
	}
	
	for(var elm = 0; elm < aryElms.length; elm++) {
		funcBuilder(aryElms[elm].match, aryElms[elm].element, aryElms[elm].params);
	}
}
}

if(!window.setPropWatch) {
function setPropWatch(elm, prop, handler) {
    elm.onwatch = handler;
    elm.watch(prop, handler);
}
}

function calCalcSizes(elm) {
  var i = 0, ni = 0, w = 0, tw = 0, cw = 0, yw = 0;
  var c = null, t = '', y = '8888';
  
  if(elm.month.monthIdx || elm.month.yearLen)
    return;

  for(var i = 0; i < elm.day.length; i++) {
    elm.day[i].innerHTML = '88';
  }

	ni = 0;
	tw = 0;
	c = elm.dow[0];
	cw = 0;
	while(ni + 1 < weekdayName.length && c.offsetWidth > cw) {
		t = '';
		while(t.length < weekdayName[ni].maxLength) {
			t += "W";
		}
		c.innerHTML = '';
		cw = c.offsetWidth;
		c.innerHTML = t;
		if(c.offsetWidth > cw) {
			ni++;
			cw = 0;
		}
	}
	elm.dow.nameIndex = ni;
	t = '';
	while(t.length < weekdayName[ni].maxLength) {
		t += "W";
	}
	for(i = 0; i < elm.dow.length; i++) {
		elm.dow[i].innerHTML = t;
	}
  
	ni = 0;
	tw = 0;
	c = elm.month;
	cw = 0;
	while(ni + 1 < monthName.length && c.offsetWidth > cw) {
		t = '';
		while(t.length < weekdayName[ni].maxLength) {
			t += "W";
		}
		c.innerHTML = '';
		cw = c.offsetWidth;
		c.innerHTML = t + '&nbsp;' + y;
		if(c.offsetWidth > cw) {
			ni++;
			cw = 0;
		}
	
	}
	
	elm.month.nameIndex = ni;
	elm.month.yearLen = 4;
	
	// work around the div taking up all space
	// I force absolute to get the render size
	// then force that size as an inline element
	if(getElementStyle(elm).position != "absolute") {
		elm.style.position = "absolute";
		w = elm.offsetWidth;
		elm.style.position = "relative";
		elm.style.width = w + "px";
	}
}

function buildCalElement(elm) {
  var t, r, c, b, h, f;
  var i = 0, w = 0, x;

  t = document.createElement("TABLE");
  t.cellPadding = 0;
  t.cellSpacing = 0;
  b = document.createElement("TBODY");
  t.appendChild(b);
  elm.appendChild(t);
  h = t.createTHead();
  f = t.createTFoot();
  
  elm.day = new Array();
  elm.day.length = 42;
  r = b.insertRow(0);
  for(i = 0; i < 42; i++) {
    if(i && !(i % 7))
      r = b.insertRow(0);
    elm.day[41-i] = c = r.insertCell(0);
    c.innerHTML = '&nbsp;';
    c.calendar = elm;
    c.onclick = function() { setCalElmDate(this.calendar, this.date, this.date, this.calendar.field); };
  }  

  elm.dow = new Array();
  r = h.insertRow(0);
  setElementClass(r, "weekday");
  w = 0;
  for(i = 0; i < 7; i++) {
    c = r.insertCell(0);
    elm.dow[6-i] = c;
    c.innerHTML = '&nbsp;';
  }

  r = h.insertRow(0);
  c = r.insertCell(0);
  setElementClass(c, "next");
  c.innerHTML = '&nbsp;';
  c.calendar = elm;
  c.onclick = function() { setCalElmDate(this.calendar, this.date); };
  elm.next = c;
  c = r.insertCell(0);
  setElementClass(c, "month");
  c.innerHTML = '&nbsp;';
  c.colSpan=5;
  elm.month = c;
  c = r.insertCell(0);
  setElementClass(c, "prev");
  c.innerHTML = '&nbsp;';
  c.calendar = elm;
  c.onclick = function() { setCalElmDate(this.calendar, this.date); };
  elm.prev = c;
  
  r = f.insertRow(0);
  c = r.insertCell(0)
  setElementClass(c, "next");
  c.innerHTML = '&nbsp;';
  c.calendar = elm;
  c.onclick = function() { setCalElmDate(this.calendar, this.date); };
  elm.nextYear = c;
  c = r.insertCell(0);
  setElementClass(c, "today");
  c.innerHTML = todayName;
  c.colSpan=5;
  elm.today = c;
  c.calendar = elm;
  c.onclick = function() { var now = (new Date()).getTime(); setCalElmDate(this.calendar, now, now, this.calendar.field); };
  c.onmouseover = function() { var now = new Date(); this.title = weekdayName[0][now.getDay()] + ', ' + monthName[0][now.getMonth()] + ' ' + now.getDate() + ', ' + now.getFullYear(); };
  c = r.insertCell(0)
  setElementClass(c, "prev");
  c.innerHTML = '&nbsp;';
  c.calendar = elm;
  c.onclick = function() { setCalElmDate(this.calendar, this.date, this.calendar.date); };
  elm.prevYear = c;
  
  
}

function getCalSharedDates(elm, selectTime) {
    var aryShare = null;
    
    if(elm['P_shared']) {
        aryShare = calShared["C_" + elm["P_shared"]];
    }
    
    if(!aryShare) {
        return null;
    }
    
    var aryDates = new Array();
    
    for(var i = 0; i < aryShare.length; i++)
        if(aryShare[i].date && aryShare[i] != elm)
            aryDates[aryDates.length] = aryShare[i].date;
        else if(aryShare[i] == elm && selectTime)
            aryDates[aryDates.length] = selectTime;
        
    
    return aryDates.sort(function(a,b) { return (a-b); });
}

function updateCalSharedDates(elm, selectTime) {
    var aryShare = null;
    
    if(elm['P_shared']) {
        aryShare = calShared["C_" + elm["P_shared"]];
    }
    
    if(!aryShare) {
        return null;
    }

    for(var i = 0; i < aryShare.length; i++)
        if(aryShare[i] != elm)
            setCalElmDate(aryShare[i], aryShare[i].date);
}

function setCalElmDate(elm, renderTime, selectTime, field) {
  var i = 0;
  var dtRender = null;
  var dtStart = null;
  var nowTime = new Date();

  // need to work around I.E. tomfoolery
  // it does not properly setup TD attributes
  // until after page load!!!
  if(!elm.month.offsetWidth) {
    window.setTimeout("setCalElmDate(document.getElementById('"+elm.id+"'), "+(renderTime && renderTime.getMonth ? renderTime.getTime() : renderTime)+", "+(selectTime && selectTime.getMonth ? selectTime.getTime() : selectTime)+");", 100);
    return;
  }

  if(!renderTime || isNaN(renderTime))
    dtRender = new Date();
  else if(!renderTime.getMonth)
    dtRender = new Date(renderTime);

  if(!selectTime || isNaN(selectTime))
    selectTime = elm.date;
  else if(!selectTime.getMonth)
    selectTime = (new Date(selectTime)).getTime();

  calCalcSizes(elm);
     
  dtRender.setHours(0, 0, 0, 0);
  dtStart = new Date(dtRender.getTime());
  
  nowTime.setHours(0, 0, 0, 0);
  nowTime = nowTime.getTime();
  
  dtStart.setHours(0, 0, 0, 0);
  elm.prev.date = new Date(dtStart);  
  elm.prev.date.setDate(0);
  elm.prev.date.setDate(dtStart.getDate());
  if(elm.prev.date.getMonth() == dtStart.getMonth())
    elm.prev.date.setDate(0);
  elm.prev.title = monthName[0][elm.prev.date.getMonth()] + ' ' + elm.prev.date.getFullYear();
  elm.prev.date = elm.prev.date.getTime();
  elm.month.innerHTML = monthName[elm.month.nameIndex][dtRender.getMonth()] + '&nbsp;' + dtRender.getFullYear().toString().substring(4 - elm.month.yearLen, 4);
  elm.month.title = monthName[0][dtRender.getMonth()] + ' ' + dtRender.getFullYear();
  elm.next.date = new Date(dtStart);  
  elm.next.date.setMonth(dtStart.getMonth()+1);
  if(elm.next.date.getMonth() - 1 > dtStart.getMonth() || (dtStart.getMonth() == 10 && elm.next.date.getMonth() == 0))
    elm.next.date.setDate(0);
  elm.next.title = monthName[0][elm.next.date.getMonth()] + ' ' + elm.next.date.getFullYear();
  elm.next.date = elm.next.date.getTime();

  elm.prevYear.date = new Date(dtStart);
  elm.prevYear.date.setYear(elm.prevYear.date.getFullYear()-1);
  if(elm.prevYear.date.getMonth() != dtStart.getMonth())
    elm.prevYear.date.setDate(0);
  elm.prevYear.title = monthName[0][elm.prevYear.date.getMonth()] + ' ' + elm.prevYear.date.getFullYear();
  elm.prevYear.date = elm.prevYear.date.getTime();
  elm.nextYear.date = new Date(dtStart);  
  elm.nextYear.date.setYear(elm.nextYear.date.getFullYear()+1);
  if(elm.nextYear.date.getMonth() != dtStart.getMonth())
    elm.nextYear.date.setDate(0);
  elm.nextYear.title = monthName[0][elm.nextYear.date.getMonth()] + ' ' + elm.nextYear.date.getFullYear();
  elm.nextYear.date = elm.nextYear.date.getTime();

  for(i = 0; i < elm.dow.length; i++) {
    elm.dow[i].innerHTML = weekdayName[elm.dow.nameIndex][(i+elm.sow)%7];
	elm.dow[i].title = weekdayName[0][(i+elm.sow)%7];
  }

  dtStart.setDate(1);
  if(dtStart.getDay() < elm.sow)
    dtStart.setDate(-5);
  if(dtStart.getDay() > elm.sow)
    dtStart.setDate(elm.sow-dtStart.getDay()+1);

  var shared = getCalSharedDates(elm, selectTime);
  var sharedStart = 0;
  var sharedEnd = 0;
  var sharedIdx = 0;
  if(shared && shared.length) {
    sharedStart = shared[0];
    sharedEnd = shared[shared.length-1];
  }

  for(i = 0; i < elm.day.length; i++) {
    var time = dtStart.getTime();
    var elmClass = "";
    if(shared && shared.length) {
        while(sharedIdx < length && shared[sharedIdx] < time)
            sharedIdx++;
    }

    if(dtStart.getMonth() < dtRender.getMonth() || dtStart.getFullYear() < dtRender.getFullYear())
        elmClass += " prev";
    else if(dtStart.getMonth() > dtRender.getMonth() || dtStart.getFullYear() > dtRender.getFullYear())
        elmClass += " next";
    
    if(time >= sharedStart && time <= sharedEnd) {
        if(time == sharedStart || time == sharedEnd || (sharedIdx < shared.length && time == shared[sharedIdx]))
            elmClass += " shared";
        else
            elmClass += " sharing";
    }

    if(time == nowTime)
        elmClass += " today";

    if(selectTime && time == selectTime)
        elmClass += " selected";
    
    setElementClass(elm.day[i], elmClass);

    elm.day[i].innerHTML = dtStart.getDate();
	elm.day[i].title = weekdayName[0][dtStart.getDay()] + ', ' + monthName[0][dtStart.getMonth()] + ' ' + dtStart.getDate() + ', ' + dtStart.getFullYear();
    elm.day[i].date = time;
    dtStart.setDate(dtStart.getDate()+1);
  }

  if(selectTime && selectTime != elm.date) {
    elm.date = selectTime;

    updateCalSharedDates(elm, selectTime);

    if(field) {
        var dtSel = new Date(selectTime);
        var strDate = (dtSel.getMonth()+1) + '/' + dtSel.getDate() + '/' + dtSel.getFullYear();
        if(field.value != strDate) {
            field.value = strDate;
        }
    }
  }
  
}

function calendar_fieldOnkeyup(e) {
    if(this.calendar) {
	    dt = Date.parse(this.value);
	    if(!dt || isNaN(dt))
		    dt = null;

        if(dt != null && this.calendar.date != dt) {
            setCalElmDate(this.calendar, dt, dt);
        }
    }

    if(this._cal_onkeyup)
        return this._cal_onkeyup(e);
        
    return true;
}

function calendar_fieldOnFocus(e) {
    this.showCalendar()

	if(this._cal_onfocus)
		return this._cal_onfocus(e);
		
	return true;
}

function calendar_fieldOnBlur(e) {
    this.hideCalendar();

	if(this._cal_onblur)
		return this._cal_onblur(e);
		
    return true;
}

function calendar_fieldOnpropchangeTest(e) {
    var elm = event.srcElement;
    
    elm.onpropertychange = null;
    elm._cal_propchangeworked = 1;
    elm.onpropertychange = null;
    
    return false;
}

function calendar_fieldOnpropchange(e) {
    var elm = event.srcElement;

    if(event.propertyName == "value") {
        if(elm.calendar) {
	        dt = Date.parse(elm.value);
	        if(!dt || isNaN(dt))
		        dt = null;

            if(dt != null && elm.calendar.date != dt) {
                setCalElmDate(elm.calendar, dt, dt);
            }
        }
    }
    
    if(this._cal_onpropchange)
        return this._cal_onpropchange(e);
        
    return true;
}

function calendar_fieldValueWatch(prop, oldval, newval) {
    if(prop == "value") {
        if(this.calendar) {
	        dt = Date.parse(newval);
	        if(!dt || isNaN(dt))
		        dt = null;

            if(dt != null && this.calendar.date != dt) {
                setCalElmDate(this.calendar, dt, dt);
            }
        }
    }
    
    if(this._cal_watch)
        return this._cal_watch(prop, oldval, newval);
        
    return newval;
}

function buildCalField(classMatch, element, parameters) {
	var calendar = document.createElement("DIV");
	var calClass = "calendar";

	if(parameters && parameters.length) {
		for(var param = 0; param < parameters.length; param++) {
		    switch(parameters[param]) {
		    case "shared":
		        if(param+1 < parameters.length) {
		            calendar["P_shared"] = parameters[++param].toLowerCase();
		        }
		        break;
		    default:
			    calendar["P_" + parameters[param].toLowerCase()] = 1;
			}
		}
	}

	var matchParam = classMatch.split('-');
	if(matchParam.length > 1) {
		calClass = matchParam[matchParam.length-1];
	}
	
	calendar.id = calBaseId+(calBaseIdx++);
	calendar.style.zIndex = calzIndex;
	calendar.sow = 0;

	element.calendar = calendar;
	calendar.field = element;

	setElementClass(calendar, calClass);

	for(i = 0; i < weekdayName[0].length; i++) {
		if(calendar["P_" + weekdayName[0][i].toLowerCase()]) {
			calendar.sow = i;
		}
	}

	if(calendar["P_focus"]) {
	    var container = document.createElement("SPAN");
	    container.style.position = "relative";
		if(document.all) { //cheap IE check, should  not harm "IE compatible" browsers.
			container.style.zIndex = calIEzIndexFix--;
		}
	    container.id = calBaseId+(calBaseIdx)+"Container";
        element.parentNode.insertBefore(container, element);
        container.appendChild(element);
        container.appendChild(calendar);
	
		calendar.style.position = 'absolute';
		calendar.style.visibility = 'hidden';
		calendar.style.left = "0";
		calendar.style.top = element.offsetHeight + "px";

		calendar.onmouseover = calendar_over;
		calendar.onmouseout = calendar_out;
		
		element.showCalendar = element_showCalendar;
		element.hideCalendar = element_hideCalendar;
		
		element._cal_onfocus = element.onfocus;
		element.onfocus = calendar_fieldOnFocus;
		element._cal_onblur = element.onblur;
		element.onblur = calendar_fieldOnBlur;
	} else {
	    if(element.nextSibling) {
		    element.parentNode.insertBefore(calendar, element.nextSibling);
	    } else {
		    element.parentNode.appendChild(calendar);
	    }
	}

    if(element.watch) {
        element._cal_watch = element.onwatch;
        setPropWatch(element, "value", calendar_fieldValueWatch);
        
	    element._cal_onkeyup = element.onkeyup;
        element.onkeyup = calendar_fieldOnkeyup;
	} else {
	    element._cal_onpropchange = element.onpropertychange;
	    element.onpropertychange = calendar_fieldOnpropchangeTest;
	    
	    var test = element.value;
	    if(test == " ") {
	        element.value = "";
	    } else {
	        element.value = " ";
	    }
	    element.value = test;
	    
	    if(!element._cal_propchangeworked) {
    	    element._cal_onkeyup = element.onkeyup;
	        element.onkeyup = calendar_fieldOnkeyup;
	    } else {
    	    element.onpropertychange = calendar_fieldOnpropchange;
	    }
	}

	buildCalElement(calendar);

    if(calendar["P_shared"]) {
        if(!calShared["C_" + calendar["P_shared"]]) {
            calShared["C_" + calendar["P_shared"]] = new Array();
        }
        calShared["C_" + calendar["P_shared"]][calShared["C_" + calendar["P_shared"]].length] = calendar;
    }
  
	dt = Date.parse(element.value);
	if(!dt || isNaN(dt))
		dt = null;
  
	setCalElmDate(calendar, dt);
}

function calendar_over(e) {
	this._mouseover = 1;
}

function calendar_out(e) {
	this._mouseover = 0;
	this.field.focus();
}

function element_showCalendar() {
	this.calendar.style.visibility = 'visible';
}

function element_hideCalendar() {
	if(!this.calendar._mouseover) {
		this.calendar.style.visibility = 'hidden';
	}
}

function initLibCalendar() {
    applyFuncByTagClass(calBaseTag, "apply-" + calApplyClass, buildCalField);
}

addPageLoadHandler(initLibCalendar);
