/* javascript for calendar stuff */

var daysOfWeek = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
var monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

/*
    hash monthDetail(year, month)

    given a year and a month, return an associative array
    (hash) with the month name, the number of days in the
    month and the day of the first (0 = sun, 6 = sat)
*/
function monthDetail (year, month) {
    var isLeapYear = (year % 4 == 0 && year % 100 != 0) ||
                     year % 400 == 0;

    var daysInMonth = [31, (isLeapYear ? 29 : 28), 31, 30, 31, 30,
                       31, 31, 30, 31, 30, 31][month - 1];

    var monthName = monthNames[month - 1];


    /* not sure how this works, but i got the algorithm from
       the web, so you know it's true.
           http://www.terra.es/personal2/grimmer/ */
    var startDay = year % 100;
    startDay += Math.floor(startDay / 4);
    startDay += [6, 2, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4][month - 1];
    startDay += 1;
    if (isLeapYear) { startDay--; }

    var century = Math.floor(year / 100);
    switch (century) {
        case 17: startDay += 5; break;
        case 18: startDay += 3; break;
        case 19: startDay += 1; break;
        case 20: startDay += 0; break;
        case 21: startDay += 5; break;
        case 22: startDay += 3; break;
        default: alert("year '" + year + "' is out of range.  " +
                       "Calendar is probably wrong."); break;
    };

    startDay %= 7;

    return {"startDay"    : startDay,
            "daysInMonth" : daysInMonth,
            "monthName"   : monthName};
}


/*
    DOM createCalendar (year, month)

    create a calendar (table) for a given year and month.
    the classes set are (indented to show relationships):
        calendar - the table
            monthName - the table row with the month name/nav
                nav - the table cells where the optional nav bits go
            daysOfWeek - the table row with the days of the week
            day - the table cells with the days
*/
function createCalendar (year, month) {
    var m = monthDetail(year, month);

    var newCalendar = TABLE({'class':'calendar'},
        THEAD(null,
            TR({'class':'monthName'},
                TD({"class":"nav"}, null),
                TD({'colspan':5}, m["monthName"] + " " + year),
                TD({"class":"nav"}, null)),
            TR({'class':'daysOfWeek'},
                map(partial(TD, null), daysOfWeek))));

    // create an array with the days of the month.  add it
    // to the calendar in blocks of seven days.
    var a = [];
    for (var i = 0; i < m["startDay"]; i++) { a.push(TD(null, null)); }
    for (var i = 1; i <= m["daysInMonth"]; i++) {
        a.push(TD({'class':'day'}, i));
    }
    for (var i = 0; i < a.length; i += 7) {
        appendChildNodes(newCalendar,
            TBODY(null,
                TR(null, a.slice(i, i+7))));
    }

    return newCalendar;
};


/*
    null addCalendar (element, year, month)

    add a calendar to some element.
*/
function addCalendar (elem, year, month) {

    // default to current month/year
    if (month == null || year == null) {
        var d = new Date();
        if (month == null) { month = d.getMonth() + 1; }
        if (year == null) { year = d.getFullYear(); }
    }

    // if the month is out of range, move it to jan/dec of the
    // next/previous year.  this is mainly for the nav thing
    if (month > 12) { month = 1; year += 1; }
    else if (month < 1) { month = 12; year -= 1; }

    var d = loadJSONDoc('/cgi-bin/shows.pl/' + year + '/' + month);

    // the callback function.  this will be called automatically
    // when d (the wrapped XMLHTTPRequest) completes.
    var callback = function (o) {
        // this is the child element where the output will go
        var output_name = elem + '_output';

        // create calendar DOM
        var newCalendar = createCalendar(year, month);

        // add nav bits
        var nav = getElementsByTagAndClassName('td', 'nav',
                                                newCalendar);
        updateNodeAttributes(nav[0], {"onclick": "addCalendar('"+
            elem+"',"+year+","+ (month-1)+")", "class":"nav"});
        nav[0].innerHTML = '&lt;';
        updateNodeAttributes(nav[1], {"onclick": "addCalendar('"+
            elem+"',"+year+","+ (month+1)+")", "class":"nav"});
        nav[1].innerHTML = '&gt;';

        // add events
        var day = getElementsByTagAndClassName('td', 'day',
                                                newCalendar);
        for (var i in o.events) {
            addElementClass(day[i-1], "calendar_event");
            updateNodeAttributes(day[i-1],
                {"onclick": "getElement('" + output_name +
                    "').innerHTML = '" + i + ": ' + unescape('" +
                    escape(o.events[i]) + "');"});
        }

        // replaceChildNodes(elem, newCalendar);
        replaceChildNodes(elem,
            DIV({"class":"calendar_div"},
                newCalendar,
                DIV({"class":"calendar_output","id":output_name})));
    };
    d.addCallback(callback);
}
