var global = this

function CalibrateMonthWidget (month_id, details_id, console_id) {
    if (!this instanceof CalibrateMonthWidget) {
        return new CalibrateMonthWidget ();
    }

    global.widget = this
    this.monthID    = month_id;
    this.detailsID  = details_id;
    this.consoleID  = console_id;
    this.apiHandler = null;
    this.key        = null;
    this.eventMap   = new Array ();
    this.eventRows  = null;
    this.detailsHeading = null;
    this.displayTimeInColumnP = false;
    this.todayTd = null;
    this.displayDayTd = null;
    
    this.setDetailsHeading = function (heading) {
        this.detailsHeading	= heading;
    }

    this.setTimeColumnP = function (tcp) {
        this.displayTimeInColumnP = tcp;
    }
   
    this.getEventsFromCalibrate = function (username, password, zoneID, cals) {
        this.username = username;
        this.password = password;
        this.zoneID   = zoneID;
        this.cals     = cals;
        
        var today = new Date ();
        this.getEventsForMonth (today.getFullYear(), today.getMonth()+1);
    }

    this.getEventsForMonth = function (yyyy, mm) {
        this.fromDate = new Date ();
        this.fromDate.setFullYear (yyyy, mm-1, 1);
        this.toDate = new Date ();
        if (mm == 12) {
            mm = 1;
            yyyy ++;
        }
        else {
            mm ++;
        }
        this.toDate.setFullYear (yyyy, mm-1, 1);
        this.toDate.setTime(this.toDate.getTime()-24*60*60*1000);

        this.key = this.fromDate.getFullYear() + "-" + this.fromDate.getMonth();
        if (this.eventMap[this.key] != null) {
            this.renderEventInfo (this.eventMap[this.key]);
        }
        else {
            this.apiHandler = new CalibrateAPI ();
            this.apiHandler.renderer = this;
            this.apiHandler.key = this.key;
            this.apiHandler.getEvents (this.username, this.password, 
                                        this.zoneID, this.cals, 
                                        this.fromDate, this.toDate);
        }
    }
    
    this.getEventsForPrevMonth = function (yyyy, mm) {
        if (mm == 1) {
            mm = 12;
            yyyy --;
        }
        else {
            mm --;
        }
        this.getEventsForMonth (yyyy, mm);
    }
        
    this.getEventsForNextMonth = function (yyyy, mm) {
        if (mm == 12) {
            mm = 1;
            yyyy ++;
        }
        else {
            mm ++;
        }
        this.getEventsForMonth (yyyy, mm);
    }
        
    this.dayNames = new Array ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 
                               'Thursday', 'Friday', 'Saturday');
    this.monthNames = new Array ("January", "February", "March",
                                 "April",   "May",      "June",
                                 "July",    "August",   "September",
                                 "October", "November", "December"   );
    
    
    this.displayMessage = function (message) {
        var schedule = document.getElementById(this.monthID);
        schedule.innerHTML = message;
    }
    
    this.debugMessage = function (message) {
        var div = document.getElementById(this.consoleID);
	if (div != null)
	    div.innerHTML = message;
    }
    
    this.initializeRendering = function () {
    }

    this.doRendering = function (handler) {
        var eventInfo = this.indexEventInfo (handler.eventInfo);
        this.eventMap[handler.key] = eventInfo;
        if (this.apiHandler != handler) {
            return;
        }
        this.renderEventInfo (eventInfo);
    }
    
    this.renderEventInfo = function (eventInfo) {
        var schedule = document.getElementById(this.monthID);
        schedule.innerHTML = "";
        if (this.detailsID != null) {
            var details = document.getElementById(this.detailsID);
            details.innerHTML = "";
        }
        var self = this; // Needed to get closures in callbacks

        var mm = this.toDate.getMonth ();
        var yyyy = this.toDate.getFullYear ();

        var heading = this.monthNames[mm] + " " + yyyy;

        var today = new Date ();
        var thisday = -1;
        if (today.getFullYear() == yyyy && today.getMonth() == mm) {
            thisday = today.getDate ();
        }
    
        var tab = document.createElement ("table");
        schedule.appendChild (tab);
        tab.setAttribute ("class", "cal_table");
        tab.setAttribute ("className", "cal_table");
        var thead = document.createElement ("thead");
        tab.appendChild (thead);            
        var tr = document.createElement ("tr");
        thead.appendChild (tr);
        tr.setAttribute ("class", "cal_event_heading");
        tr.setAttribute ("className", "cal_event_heading");
        var th = document.createElement ("th");
        th.setAttribute ("class", "cal_event_heading");
        th.setAttribute ("className", "cal_event_heading");
        tr.appendChild (th);
        th.colSpan = 7;
        var prev = document.createElement ("a");
        prev.appendChild (document.createTextNode ("<"));
        prev.setAttribute ("href", "");
        prev.onclick = function (s, y, m) {
                            return function () {
                                s.getEventsForPrevMonth (y, m); 
                                return false; };
                        } (self, yyyy, mm+1);
        th.appendChild (prev);
        th.appendChild (document.createTextNode (" " + heading + " "));
        var next = document.createElement ("a");
        next.appendChild (document.createTextNode (">"));
        next.setAttribute ("href", "");
        next.onclick = function (s, y, m) {
                            return function () {
                                s.getEventsForNextMonth (y, m); 
                                return false; };
                        } (self, yyyy, mm+1);
        th.appendChild (next);
        tr = document.createElement ("tr");
        thead.appendChild (tr);
        var days = new Array ("S", "M", "T", "W", "T", "F", "S");
        for (var i=0; i<days.length; i++) {
            th = document.createElement ("th");
            th.setAttribute ("class", "cal_day_heading");
            th.setAttribute ("className", "cal_day_heading");
            th.appendChild (document.createTextNode (days[i]));
            tr.appendChild (th);
        }
        var tbody = document.createElement ("tbody");
        tab.appendChild (tbody);
	this.displayDayTd = null;

        var day = 1;
        var last = this.toDate.getDate ();
        while (day <= last) {
            tr = document.createElement ("tr");
            tbody.appendChild (tr);
            var dow = 0;
            if (day == 1) {
                dow = this.fromDate.getDay ();
                for (var i=0; i<dow; i++) {
                    var td = document.createElement ("td");
                    td.setAttribute ("class", "cal_day_empty");
                    td.setAttribute ("className", "cal_day_empty");
                    tr.appendChild (td);
                }
            }
            while (dow < 7 && day <= last) {
                var td = document.createElement ("td");
                if (day == thisday) {
                    td.setAttribute ("class", "cal_day_today cal_day_selected");
                    td.setAttribute ("className", "cal_day_today cal_day_selected");
		    this.todayTd = td;
		    this.displayDayTd = td;
                }
		else if (thisday < 0 && this.displayDayTd == null) {
                    td.setAttribute ("class", "cal_day_normal cal_day_selected");
                    td.setAttribute ("className", "cal_day_normal cal_day_selected");
		    this.displayDayTd = td;
		    this.displayDayTd = td;
		}
                else {
                    td.setAttribute ("class", "cal_day_normal");
                    td.setAttribute ("className", "cal_day_normal");
                }
                var daynode = document.createTextNode (day);
                if (eventInfo[day] != null) {
                    var a = document.createElement ("a");
                    a.setAttribute ("href", "");
                    a.onclick = function (s, k, y, m, d, t) {
                                    return function () {
                                        s.renderDetails (k, y, m, d); 
					if (s.displayDayTd != null) {
					    if (s.displayDayTd == s.todayTd) {
						s.displayDayTd.setAttribute ("class", "cal_day_today");
						s.displayDayTd.setAttribute ("className", "cal_day_today");
					    }
					    else {
						s.displayDayTd.setAttribute ("class", "cal_day_normal");
						s.displayDayTd.setAttribute ("className", "cal_day_normal");
					    }
					}
					s.displayDayTd = t;
					if (t == s.todayTd) {
					    t.setAttribute ("class", "cal_day_today cal_day_selected");
					    t.setAttribute ("className", "cal_day_today cal_day_selected");
					}
					else {
					    t.setAttribute ("class", "cal_day_normal cal_day_selected");
					    t.setAttribute ("className", "cal_day_normal cal_day_selected");
					}
                                        return false; };
                                } (self, self.key, yyyy, mm+1, day, td);
                    a.appendChild (daynode);
                    daynode = a;
                    if (thisday < 0) {
                        thisday = day;
                    }
                }
                td.appendChild (daynode);
                tr.appendChild (td);
                day ++;
                dow ++;
            }
            while (dow < 7) {
                var td = document.createElement ("td");
                td.setAttribute ("class", "cal_day_empty");
                td.setAttribute ("className", "cal_day_empty");
                tr.appendChild (td);
                dow ++;
            }
        }

        if (this.detailsID == null) {
            schedule.appendChild (this.createCredit());
        }
        else {
            var table = this.createEventsTable ();
            var details = document.getElementById (this.detailsID);
            details.appendChild (table);
            details.appendChild (this.createCredit());
            this.eventRows = table.getElementsByTagName("tbody")[0];
        }
        
        if (thisday < 0) {
            thisday = 1;
        }
        this.renderDetails (this.key, yyyy, mm+1, thisday);

    }
    
    this.createEventsTable = function () {
        var tab = document.createElement ("table");
        tab.setAttribute ("class", "cal_table");
        tab.setAttribute ("className", "cal_table");
        if (this.detailsHeading != null) {
            var thead = document.createElement ("thead");
            tab.appendChild (thead);	    
            var tr = document.createElement ("tr");
            thead.appendChild (tr);
            tr.setAttribute ("class", "cal_event_heading");
            tr.setAttribute ("className", "cal_event_heading");
            var th = document.createElement ("th");
            th.setAttribute ("class", "cal_event_heading");
            th.setAttribute ("className", "cal_event_heading");
            tr.appendChild (th);
            th.colSpan = 2;
            th.appendChild (document.createTextNode (this.detailsHeading));
        }
        rows = document.createElement ("tbody");
        tab.appendChild (rows);
        return tab;
    }
    
    this.formatDate = function (yyyy, mm, dd) {
        var date = new Date ();
        date.setFullYear (yyyy, mm-1, dd);
	
        var dow = date.getDay ();
	
        var str = this.dayNames[dow] + ", " + this.monthNames[mm-1] + " " + dd + ", " + yyyy;
        return str;
    }

    this.formatTimeString = function (timestr) {
        var idx = timestr.indexOf (":");
        
        var hh = timestr.substring (0, idx) - 0;
        var mm = timestr.substring (idx+1);
        var am_pm = "am";
        
        if (hh >= 12) {
            hh -= 12;
            am_pm = "pm";
        }
        
        if (hh == 0) {
            hh = 12;
        }
        
        return hh + ":" + mm + am_pm;
    }
    
    this.eventToString = function (info) {
        var s = "";
        for (j in info) {
            s += j + " => " + info[j] + "\n";
        }
        return s;
    }
    
    this.renderDetails = function (key, yyyy, mm, day) {
        var rows = null;
        var table = null;
        
        if (this.detailsID == null) {
            table = this.createEventsTable ();
            rows  = table.getElementsByTagName("tbody")[0];
        }
        else {
            rows = this.eventRows;
        }
        
        var kids = rows.childNodes;
        var idx = 0;

		var tr;
		tr = document.createElement ("tr");
		tr.setAttribute ("class", "cal_day_heading");
		tr.setAttribute ("className", "cal_day_heading");
		var td = document.createElement ("td");
		td.setAttribute ("class", "cal_day_heading");
		td.setAttribute ("className", "cal_day_heading");
		td.appendChild (document.createTextNode(this.formatDate(yyyy,mm,day)));
		tr.appendChild (td);
		td.colSpan = 2;
		this.replaceOrInsertNode (rows, kids, idx, tr);
		idx ++;
	
        var events = this.eventMap[key][day];
        if (events == null) {
            events = new Array ();
        }
        
        for (var i=0; i<events.length; i++) {
            var info = events[i];
            //alert (this.eventToString (info));
    
            var rowclass;
            if ((i%2) == 0) {
                rowclass = "cal_row_even";
            }
            else {
                rowclass = "cal_row_odd";
            }
            var tr = document.createElement ("tr");
            tr.setAttribute ("class", rowclass);
            tr.setAttribute ("className", rowclass);
            var td = document.createElement ("td");
            td.setAttribute ("class", rowclass);
            td.setAttribute ("className", rowclass);
            if (!info.allDay) {
                var timestr = document.createTextNode (this.formatTimeString(info.stTime) + "-" + this.formatTimeString(info.endTime));
                if (this.displayTimeInColumnP) {
                  var nobr = document.createElement ("nobr");
                  nobr.appendChild (timestr);
                  td.appendChild (nobr);
                  td.setAttribute ("valign", "top");
                }
                else {
                    td.appendChild (timestr);
                    td.appendChild (document.createElement("br"));
                }
            }
            if (this.displayTimeInColumnP) {
                tr.appendChild (td);
                td = document.createElement ("td");
                td.setAttribute ("class", rowclass);
                td.setAttribute ("className", rowclass);
            }
            else {
                td.colSpan = 2;
            }
            var txt;
            if (info.visibility == 'busy') {
                txt = document.createTextNode ("Busy");
            }
            else if (info.description != null && info.description != "") {
                txt = document.createTextNode (info.description);
            }
            else {
                txt = document.createTextNode (info.caption);
            }
            td.appendChild (txt);
            tr.appendChild (td);
            this.replaceOrInsertNode (this.eventRows, kids, idx, tr);
            idx ++;
        }
        for (var i=kids.length-1; i>=idx; i--) {
            this.eventRows.removeChild (kids[i]);
        }
    }
    
    this.replaceOrInsertNode = function (parent, kids, idx, child) {
        if (kids != null && idx < kids.length) {
            parent.replaceChild (child, kids[idx]);
        }
        else {
            parent.appendChild (child);
        }
    }

    this.createCredit = function () {
        var credit = document.createElement ("div");
        credit.setAttribute ("style", "clear: both; padding-top: .5em; text-align: right;");
        var creditline = document.createElement ("div");
        creditline.setAttribute (document.all ? "className" : "class", "cal_credit");
        var ahj = document.createElement ("a");
	var img = document.createElement("IMG");
	ahj.appendChild(img);
        //creditline.appendChild (document.createTextNode ("Powered by "));
        ahj.setAttribute ("href", "http://www.happyjacksoftware.com");
	img.setAttribute("src","http://www.happyjacksoftware.com/calibrate/images/powered_by.gif");
	img.setAttribute("width","161");
	img.setAttribute("height","23");
	img.style.border = "0px"
        creditline.appendChild (ahj);
        credit.appendChild (creditline);
        return credit;
    }

    this.indexEventInfo = function (eventInfo) {
        var eventInfoByDate = new Array ();
        for (var i=0; i<=31; i++) {
            eventInfoByDate[i] = null;
        }
        for (var i=0; i<eventInfo.length; i++) {
            var datestr = eventInfo[i].date;
            var idx1 = datestr.indexOf ("-");
            var idx2 = datestr.lastIndexOf ("-");
            var yy = datestr.substring (0, idx1)      - 0;
            var mm = datestr.substring (idx1+1, idx2) - 0;
            var dd = datestr.substring (idx2+1)       - 0;

            if (eventInfoByDate[dd] == null) {
                eventInfoByDate[dd] = new Array ();
            }
            eventInfoByDate[dd].push (eventInfo[i]);
        }
        return eventInfoByDate;
    }

    return this;
}
