/**
 * Bloglendar, a class that generates a calendar navigation panel for Blogger,
 * which greatly help locating posts of a particular day.
 * @param dateSelector TagName+ClassName for the date entries, e.g. "div.blogDate"
 * @param panelId ID of the panel object, e.g. "bloglendar"
 * @param monthNames Names of months for displaying (optional)
 * @param weekdayNames Names of weekdays for displaying (optional)
 * @param dayNames Names of days for displaying (optional)
 */
function Bloglendar( dateSelector, panelId, monthNames, weekdayNames, dayNames )
{
    this.links = new Array();
    this.panelHolder = document.getElementById( panelId );
    this.monthNames = monthNames;
    this.weekdayNames = weekdayNames;
    this.dayNames = dayNames;
    this.firstFoundDate = new Date();

    // Get the links
    var selector = dateSelector.split( "." );
    var elements = document.getElementsByTagName( selector[0] );
    var currentDate, currentId;
    for ( var i = 0, len = elements.length; i < len; i++ )
    {
        if ( elements[i].className == selector[1] )
        {
            currentDate = new Date( elements[i].title );
            currentId = currentDate.valueOf();
            elements[i].removeAttribute( "title" );

            // Only do this once
            if ( this.links.length == 0 )
            {
                this.firstFoundDate = currentDate;
            }

            // Only add links of the same month
            if ( this.firstFoundDate.getYear() == currentDate.getYear()
                &&  this.firstFoundDate.getMonth() == currentDate.getMonth() )
            {
                elements[i].id = currentId;
                this.links[ currentDate.getDate() ] = "#" + currentId;
            }
        }
    }

    if ( monthNames == null || monthNames.length != 12 )
    {
        this.monthNames = new Array( "JAN", "FEB", "MAR",
                                     "APRL", "MAY", "JUN",
                                     "JUL", "AUG", "SEP",
                                     "OCT", "NOV", "DEC" );
    }
    if ( weekdayNames == null || weekdayNames.length != 7 )
    {
        this.weekdayNames = new Array( "Su", "M", "Tu", "W",
                                       "Th", "F", "Sa" );
    }
    if ( dayNames == null || dayNames.length != 31 )
    {
        this.dayNames = new Array( 31 );
        for ( var j = 0; j < 31; j++ )
        {
            this.dayNames[j] = j+1;
        }
    }
}

/**
 * Count the number of days in a given date
 * @param date The date to be counted
 * @return The number of days in that date
 */
Bloglendar.prototype.countDays = function( date )
{
    var monthCounts = new Array ( 31, 28, 31, 30,
                                  31, 30, 31, 31,
                                  30, 31, 30, 31 );
    var year = date.getFullYear();
    if ( year % 4 == 0 )
    {
        if ( year % 100 == 0 )
        {
            if ( year % 400 == 0 )
                monthCounts[1]++;
        }
        else
            monthCounts[1]++;
    }
    return monthCounts[date.getMonth()];
}

/**
 * Stop propagation of event
 * @param e Event that triggers this handler
 */
Bloglendar.prototype.stopPropagation = function( e )
{
    if ( e.stopPropagation )      // W3C
    {
        e.stopPropagation();
    }
    else                          // IE
    {
        window.event.cancelBubble = true;
    }
}

/**
 * Go to the URL inside the target element
 * @param e Event that triggers this handler
 */
Bloglendar.prototype.gotoUrl = function( e )
{
    var targetObj;
    if ( e.target )         // W3C
    {
        targetObj = e.target;
    }
    if ( e.srcElement )     // IE
    {
        targetObj = e.srcElement;
    }

    document.location.href = targetObj.firstChild.href;
}

/**
 * Draw the calendar into the place holder
 */
Bloglendar.prototype.draw = function()
{
    var calendar;

    // Display the bloglendar if and only if there are blog entries
    if ( this.links.length == 0 )
    {
        var notice = document.createTextNode( "This month: No blog entry yet" );
        calendar = document.createElement( "p" );
        calendar.appendChild( notice );
    }
    else
    {
        // Times and dates
        var currDate = new Date();
        var calMonth = this.firstFoundDate;
        var dayCount = this.countDays( calMonth );
        var currDay = -1;   // An impossible value

        if ( currDate.getYear() == calMonth.getYear()
            && currDate.getMonth() == calMonth.getMonth() )
        {
            currDay = currDate.getDate();
        }

        // Leading blanks
        calMonth.setDate( 1 );
        var blankCount = calMonth.getDay();

        // Bloglendar table
        var calTable = document.createElement( "table" );
        calTable.createTHead();
        var calTbody = document.createElement( "tbody" );

        // Repetitive objects (frequently reused)
        var row = document.createElement( "tr" );
        var headerCell = document.createElement( "th" );
        var normalCell = document.createElement( "td" );
        var text = document.createTextNode( "" );
        var anchor = document.createElement( "a" );

        // Create month
        var monthRow = row.cloneNode( false );
        var monthCell = headerCell.cloneNode( false );
        var monthText = text.cloneNode( false );
        monthText.data = this.monthNames[calMonth.getMonth()]
            + " " + calMonth.getFullYear();
        monthCell.colSpan = "7";
        monthCell.className = "month";
        monthCell.appendChild( monthText );
        monthRow.appendChild( monthCell );
        calTable.tHead.appendChild( monthRow );

        // Create weekdays
        var weekdayRow = row.cloneNode( false );
        var weekdayCell;
        var weekdayText;
        for ( var i = 0; i < 7; i++ )
        {
            weekdayCell = normalCell.cloneNode( false );
            weekdayCell.className = "weekday";
            weekdayText = text.cloneNode( false );
            weekdayText.data = this.weekdayNames[i];
            weekdayCell.appendChild( weekdayText );
            weekdayRow.appendChild( weekdayCell );
        }
        calTable.tHead.appendChild( weekdayRow );

        // Create days
        for ( var j = 1; j <= dayCount; )
        {
            var dayRow = row.cloneNode( false );
            var dayCell;
            var dayText;
            var dayAnchor;

            // Create empty days
            for ( var a = 0; a < blankCount; a++ )
            {
                dayCell = normalCell.cloneNode( false )
                dayText = text.cloneNode( false );
                dayText.data = " ";
                dayCell.appendChild( dayText );
                dayRow.appendChild( dayCell );
            }

            // Create days
            for ( var b = blankCount; b < 7; b++ )
            {
                dayCell = normalCell.cloneNode( false );
                dayText = text.cloneNode( false );
                dayText.data = this.dayNames[j-1];

                // Create active days
                if ( this.links[j] )
                {
                    dayAnchor = anchor.cloneNode( false );
                    dayAnchor.href = this.links[j];
                    dayAnchor.appendChild( dayText );
                    dayCell.appendChild( dayAnchor );
                    dayCell.className = "activeday";
                }
                // Create inactive days
                else if ( j <= dayCount )
                {
                    dayCell.appendChild( dayText );
                }
                // Create empty days
                else
                {
                    dayText.data = " ";
                    dayCell.appendChild( dayText );
                }

                // Set day's class
                if ( j < currDay || ( currDay < 0 && j <= dayCount ) )
                {
                    dayCell.className = dayCell.className + " pastday";
                }
                else if ( j == currDay )
                {
                    dayCell.className = dayCell.className + " currentday";
                }
                else if ( j <= dayCount )
                {
                    dayCell.className = dayCell.className + " futureday";
                }

                dayRow.appendChild( dayCell );
                calTbody.appendChild( dayRow );
                j++;
            }
            blankCount = 0;
        }
        calTable.appendChild( calTbody );
        calendar = calTable;
    }

    this.panelHolder.appendChild( calendar );
}
