/*--------------------------------------------------------------------------------------+
 | Javascript Class - dedokoCal.js - Version 1.0                                        |
 | ---------------------------------------------                                        |
 |                                                                                      |
 | Javascript / DHTML calendar object. Can either be applied to an existing element     |
 | (using the divName parameter) or will add its own new element to the document.       |
 |                                                                                      |
 | Calendar positioning                                                                 |
 | --                                                                                   |
 | Default (trackMouse parameter true): calendar will appear at the mouse position.     |
 | Alternatively, you can set the x_orig and y_orig parameters to show the calendar at  |
 | a fixed x and / or y position. You can set trackMouse to stop the mouse tracking if  |
 | the body onmousemove action it uses conflicts with an existing one.                  |
 | The calendar will be positioned relative to its container. If the calendar element   |
 | is generated by the object, it's container is the document body. However, you can    |
 | manually include an element to receive the calendar (and pass its name in divName)   |
 | and put that in its own container.                                                   |
 | By default, the calendar should stay inside the window. If the code that handles     |
 | this causes problems, set the keepInWindow parameter to false.                       |
 |                                                                                      |
 | Usage                                                                                |
 | --                                                                                   |
 | Simplest scenario:                                                                   |
 | 1. Include this script file and a corresponding CSS stylesheet.                      |
 | 2. Create object: var dCal = new dedokoCal(divName, className);  (params optional)   |
 | 3. Call the dCal.makeCalendar() method in the window's onload action.                |
 | 4. Override the dCal.callback(timestamp) method ready to handle date selection.      |
 | 5. To open the calendar, call dCal.showCalendar(startDate)                           |
 |                                                                                      |
 | Timestamps                                                                           |
 | --                                                                                   |
 | Dates are passed to and from the object as UNIX timestamps. UNIX timestamps are in   |
 | seconds, whilst Javascript requires a value in milliseconds. So values need to be    |
 | multiplied or divided by 1000 in your Javascript.                                    |
 |                                                                                      |
 | CSS Styling                                                                          |
 | --                                                                                   |
 | When the object creates the calendar element, it gives it a class name which is held |
 | in the className parameter. By default this is 'dedokoCalClass' but you can override |
 | this to use another CSS class by setting className in the constructor.               |
 |                                                                                      |
 | What to define in CSS:                                                               |
 |  div.dedokoCalClass => container div (absolute position and hide off-screen)         |
 |  div.dedokoCalClass table => table that contains the calendar                        |
 |  div.dedokoCalClass td.dedCalHeader => table cell for calendar header / links        |
 |  div.dedokoCalClass a => for the links in the header                                 |
 |  td.dedCalCellDay => the cells containing the day names                              |
 |  td.dedCalCellOff => blank (ie not in this month) day cells                          |
 |  td.dedCalCellOn => active (ie a day in this month) day cells                        |
 |  td.dedCalCellCurrent => currently selected day cell                                 |
 |  td.dedCalCellOver => style to apply to active day cells on mouseover                |
 |                                                                                      |
 | Min / Max Date                                                                       |
 | --                                                                                   |
 | If you want to restrict the dates that can be selected, set the minDate and / or     |
 | maxDate parameters                                                                   |
 +-------------------------------------------------------------------------------------*/

function dedokoCal(divName, className) {
    // Identify object in window scope (needed for event handlers)
    this.objID = "c" + String(Math.random()).substring(2);
    this.divName = (divName && divName != "") ? divName : this.objID;
	// default dates to today to start with
    this.currDate = new Date();
    this.origDate = new Date();
    this.obj = null;
	this.className = className ? className : "dedokoCalClass";    
    this.showInitDate = true;
    this.minDate = 0;
    this.maxDate = 0;
    // Day / Month names - use PHP to overide with locale-based values for multi-lang 
    this.arrDays = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
    this.arrMonths = ['January','February','March','April','May','June','July','August','September','October','November','December'];
    // Use mouse position to determine where to show?
    this.trackMouse = true;
    this.IE = document.all?true:false;
    this.mouse_pos = {x:0,y:0};
    // Alternatively, you can specify a fixed position
    this.x_orig = null;
    this.y_orig = null;
    this.keepInWindow = true;

    
    this.makeCalendar = function() {
    	// Make sure we can get back to object when we call functions in window scope
    	window[this.objID] = this;
    	// Create div and add to document (if not already present)
    	if(!this.obj) {
    		this.obj = this.getObj(this.divName);
    		if(!this.obj) {
				var cDiv = document.createElement('div');
				cDiv.setAttribute('id',this.divName);
				document.body.appendChild(cDiv);
				this.obj = this.getObj(this.divName);
				this.obj.className = this.className;
    		}
    	}
		this.obj.style.position = "absolute";
		this.obj.style.zIndex = 100;
		this.hideCalendar();
    	// Now put some HTML in it ...
        var bLink = "<a id=\"mth_down\" style=\"float:left;\" href=\"javascript:window['" + this.objID + "'].changeMonth(-1);\">&lt;&lt;</a>";
        var fLink = "<a id=\"mth_up\" style=\"float:right;\" href=\"javascript:window['" + this.objID + "'].changeMonth(1);\">&gt;&gt;</a>";
        var html = "<table>\n <tr>\n" +
        		   "<tr><td colspan=7 class=dedCalHeader>" + bLink + fLink + "<span id=\"hdr_month\"></span>&nbsp;<span id=\"hdr_year\"></span></td></tr>\n";
        var d = this.arrDays;
        for(var i=0; i<d.length; i++) html += "  <td class=dedCalCellDay>" + d[i].substr(0,2) + "</td>\n";
        html += " </tr>\n";
        for(var w=1; w<=6; w++) {
            html += " <tr align=center>\n";
            for(var d=1; d<=7; d++) html += "  <td id=\"" + w + "_" + d + "\">&nbsp;</td>\n";
            html += " </tr>\n";
        }
        html += "</table>";
        this.obj.innerHTML = html;
        // And add the mouse tracking ...
        if(this.trackMouse) {
			eval("this.getCursorPosHandler = function(e) { window['" + this.objID + "'].getCursorPosition(e); }");
			if (!this.IE) document.captureEvents(Event.MOUSEMOVE)
			document.onmousemove = this.getCursorPosHandler;			
        }
    }
    
    this.showCalendar = function(defTime) {
    	if(!defTime) {
	    	var tmpDate = new Date();
	    	defTime = Math.round(tmpDate.getTime()/1000);
    	}
    	this.origDate = new Date(defTime * 1000);
        this.currDate = new Date(defTime * 1000);
        this.drawCalendar();
        with(this.obj.style) {
			display = 'block';
			var os;
			var x = !isNaN(os = parseInt(this.x_orig)) ?  os : this.mouse_pos.x;
			var y = !isNaN(os = parseInt(this.y_orig)) ?  os : this.mouse_pos.y;
        	// Experimental keep-it-in-the-window code
			if(this.keepInWindow) {
				if((os = document.body.offsetWidth - (x + this.obj.offsetWidth + 5)) < 0) x += os;
				if((os = document.body.offsetHeight - (y + this.obj.offsetHeight + 5)) < 0) y += os;
			}
			left = x + "px";
			top = y + "px";
		}
	}

    this.drawCalendar = function() {
        var useDate = new Date(this.currDate.getTime());
        useDate.setDate(1);
        useDate.setDate(1 - useDate.getDay());
        for(var r=1; r<=6; r++) {
            for(var c=1; c<=7; c++) {
                var d = useDate.getDate();
                var td = this.getObj(r + "_" + c);
                var bg = 'dedCalCellOff';
                if(useDate.getMonth() == this.currDate.getMonth()) {
                    td.innerHTML = d;
                    td.onmouseover = function() { this.className='dedCalCellOver'; }
                    eval("td.onclick = function() { window['" + this.objID + "'].chooseDate(" + d + "); }");
                    if(useDate.getTime() == this.origDate.getTime() && this.showInitDate) bg = "dedCalCellCurrent";
                } else {
                    td.innerHTML = "&nbsp;";
                    td.onclick = "";
                    td.onmouseover = "";
                    td.onmouseout = "";
                }
                td.className = bg;
                eval("td.onmouseout = function () { this.className='" + bg + "'; }");
                useDate.setDate(useDate.getDate()+1);
            }
        }
        var dsp = [];
        if(dsp = this.getDateStringParts()) {
            this.getObj("hdr_month").innerHTML = dsp[0];
            this.getObj("hdr_year").innerHTML = dsp[1];
        }
        if(this.minDate > 0) {
            var dl = new Date(this.minDate * 1000);
            var dlm = (dl.getYear() * 12) + dl.getMonth();
            var cdm = (this.currDate.getYear() * 12) + this.currDate.getMonth();
            this.getObj("mth_down").style.visibility = dlm == cdm ? "hidden" : "visible";
        }
        if(this.maxDate > 0) {
            var dl = new Date(this.maxDate * 1000);
            var dlm = (dl.getYear() * 12) + dl.getMonth();
            var cdm = (this.currDate.getYear() * 12) + this.currDate.getMonth();
            this.getObj("mth_up").style.visibility = dlm == cdm ? "hidden" : "visible";
        }
        this.obj.onmouseover = function() { if(window.cto != undefined) window.clearTimeout(window.cto); }
        eval("this.obj.onmouseout = function() { window.cto = setTimeout('window[\"" + this.objID + "\"].hideCalendar();',1500); }");
    }

    this.hideCalendar = function() {
		this.obj.style.display = 'none';
        if(window.cto != undefined) window.clearTimeout(window.cto);
    }

    this.chooseDate = function(pos) {
        this.currDate.setDate(pos);
        this.callback(Math.round(this.currDate.getTime()/1000));
        this.hideCalendar();
    }
    
    this.callback = function(ts) {
        alert("timestamp: " + ts + "\n\nRedefine dedokoCalendar.callback(ts) to use this value");
    }

    this.getDateStringParts = function() {
        var mths = this.arrMonths;
        return new Array(mths[this.currDate.getMonth()], this.currDate.getFullYear());
    }

    this.changeYear = function(cDir) {
        with(this.currDate) setFullYear(getFullYear() + cDir);
        this.drawCalendar();
    }

    this.changeMonth = function(cDir) {
        with(this.currDate) setMonth(getMonth() + cDir);
        this.drawCalendar();
    }
    
    this.getObj = function(name) {
        return document.getElementById(name);
    }

	// Cross-browser cursor position (works in IE with and without DOCTYPE) ...
	this.getCursorPosition = function(e) {
		if(this.IE) {		
			this.mouse_pos.x = event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
			this.mouse_pos.y = event.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
		} else {
			this.mouse_pos.x = e.pageX;
			this.mouse_pos.y = e.pageY;
		}
	}
    
}
