var CALENDAR_FREQUENCY = 500;
var DAY_LENGTH = (24 * 60 * 60 * 1000);
var DAY_NAME_ROW_INDEX = 1;
var FIRST_WEEK_ROW_INDEX = 2;

var g_prevMouseDown = null;
var g_calendarControl = null;

function isIE()
{
	var browserName = navigator.appName;
	if (browserName == "Microsoft Internet Explorer")
		return true;
	return false;
}


function isDST(theDate)
{
    var theTime = theDate.toTimeString().toLowerCase();
    var isDST = false;
    if (isIE())
    {
		if (theTime.length > 9)
		{
			theTime = theTime.substr(9); //trim off the time so we just have the time zone
			if (theTime.length > 1 && theTime.indexOf("d") > -1)
			{
				isDST = true;
			}
		}
	}
    else //handle W3C compliant browsers
    {
    	if (theTime.indexOf("daylight") > -1)
    	{
    		isDST = true;
    	}
    }
	return isDST;
}

function CalendarDay(date) {
    this.date = new Date(date.getTime());

    this.getDay = getDay;
    this.isSameMonth = isSameMonth;
    this.isSameDay = isSameDay;
    this.isAfter = isAfter;

    function getDay() {
        if (this.date != null) {
            return this.date.getDate();
        }
        return 0;
    }

    function isSameMonth(date) {
        return ((this.date.getFullYear() == date.getYear())
        	&& (this.date.getMonth() == date.getMonth()));
    }
    
    function isSameDay(date) {
    	return (this.date.getTime() == date.getTime());
    }

    function isAfter(date) {
        var after = true;
        if ((this.date != null) && (date != null)) {
            after = (this.date.getTime() > date.getTime());
        }
        return after;
    }
}

function CalendarMonth(month, year) {
	var date = new Date();
	date.setFullYear(year, month, 1);
    this.month = date.getMonth();
    this.year = date.getFullYear();

    this.getMonth = getMonth;
    this.getYear = getYear;
    this.getWeeks = getWeeks;
    this.getMonthName = getMonthName;
    this.getFirstWeek = getFirstWeek;
    this.isSameMonthAs = isSameMonthAs;
    this.isAfter = isAfter;

    function getMonth() {
        return this.month;
    }

    function getYear() {
        return this.year;
    }

    function getWeeks() {
        var weeks = new Array();
        var date = this.getFirstWeek();

        do {
            var week = new Array();
            for (var i = 0; i < 7; i++) {
            	week[week.length] = new CalendarDay(date);
            	if (month == 10)
            	{
            		if (isDST(date))
                		date.setTime(date.getTime() + DAY_LENGTH*2);
					else
						date.setTime(date.getTime() + DAY_LENGTH);
				}
				else
					date.setTime(date.getTime() + DAY_LENGTH);
            }
            weeks[weeks.length] = week;
        } while (date.getMonth() == this.month);

        return weeks;
    }

    function getMonthName() {
        return monthNamesAbrev[this.month];
    }

    function getFirstWeek() {
        var firstWeek = new Date(this.year, this.month, 1, 0, 0, 0);
        while (firstWeek.getDay() > 0) {
            firstWeek.setTime(firstWeek.getTime() - DAY_LENGTH);
        }
        return firstWeek;
    }

    function isSameMonthAs(date) {
        return ((date.getFullYear() == this.getYear()) &&
            (date.getMonth() == this.getMonth()));
    }
    
    function isAfter(date) {
    	var thisDate = new Date(this.getYear(), this.getMonth(), 1, 0, 0, 0);
    	return (date.getTime() < thisDate.getTime());
    }
}

function CalendarControl(selectFunc, cancelFunc, allowFuture, allowPast) {
	this.selectFunc = selectFunc;
	this.cancelFunc = cancelFunc;
	this.allowFuture = allowFuture;
	this.allowPast = allowPast;
	
	this.calElement = document.getElementById("calCtrlTable");
	this.calCtrl = document.getElementById("calCtrlObj");
	this.titleElement = document.getElementById("calCtrlTitle");
	this.forwardArrow = document.getElementById("calCtrlForwardArrow");
	this.backArrow = document.getElementById("calCtrlBackArrow");
	
	this.currentMonth = null;
	
	this.setMonth = setMonth;
	this.canGoBack = canGoBack;
	this.canGoForward = canGoForward;
	this.canSelect = canSelect;
	this.goBack = goBack;
	this.goForward = goForward;
	this.selectDay = selectDay;
	this.handleMouseDown = handleMouseDown;
	this.show = show;
	this.hide = hide;
	this.init = init;
	
	this.init();
	
	function init() {
	    var initComplete = false;
	    if ((this.calCtrl != null) && (this.calElement != null)) {
            var dayNameRow = this.calElement.rows[DAY_NAME_ROW_INDEX];
            if (dayNameRow != null) {
            	var col = 0;
            	for (var i = 0; i < dayNameRow.childNodes.length; i++) {
            		var cell = dayNameRow.childNodes[i];
            		if ("TD" == cell.nodeName) {
                        var content = cell.firstChild;
                        if (content != null) {
                            content.nodeValue = dayNameLetters[col];
                        } else {
                            break;
                        }
            			col++;
                    }
                }
                if (7 == col) {
	                initComplete = true;
                }
            }
        }
	    if (initComplete) {
	        g_calendarControl = this;
	        g_prevMouseDown = document.onmousedown;
	        document.onmousedown = calCtrlHandleMouseDown;
	    }
	}
	
	function setMonth(month) {
	    if (this.calElement != null) {
	        this.currentMonth = month;
	        
	        var now = new Date();
	        now = new Date(now.getFullYear(), now.getMonth(), now.getDate());
	
	        if (this.titleElement != null) {
	            this.titleElement.firstChild.nodeValue =
	                month.getMonthName() + " " + month.getYear();
	        }
	        
	        if (this.forwardArrow != null) {
	        	if (this.canGoForward(now)) {
                	setElementStyle(this.forwardArrow, "cursor", "pointer");
                	setElementStyle(this.forwardArrow, "cursor", "hand");
	        	} else {
                	setElementStyle(this.forwardArrow, "cursor", "auto");
	        	}
	        }
	        if (this.backArrow != null) {
	        	if (this.canGoBack(now)) {
                	setElementStyle(this.backArrow, "cursor", "pointer");
                	setElementStyle(this.backArrow, "cursor", "hand");
	        	} else {
                	setElementStyle(this.backArrow, "cursor", "auto");
	        	}
	        }
			
	        var weeks = month.getWeeks();
	        for (var i = 0; i < 6; i++) {
	            var weekElem = this.calElement.rows[i + FIRST_WEEK_ROW_INDEX];
	            if (null == weekElem)
	                continue;
	
	            var week = weeks[i];
	            if (week != null) {
	                setElementStyle(weekElem, "display", "");
	                var dayIndex = 0;
	                for (var j = 0; j < weekElem.childNodes.length; j++) {
	                	var dayElem = weekElem.childNodes[j];
	                	if ("TD" == dayElem.nodeName) {
	                    	var day = week[dayIndex];
	                		dayIndex++;
							dayElem.firstChild.nodeValue = "" + day.getDay();
	                    	if (day.isSameMonth(month)) {
	                    		if (day.isSameDay(now)) {
                            		dayElem.className = "calCtrlTargetDay";
		                    	} else if (day.isAfter(now)) {
		                        	if (this.allowFuture) {
		                            	dayElem.className = "calCtrlTargetDay";
	    	                        } else {
	        	                    	dayElem.className = "calCtrlOutOfRangeDay";
	            	                }
	                	        } else {
	                    	    	if (this.allowPast) {
	                        	    	dayElem.className = "calCtrlTargetDay";
	                            	} else {
		                            	dayElem.className = "calCtrlOutOfRangeDay";
		                            }
	    	                    }
	        	            } else {
	            	            dayElem.className = "calCtrlNonTargetDay";
	                	    }
	                	}
	                }
	            } else {
	                setElementStyle(weekElem, "display", "none");
	            }
	        }
	    }
	}
	
	function canGoBack(now) {
		var canGo = false;
		if (this.currentMonth != null) {
			if (this.allowPast) {
				canGo = true;
			} else {
				canGo = this.currentMonth.isAfter(now);
			}
	    }
	    return canGo;
	}
	
	function canGoForward(now) {
		var canGo = false;
		if (this.currentMonth != null) {
			if (this.allowFuture) {
				canGo = true;
			} else {
				canGo = (!this.currentMonth.isAfter(now)
					&& !this.currentMonth.isSameMonthAs(now));
	    	}
	    }
	    return canGo;
	}
	
	function canSelect(date, now) {
		var canSel = false;
		if (this.allowFuture) {
			canSel = (date.getTime() >= now.getTime());
		}
		if (this.allowPast) {
			canSel |= (date.getTime() <= now.getTime());
		}
		return canSel;
	}

	function goBack() {
		var now = new Date();
		if (this.canGoBack(now)) {
    		var month = new CalendarMonth(this.currentMonth.getMonth() - 1,
        		this.currentMonth.getYear());
    		this.setMonth(month);
	    }
	}
	
	function goForward() {
		var now = new Date();
		if (this.canGoForward(now)) {
	        var month = new CalendarMonth(this.currentMonth.getMonth() + 1,
	            this.currentMonth.getYear());
	        this.setMonth(month);
	    }
	}

	function selectDay(dayCell) {
	    if (dayCell != null) {
	    	if ("calCtrlTargetDay" == dayCell.className) {
	    		if ((this.currentMonth != null)
	        		&& ("function" == typeof(this.selectFunc))) {
			        var dayElem = dayCell.firstChild;
			        if (dayElem != null) {
			            var date = new Date(this.currentMonth.getYear(),
			            	this.currentMonth.getMonth(), dayElem.nodeValue, 0, 0,
			            		0);
			            var now = new Date();
			            now = new Date(now.getFullYear(), now.getMonth(),
			            	now.getDate(), 0, 0, 0);
		            	this.selectFunc(date);
			        }
			    }
        		this.hide();
		    }
	    }
	}

	function handleMouseDown(event) {
        var mouseX = 0;
        var mouseY = 0;
        if (window.event != null) {
            mouseX = window.event.clientX;
            mouseY = window.event.clientY;
            if (document.body.scrollLeft != null) {
                mouseX += document.body.scrollLeft;
            }
            if (document.body.scrollTop != null) {
                mouseY += document.body.scrollTop;
            }
        } else {
            mouseX = event.pageX;
            mouseY = event.pageY;
        }

        if (!elementContainsPoint(this.calCtrl, mouseX, mouseY)) {
            if ("function" == typeof(this.cancelFunc)) {
                this.cancelFunc();
            }
            this.hide();
        }
	}
	
	function hide() {
	    if (this.calElement != null) {
	        setElementStyle(this.calCtrl, "display", "none");
	    }
		
		document.onmousedown = g_prevMouseDown;
		g_prevMouseDown = null;
	    g_calendarControl = null;
	}
	
	function show(month, year, owner) {
        var month = new CalendarMonth(month, year);
        this.setMonth(month);
        var x = getElementXPos(owner);
        var y = getElementYPos(owner);
        var absoluteParent = getAbsoluteAncestor(owner);
        x -= getElementXPos(absoluteParent);
        y -= getElementYPos(absoluteParent);
        setElementStyle(this.calCtrl, "left", x + "px");
        setElementStyle(this.calCtrl, "top", y + "px");
        setElementStyle(this.calCtrl, "display", "block");
	}
}

function calCtrlHandleMouseDown(event) {
    if (g_prevMouseDown != null) {
        g_prevMouseDown(event);
    }

    if (g_calendarControl != null) {
    	g_calendarControl.handleMouseDown(event);
    }
}

function calCtrlSelectDay(dayCell) {
	if (g_calendarControl != null) {
		g_calendarControl.selectDay(dayCell);
	}
}

function calCtrlGoBack() {
	if (g_calendarControl != null) {
		g_calendarControl.goBack();
	}
}

function calCtrlGoForward() {
	if (g_calendarControl != null) {
		g_calendarControl.goForward();
	}
}

function showCalendar(month, year, owner, selectFunc, cancelFunc, allowFuture,
	allowPast) {
	if (g_calendarControl != null) {
		g_calendarControl.hide();
	}
	new CalendarControl(selectFunc, cancelFunc, allowFuture, allowPast);
	if (g_calendarControl != null) {
		g_calendarControl.show(month, year, owner);
	}
}