<!--
/*****************************************************************************
*        File: cal.js
* Description: Functions for building the calendar page
*     Created: 12/04/2004
*****************************************************************************/
var nMeeting = 1;
var nEvent = 2;
var nOther = 3;
var nAlliance = 4;
var colorMeeting = "#0000FF";
var colorEvent = "#FF0000";
var colorOther = "#CC9900";
var colorAlliance = "#336666";
var colorBlack = "#000000";
var bListBorder = false;

/*****************************************************************************
*    Function: event
* Description: Class to hold an event
*     Created: 12/04/2004
*****************************************************************************/
function event(nMonth, nSDay, nEDay, nYear, sName, sDesc, sHost, nCategory,
               sNotification) {

    this.month = nMonth;
    this.startDay = nSDay;
    this.endDay = nEDay;
    this.year = nYear;
    this.name = sName;
    this.description = sDesc;
    this.host = sHost;
    this.category = nCategory;
    this.meetingNotice = sNotification;

}

/*****************************************************************************
*    Function: events
* Description: Class to hold a list of events
*     Created: 12/04/2004
*****************************************************************************/
function events(nYear, sNote) {


    this.eventList = new Array();
    this.count = countEvents;
    this.add = addEvent;
    this.getEventByName = getEventByName;
    this.getEventByDate = getEventByDate;
    this.getEventByPos = getEventByPos;

    if (nYear == null)
        this.year = (new Date()).getYear();
    else
        this.year = nYear;

    if (sNote == null)
        this.note = '';
    else
        this.note = sNote;

}

/*****************************************************************************
*    Function: addEvent
* Description: Add an event to the event list
*     Created: 12/04/2004
*****************************************************************************/
function addEvent(nMonth, nSDay, nEDay, sName, sDesc, sHost, nCategory, sNotice) {

    this.eventList.push(new event(nMonth, nSDay, nEDay, this.year, sName, sDesc, sHost, nCategory, sNotice));

}

/*****************************************************************************
*    Function: countEvents
* Description: Return the number of events in the list
*     Created: 12/05/2004
*****************************************************************************/
function countEvents() {

    return this.eventList.length;

}

/*****************************************************************************
*    Function: getEventByName
* Description: Retrieve an event by the event name
*     Created: 12/04/2004
*   Arguments: sName - String, The name of the event to find
*     Returns: Object of class event
*****************************************************************************/
function getEventByName(sName) {
    var found = false;
    var i = 0;

    with (this) {
        while (i < eventList.length && !found) {
            if (eventList[i].name == sName)
                found = true;
            else
                i++;

        }

        if (found)
            return eventList[i];
        else
            return null;

    }

}

/*****************************************************************************
*    Function: getEventByDate
* Description: Retrieve an event by the month and day
*     Created: 12/04/2004
*   Arguments: nMonth - Numeric, the month
*              nDay - Numeric, the day of the month
*     Returns: Object of class event
*****************************************************************************/
function getEventByDate(nMonth, nDay) {
    var found = false;
    var i = 0;

    with (this) {
        while (i < eventList.length && !found) {

            if (eventList[i].month == nMonth &&
                eventList[i].startDay <= nDay &&
                nDay <= eventList[i].endDay)
                found = true;
            else
                i++;

        }

        if (found)
            return eventList[i];
        else
            return null;

    }

}

/*****************************************************************************
*    Function: getEventByPos
* Description: Retrieve an event using it's index
*     Created: 12/04/2004
*   Arguments: nPos - The position in the list of the event to retrieve
*     Returns: Object of class event
*****************************************************************************/
function getEventByPos(nPos) {

    with (this) {
        if (nPos >= 0 && nPos < eventList.length)
            return eventList[nPos];
        else
            return null;

    }

}

/*****************************************************************************
*    Function: Gregorian
* Description: Determine the day of the week of a date on the Gregorian
*              calendar
*     Created: 12/04/2004
*   Arguments: nMonth - Numeric, the month
*              nDay - Numeric, the day of the month
*              nYear - Numeric, the year
*     Returns: Numeric - 0 = Sunday, 6 = Saturday
*****************************************************************************/
function Gregorian(nMonth, nDay, nYear) {
    var nDOW;

    if (nMonth <= 2) {
        nMonth = nMonth + 12;
        nYear = nYear - 1;
    }

    nDOW = (nDay + 2 * nMonth + Math.floor(6 * (nMonth + 1) / 10) + nYear +
            Math.floor(nYear / 4) - Math.floor(nYear / 100) +
            Math.floor(nYear / 400) + 2) % 7;

    if (nDOW == 0)
        nDOW = 7;

    return (nDOW - 1);

}

/*****************************************************************************
*    Function: Julian
* Description: Determine the day of the week of a date on the Julian calendar
*     Created: 12/04/2004
*   Arguments: nMonth - Numeric, the month
*              nDay - Numeric, the day of the month
*              nYear - Numeric, the year
*     Returns: Numeric - 0 = Sunday, 6 = Saturday
*****************************************************************************/
function Julian(nMonth, nDay, nYear) {
    var nDOW;

    if (nMonth <= 2) {
        nMonth = nMonth + 12;
        nYear = nYear - 1;
    }

    nDOW = (nDay + 2 * nMonth + Math.floor(6 * (nMonth + 1) / 10) + nYear +
            Math.floor(nYear / 4)) % 7

    if (nDOW == 0)
        nDOW = 7;

    return (nDOW - 1);

}

/*****************************************************************************
*    Function: LeapYear
* Description: Determine if a year is a leap year
*     Created: 12/04/2004
*   Arguments: nYear - Numeric, the year
*     Returns: Boolean - True if the year is a leap year
*****************************************************************************/
function LeapYear(nYear) {

    if (nYear > 1582)
        return ((nYear % 4 == 0) && ((nYear % 100 != 0) || (nYear % 400 == 0)));
    else
        return (nYear % 4 == 0);

}

/*****************************************************************************
*    Function: monthName
* Description: Given a month number, return the name of the month
*     Created: 12/05/2004
*   Arguments: nMonth - The month
*     Returns: String - The name of the month
*****************************************************************************/
function monthName(nMonth) {
    var months = new Array('January', 'February', 'March', 'April', 'May', 'June',
                           'July', 'August', 'September', 'October', 'November',
                           'December');
    var n = (nMonth - 1) % 12;

    return months[n];

}

/*****************************************************************************
*    Function: daysInMonth
* Description: Given a month and year, return the number of days in that month
*     Created: 12/05/2004
*   Arguments: nMonth - The month
*              nYear - The year
*     Returns: Numeric - The number of days in the month
*****************************************************************************/
function daysInMonth(nMonth, nYear) {

    if (nMonth == 1 || nMonth == 3 || nMonth == 5 || nMonth == 7 ||
        nMonth == 8 || nMonth == 10 || nMonth == 12)
        return 31;
    else if (nMonth == 2) {
        if (LeapYear(nYear))
            return 29;
        else
            return 28;
    }
    else
        return 30;

}

/*****************************************************************************
*    Function: ccccMonth
* Description: Class to hold information about a month
*     Created: 12/05/2004
*****************************************************************************/
function ccccMonth(nMonth, nYear) {

    this.month = nMonth;
    this.monthName = monthName;
    this.year = nYear;
    this.days = buildMonth(nMonth, nYear);


}

/*****************************************************************************
*    Function: buildMonth
* Description: Generate the body of a month
*     Created: 12/05/2004
*   Arguments: nMonth - Numeric, the month
*              nYear - Numeric, the year
*     Returns: Array of days organized in weeks
*****************************************************************************/
function buildMonth(nMonth, nYear) {
    var aMonth = new Array();
    var nDay = 1;
    var nDOW;
    var i;
    var j;

    // Determine the starting day
    if ((nYear < 1582) || ((nYear == 1582) && (nMonth <= 10)))
        nDOW = Julian(nMonth, 1, nYear);
    else
        nDOW = Gregorian(nMonth, 1, nYear);

    // Fill in the array with zeros
    for (i = 0; i <= 5; i++)
        aMonth.push(new Array(0, 0, 0, 0, 0, 0, 0));

    // Fill in the days
    i = 0;
    while (nDay <= daysInMonth(nMonth, nYear) && i < aMonth.length) {
        aMonth[i][nDOW] = nDay;

        nDay++;
        nDOW++;

        if (nDOW > 6) {
            nDOW = 0;
            i++;
        }

    }

    return aMonth;

}

/*****************************************************************************
*    Function: generateCell
* Description: Generate the HTML for a cell in the event list
*     Created: 12/05/2004
*   Arguments: cellContent - The value to display in the cell
*              bCenter - True if the cell is to be center aligned, otherwise
*                        align left.
*     Returns: The HTML that will generate the desired cell
*****************************************************************************/
function generateCell(cellContent, bCenter, sColor) {
    var sCell;

    if (bCenter)
        sCell = '<td align="center" valign="top">';
    else
        sCell = '<td valign="top">';

    if (cellContent.toString().length <= 0)
        sCell += '&nbsp;</td>';
    else
        sCell += '<font color="' + sColor + '">' + cellContent + '</font></td>';

    return sCell;

}

/*****************************************************************************
*    Function: generateSep
* Description: Generate a separator row
*     Created: 12/05/2004
*   Arguments: nColumns - The number of columns the separator will span
*     Returns: The HTML to generate the the separator row
*****************************************************************************/
function generateSep(nColumns) {
    var cSep;

    if (bListBorder)
        cSep = '&nbsp;';
    else
        cSep = '<hr>';

    if (nColumns > 0)
        return '<tr><td colspan="' + nColumns + '">' + cSep + '</td></tr>';
    else
        return '<tr><td><hr></td></tr>';

}

/*****************************************************************************
*    Function: generateList
* Description: Generate the HTML for the event list
*     Created: 12/05/2004
*   Arguments: objEvents - An object of the events class
*     Returns: The HTML to generate the event list.
*****************************************************************************/
function generateList(objEvents) {
    var lastMonth = 0;
    var nBorder;
    var events;
    var sDayCell;
    var rowColor;
    var i;

    if (bListBorder)
        nBorder = 2;
    else
        nBorder = 0;

    events = '<p align="center"><big><b>' + objEvents.year + ' CCCC Meeting and Events Schedule</b></big></p>';
    events += '<table border="' + nBorder + '" width="100%">';

    // Setup the column headers
    events += '<tr><td align="center" width="15%"><b>Month</b></td>';
    events += '<td align="center" width="15%"><b>Day</b></td>';
    events += '<td width="35%"><b>Event</b></td>';
    events += '<td width="35%"><b>Host</b></td></tr>';

    with (objEvents) {
        for (i = 0; i < count(); i++) {
            // Generate a row
            with (eventList[i]) {
                if (category == nAlliance)
                    rowColor = colorAlliance;
                else
                    rowColor = colorBlack;

                if (month == lastMonth)
                    events += '<tr>' + generateCell('', true, rowColor);
                else {
                    if (i > 0)
                        events += generateSep(4);

                    events += '<tr>' + generateCell('<a name=\'' + monthName(month) + '\'>' + monthName(month) + '</a>', true, colorBlack);
                    lastMonth = month;
                }

                if (startDay == 0) {
                    sDayCell = '<a name="' + name + '">TBD';

                }
                else {
                    sDayCell = '<a name="' + name + '">' + startDay;

                    if (startDay != endDay)
                        sDayCell += '-' + endDay;

                }

                sDayCell += '</a>'
                events += generateCell(sDayCell, true, colorBlack);

                events += generateCell(description, false, rowColor);
                events += generateCell(host, false, rowColor);
                events += '</tr>';

            }

        }

        if (note.length > 0)
            events += '<tr><td colspan="4">' + note + '</td></tr>';

    }

    events += '</table>';

    return events;

}

/*****************************************************************************
*    Function: generateMonth
* Description: Generate the HTML for a month
*     Created: 12/05/2004
*   Arguments: objMonth - An object of the cccMonth class
*              objEvents - The list of events
*     Returns: The HTML to display the month.
*****************************************************************************/
function generateMonth(objMonth, objEvents) {
    var sDOW = 'SMTWHFA';
    var sText = '';
    var objEvent;
    var sAnchor1;
    var sAnchor2;
    var sColor;
    var i;
    var j;

    with (objMonth) {
        sText += '<table border="0"><tr><td colspan="' + days[0].length +
                 '" align="center"><b>' +  monthName(month) + '</b></td></tr>';

        // Add the days of the week legend
        sText += '<tr>';

        for (i = 0; i < days[0].length; i++)
            sText += '<td align="center"><b>' + sDOW.substring(i, i + 1) +
                     '</b></td>';

        sText += '</tr>';

        // Create the body of the calendar
        for (i = 0; i < days.length; i++) {
            sText += '<tr>';

            for (j = 0; j < days[i].length; j++) {
                // Determine if an event occurs on this day
                if (days[i][j] > 0)
                    objEvent = objEvents.getEventByDate(month, days[i][j]);
                else
                    objEvent = null;

                if (objEvent == null) {
                    sAnchor1 = '';
                    sAnchor2 = '';
                }
                else {
                    if (objEvent.category == nMeeting)
                        sColor = colorMeeting;
                    else if (objEvent.category == nEvent)
                        sColor = colorEvent;
                    else if (objEvent.category == nAlliance)
                        sColor = colorAlliance;
                    else
                        sColor = colorOther;

                    sAnchor1 = '<a href="#' + objEvent.name + '" style="color: ' + sColor + '">';
                    sAnchor2 = '</a>';
                }

                // Create the cell with the day in it
                if (days[i][j] > 0)
                    sText += '<td align="right">' + sAnchor1 + days[i][j] + sAnchor2 + '</td>';
                else
                    sText += '<td>&nbsp;</td>';
            }

            sText += '</tr>';

        }

        sText += '</table>';

    }

    return sText;

}

/*****************************************************************************
*    Function: loadCalData
* Description: Load the calendar data
*     Created: 07/25/2006
*   Arguments: None
*     Returns: An array of event objects
*****************************************************************************/
function loadCalData() {
    var aEvents = getEventList();
    var objEvents = new events(2009, '');
    var i;

    // Build the list
    with (objEvents) {
        for (i = 0; i < aEvents.length; i++) {
            add(aEvents[i][0],
                aEvents[i][1],
                aEvents[i][2],
                aEvents[i][3],
                aEvents[i][4],
                aEvents[i][5],
                aEvents[i][6],
                aEvents[i][7]);

        }

    }

    return objEvents;

}

/*****************************************************************************
*    Function: nextMeeting
* Description: Return a line describing the location of the next meeting
*  Parameters: month - Number of the month (1 - 12) to display the meeting for
*     Returns: String describing the next meeting
*****************************************************************************/
function nextMeeting(month) {
    var objEvents = loadCalData();
    var nextMonth = month + 1;
    var nextMeeting = '';
    var found = false;
    var event;
    var i;

    // If the next month number is located in the event list, use it.
    // Otherwise, correct the month for overflow
    if (objEvents.eventList[objEvents.eventList.length - 1].month < nextMonth)
        nextMonth = nextMonthID(month);

    // Find the next meeting
    for (i = 0; i < objEvents.eventList.length && !found; i++) {
        event = objEvents.eventList[i];

        if (event.month == nextMonth && event.category == nMeeting) {
            nextMeeting = objEvents.eventList[i].meetingNotice;
            found = true;

        }

    }

    return nextMeeting;

}

/*****************************************************************************
*    Function: headlines
* Description: Return the events for this and next month
*  Parameters: month - Number of the month (1 - 12) to display the meeting for
*     Returns: HTML for the this and next month's events
*****************************************************************************/
function headlines(month) {

    return headlines(month, true);

}

/*****************************************************************************
*    Function: headlines
* Description: Return the events for this and next month
*  Parameters: month - Number of the month (1 - 12) to display the meeting for
*              showPast - true if events that are in the past should be shown
*     Returns: HTML for the this and next month's events
*****************************************************************************/
function headlines(month, showPast) {
    var nextMonth = month + 1;
    var head1 = '<b><u>' + monthName(month) + '</u></b><br>';
    var head2 = '<b><u>' + monthName(nextMonth) + '</u></b><br>';
    var objEvents = loadCalData();
    var m1List = new Array(0);
    var m2List = new Array(0);
    var html = '';
    var done = false;
    var event;
    var i;

    // If the next month number is located in the event list, use it.
    // Otherwise, correct the month for overflow
    if (objEvents.eventList[objEvents.eventList.length - 1].month < nextMonth)
        nextMonth = nextMonthID(month);

    for (i = 0; i < objEvents.eventList.length && !done; i++) {
        event = objEvents.eventList[i];

        if (event.month > nextMonth)
            done = true;
        else if (showEvent(event, month, nextMonth, showPast)) {
            if (event.startDay > 0) {
                if (event.month == month)
                    m1List.push(makeHeadline(event));
                else if (event.month == nextMonth)
                    m2List.push(makeHeadline(event));

            }

        }

    }

    if (m1List.length > 0) {
        html += head1;
        for (i = 0; i < m1List.length; i++) {
            html += m1List[i];
        }
    }

    if (m2List.length > 0) {
        if (m1List.length > 0)
            html += '<br>';

        html += head2;
        for (i = 0; i < m2List.length; i++) {
            html += m2List[i];
        }
    }

    return html;

}

/*****************************************************************************
*    Function: showEvent
* Description: Determine if the event should be displayed in the headlines
*  Parameters: event - The event to evaluate
*              curMonth - The month to evaluate the event against
*              nextMonth - The month after curMonth
*              showPast - True to show any events from the curMonth or
*                         nextMonth that are before today
*     Returns: Integer - The next month
*****************************************************************************/
function showEvent(event, curMonth, nextMonth, showPast)
{
    var today = new Date();

    var eventDate = new Date(event.year, event.month - 1, event.endDay);

    return ((showPast || eventDate.valueOf() >= today.valueOf()) &&
            (event.month == curMonth || event.month == nextMonth));

}

/*****************************************************************************
*    Function: nextMonthID
* Description: Determine the month number of the next month (1 - 12)
*  Parameters: month - Number of the month (1 - 12) to base the calculation on
*     Returns: Integer - The next month
*****************************************************************************/
function nextMonthID(month) {
    var nextMonth = month + 1;

    if (nextMonth > 12)
        nextMonth = nextMonth - 12;

    return nextMonth;

}

/*****************************************************************************
*    Function: makeHeadline
* Description: Build the HTML for a headline
*  Parameters: event - An event object
*     Returns: String - The HTML that will display the event
*****************************************************************************/
function makeHeadline(event) {

    return '<li>' + event.startDay + ' - ' + event.description + '</li>\n';

}
//-->

