var g_currentMonth = null;
var g_calendarCallback;
var MONTHS_LONG = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
var MONTHS = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
var DOW_LONG = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
var DOW = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];

function cal_daysBetween( start, end )
{
    start = Date.UTC( start.getFullYear(), start.getMonth(), start.getDate() );
    end = Date.UTC( end.getFullYear(), end.getMonth(), end.getDate() );
    return (end - start) / 86400000;
};

function cal_changeDayTo( dayOfWeek, date, direction )
{
    var difference = direction * (Math.abs(date.getDay() - dayOfWeek - (direction * 7)) % 7);
    return new Date( date.getFullYear(), date.getMonth(), date.getDate() + difference );
};
  
function cal_rangeStart( date, start_of_week )
{
    return cal_changeDayTo( start_of_week, new Date(date.getFullYear(), date.getMonth()), -1 );
};
  
function cal_rangeEnd( date, start_of_week )
{
    return cal_changeDayTo( (start_of_week - 1) % 7, new Date(date.getFullYear(), date.getMonth() + 1, 0), 1 );
};
  
function cal_isLastDayOfWeek( date, start_of_week )
{
    return date.getDay() == (start_of_week - 1) % 7;
};

function cal_isFirstDayOfWeek( date, start_of_week )
{
    return date.getDay() == start_of_week;
};
function cal_moveMonthBy( selector, currentMonth, amount )
{
    if( amount < 0 )
        var newMonth = new Date( currentMonth.getFullYear(), currentMonth.getMonth() + amount+1, -1 );
    else
        var newMonth = new Date( currentMonth.getFullYear(), currentMonth.getMonth() + amount, 1 );

    cal_buildCalendar( selector, newMonth, g_calendarCallback );
};

function cal_buildCalendar( selector, now, callback )
{
    $(selector).empty();
    g_currentMonth = now;
    g_calendarCallback = callback;

    var yearNav = $('<td class="year_nav">' +
        '<span class="no-print cal_button prev" title="Previous year">&laquo;</span>' +
        ' <span class="year_name" id="year_name"></span> ' +
        '<span class="no-print cal_button next" title="Next year]">&raquo;</span>' +
        '</td>');
      
    var yearNameSpan = $(".year_name", yearNav );
    yearNameSpan.empty().append( now.getFullYear() );

    $(".prev", yearNav).click( function() { cal_moveMonthBy( selector, g_currentMonth, -12); } );
    $(".next", yearNav).click( function() { cal_moveMonthBy( selector, g_currentMonth, 12); } );

    var monthNav = $('<td class="month_nav">' +
        '<span class="no-print cal_button prev" title="Previous month">&laquo;</span>' +
        ' <span class="month_name"></span> ' +
        '<span class="no-print cal_button next" title="Next month">&raquo;</span>' +
        '</td>');

    var monthNameSpan = $(".month_name", monthNav);
    monthNameSpan.empty().append( MONTHS_LONG[now.getMonth()] );

    $(".prev", monthNav).click( function() { cal_moveMonthBy( selector, g_currentMonth, -1 ); } );
    $(".next", monthNav).click( function() { cal_moveMonthBy( selector, g_currentMonth, 1 ); } );

    var print = "<div class='no-print' style='float: right; margin: 0 15px;'><a href='javascript:void(0)' onclick='window.print();'>Print</a></div>";
    var nav = $("<tr></tr>").append( monthNav, yearNav, print );
    nav = $('<table class="calendar_nav"></table>').append( nav );
    $(selector).append( nav );

    var tableShell = "<table class='calendar'><thead><tr>";
    var strHeader = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];
    $(strHeader).each( function() {
        tableShell += "<th>" + this + "</th>";
    });
    tableShell += "</tr></thead><tbody></tbody></table>";
    var rangeStart = cal_rangeStart( now, START_OF_WEEK );
    var rangeEnd = cal_rangeEnd( now, START_OF_WEEK );
    var numDays = cal_daysBetween( rangeStart, rangeEnd );
    var dayCells = "";
    $(selector).append( tableShell );

    for ( var i = 0; i <= numDays; i++ )
    {
        var currentDay = new Date( rangeStart.getFullYear(), rangeStart.getMonth(), rangeStart.getDate() + i, 12, 00 );

        if ( cal_isFirstDayOfWeek( currentDay, START_OF_WEEK ) )
            dayCells += "<tr>";
        
        var firstDayOfWeek = currentDay;

        if ( currentDay.getMonth() == now.getMonth() )
        {
            var classWeekend = "";
            if ( currentDay.getDay() == 6 || currentDay.getDay() == 0 )
                classWeekend = " weekend";
            dayCells += '<td class="selectable_day' + classWeekend + '" date="' + formatDate(currentDay.getTime()) + '"><span class="day">' + currentDay.getDate() + '</span></td>';
        }
        else
            dayCells += '<td class="unselected_month" date="' + formatDate(currentDay.getTime()) + '">' + currentDay.getDate() + '</td>';
        
        if ( cal_isLastDayOfWeek( currentDay, START_OF_WEEK ) )
            dayCells += "</tr>";
    }

    $( selector + " table.calendar tbody").empty().append( dayCells );
    $( selector + " table.calendar td[date=" + formatDate( new Date().getTime() ) + "]").addClass( "today" );

    callback();
};

