//////////////////////////////////////////////////////////////////////////////
// This file contains functions to determine when the next event will occur //
//////////////////////////////////////////////////////////////////////////////

// Determine when next event will occur and return the date
//
// Input:
//     n      = Week number (1 = 1st, 2 = 2nd, ...)
//     dow    = Day of week: 0 = Sunday, 1 = Monday, ..., 6 = Saturday
//     months = Array of months where event can occur: 1 = January,
//              2 = February, ..., 12 = December
//
// Output:
//     Date of next event
//
// Example:
//     Determine when next 4th Saturday of the month will occur,
//     excluding November and December:
//         d = getNextEvent(4, 6, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
//
//     Determine when next 3rd Sunday in September will occur:
//         d = nextEvent(3, 0, [9]);
//
function getNextEvent(n, dow, months)
{
    // Get current date
    dcurr = new Date();

    // Set current time to midnight to allow for easy comparison
    // of dates
    dcurr.setHours(0, 0, 0, 0);

    // Get current year
    year = dcurr.getFullYear();

    // Initialize month index to point to first allowed month
    monthIdx = 0;

    // Repeat
    do
    {
        // Set new date to first of this allowed month and the
        // current year
        //
        // NOTE: JavaScript numbers months from 0 to 11 instead of
        //       1 to 12, so use months[monthIdx] - 1 for this
        //       allowed month
        dnew = new Date();
        dnew.setFullYear(year, months[monthIdx] - 1, 1);

        // Determine nth day of week for this allowed month
        //
        // NOTE: The +7 keeps the modulo operation from coming up
        //       with a negative number
        dnew.setDate(7 * n - 6 + ((dow - dnew.getDay() + 7) % 7));

        // Set new date to midnight to allow for easy comparison
        // of dates
        dnew.setHours(0, 0, 0, 0);

        // Increment month index
        monthIdx++;

        // If end of allowed months,
        if (monthIdx >= months.length)
        {
            // Initialize month index
            monthIdx = 0;

            // Increment year
            year++;
        }
    }
    // Until the new date is on or after the current date
    while (dnew < dcurr);

    return dnew;
}

// Offset an event by a specified number of days
//
// Input:
//     d = Date of event
//     offset = Number of days to add to date of event
//
// Output:
//     Date offset by specified number of days
//
function offsetEvent(d, offset)
{
    // Copy date of event, setting time to midnight
    dnew = new Date();
    dnew.setFullYear(d.getFullYear(), d.getMonth(), d.getDate());
    dnew.setHours(0, 0, 0, 0);

    // Offset date of event
    dnew.setDate(dnew.getDate() + offset);

    return dnew;
}

// Display the date of an event
//
// Input:
//     d = Date of event
//
function displayEvent(d)
{
    // Display date
    monthNames = new Array 
    (
        "January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December"
    );
    dayNames = new Array
    (
        "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
        "Saturday"
    );

    document.write(dayNames[d.getDay()] + ", " + 
        monthNames[d.getMonth()] + " " + 
        d.getDate() + ", " + d.getFullYear());
}

// Determine when next event will occur and display it
//
// Input:
//     n      = Week number (1 = 1st, 2 = 2nd, ...)
//     dow    = Day of week: 0 = Sunday, 1 = Monday, ..., 6 = Saturday
//     months = Array of months where event can occur: 1 = January,
//              2 = February, ..., 12 = December
//
// Example:
//     Determine when next 4th Saturday of the month will occur,
//     excluding November and December:
//         nextEvent(4, 6, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
//
//     Determine when next 3rd Saturday in September will occur:
//         nextEvent(3, 6, [9]);
//
function nextEvent(n, dow, months)
{
    // Display date of next event
    displayEvent(getNextEvent(n, dow, months));
}
