// Kevin's Calendar
//
//
// JavaScript Event Calendar
//
// Version: 1.0
// Date: November 15, 1998
// By Kevin Ilsen
// For information: http://calendar.ilsen.net
//
// * This is a modification of the calendar by John Banister in mid-January 2008.
// * It's available as www.John.Banister.name/Calendar3.txt (rename it to .js to use it)  
// * This script expects a server to provide it with events stored in a .csv file named 
// * by the variable csv_file below.  If you computer at home isn't a server,  
// * or your server doesn't have such a file then it won't work there.  The format of the
// * .csv file is that created by choosing File -> Export -> Events in Broderbund's
// * Calendar Creator.  It uses the date as formatted by Calendar Creator in the first
// * "column," the event name in the fourth "column," and ignores everything else.
// * It wouldn't be to hard to modify my BCCcsv_to_events function to handle other types
// * of csv files. 
// * I'm building the table in the DOM fashion following the example set at
// * http://developer.mozilla.org/en/docs/Traversing_an_HTML_table_with_JavaScript_and_DOM_Interfaces
// * and many places at www.w3schools.com
// * So it can be inserted in the manner suggested by James Edwards at
// * http://www.sitepoint.com/blogs/2007/07/11/insert-in-place-without-documentwrite/
// *
// * Note:
// * Instead of putting <script src="Calendar.js"></script> and
// * <script language="JavaScript">
// * <!--
// * Calendar( );
// * -->
// * In your file, copy the following (w/o the slashes at the start)
// * and paste it in where you want the calendar to appear:
// * <script type="text/javascript" id="CalendarHere" src="Calendar3.js"></script>
// *
// * If you use this with any other script containing calls to DefineEvent
// * The <script src="your script here"></script> tags have to appear in the web page AFTER
// * the one with the reference to Calendar3.js or else, the browser thinks DefineEvent
// * is a variable instead of a function and it doesn't work.


// Configurable values are set to defaults here; can override them before calling Calendar( ) from the HTML page

var SpecialDay=1;        // 1=Sunday, 2=Monday, . . . 7=Saturday
var FontSize=25;
var SmallFontSize=14;
var ColorBackground = "ffffcc";
var EventBackground = "b4b492";
var EventTextColor = "fdff6c";
var ColorSpecialDay = "red";
var ColorToday = "green";
var ColorEvent = "blue";
var csv_file = "Town_Events.csv" ;


// Initialize the range of the calendar to Jan - Dec of the current year.  Calls to DefineEvent( ) will change this
// as needed; it is also possible to explicitly override the range before calling Calendar( ) from the HTML page.

var today = new Date();
var FirstMonth=GetFullYear(today) * 100 + 1;
var LastMonth=FirstMonth + 11;
var Town_Event_Date = 19950101 ;
var Town_Event_Text = "Not a big event" ;

// Events[] is a SPARSE array; Call DefineEvent( ) to populate it
var Events = new Array();

// Each event is defined by calling the DefineEvent( ) routine with the following parameters:
//
//   DefineEvent(EventDate, EventDescription, EventLink, Image, Width, Height)
//        EventDate is a numeric value in the format YYYYMMDD
//        EvenDescription is a string that can include embedded HTML tags (e.g., <BR>, <strong>, etc.)
//        EventLink is the URL of the target page if a hyperlink is desired from this event entry
//        Image is the URL of the image if you want to display an image with this event
//        Width is the width of the image in pixels
//        Height is the height of the image in pixels



function DefineEvent(EventDate, EventDescription, EventLink, Image, Width, Height) {

    var eventTableBody = null ;
    if ( ! Events[EventDate]) {
        var eventTable = document.createElement('table') ;
        var eventTableBody = document.createElement('tbody') ;
        eventTable.appendChild(eventTableBody) ;
        eventTable.width = '100%' ;
        eventTable.border = 3 ;
        eventTable.cellSpacing = '3px' ;
        eventTable.style.backgroundColor = ColorBackground ;
        Events[EventDate] = eventTable ;
    } else {
        eventTableBody = Events[EventDate].tBodies[0] ;
    }
    var eventRow = document.createElement('tr') ;
    var eventCell = document.createElement('td') ;
    eventRow.appendChild(eventCell) ;
    eventCell.style.backgroundColor = EventBackground ;
    eventCell.style.color = EventTextColor ;
    eventCell.align = 'center' ;

    // Build the Paragraph object for the text, image, and link.
    // If EventLink exists it needs to append the text & image and
    // then get appended in turn.

    var eventText = null;
    if (EventDescription.length > 0) {
        eventText = document.createTextNode(EventDescription) ;
    }
    var eventImage = null;
    if (Image.length > 3) {
        eventImage = document.createElement('img') ;
        eventImage.src = Image ;
        eventImage.width = Width ;
        eventImage.height = Height ;
        eventImage.align = "left" ;
    }
    if (EventLink.length > 2) {
        var tmpLink = document.createElement('a') ;
        tmpLink.href = EventLink ;
        if (eventImage || eventText) {
            if (eventImage) tmpLink.appendChild(eventImage) ;
            if (eventText) tmpLink.appendChild(eventText) ;
        } else {
            tmpLink.appendChild(document.createTextNode('Link')) ;
        }
        eventCell.appendChild(tmpLink) ;
    } else {
        if (eventImage) {
            eventCell.appendChild(eventImage) ;
        }
        if (eventText) {
            eventCell.appendChild(eventText) ;
        }
    }
    if (eventCell.firstChild) {
        eventTableBody.appendChild(eventRow) ;
    }

    // Adjust the minimum and maximum month & year to include this date
    tmp = Math.floor(EventDate / 100);
    if (tmp < FirstMonth) FirstMonth = tmp;
    if (tmp > LastMonth) LastMonth = tmp;
}

// Utility function to populate an array with values
function arr() {
    for (var n=0;n<arr.arguments.length;n++) {
        this[n+1] = arr.arguments[n];
    }
}

// Create the array of month names (used in various places)
var months = new arr("January","February","March","April","May","June","July","August","September","October","November","December");

// * The last two lines of the following function came from James Edwards as mentioned above

function ShowCalendar( ){

    var TheCalendar = document.createElement("table") ;

    // Default to current month and year
    mo = today.getMonth() + 1 ;
    yr = GetFullYear(today) ;

    BuildCalendar(TheCalendar, mo, yr) ;
    var scr = document.getElementById('CalendarHere') ;
    scr.parentNode.insertBefore(TheCalendar, scr) ;

}

function BuildCalendar(TheCalendar,mo,yr) {
    var CalendarTableBody = document.createElement("tbody");
    var curdy, curmo, dy, dayofweek, bgn, lastday, yearmonth, jump;
    var weekdays = new arr("Sun","Mon","Tue","Wed","Thu","Fri","Sat");

    // Save current day and month for comparison
    curdy = today.getDate();
    curmo = today.getMonth()+1;

    yearmonth = (yr * 100) + mo;


    // Create a datae object for the first day of the desired month
    bgn = new Date(months[mo] + " 1," + yr);
    // Get the day-of-week of the first day, and the # days in the month
    dayofweek = bgn.getDay();
    lastday = NumDaysIn(mo,yr);

    TheCalendar.style.backgroundColor = "#" + ColorBackground ;
    TheCalendar.style.tableLayout = "fixed" ;
    TheCalendar.id = "TheCalendarTable" ;
    var thisRow = document.createElement("tr") ;
    var thisCell = document.createElement("td") ;
    thisCell.align = "center" ;
    thisCell.colSpan = 7 ;
    var titleSpan = document.createElement("span") ;
    titleSpan.style.fontSize = FontSize ;
    titleSpan.style.fontWeight = 'bold' ;
    thisCellText = document.createTextNode
        ('\u00A0\u00A0' + months[mo] + " " + yr + '\u00A0\u00A0') ;
    titleSpan.appendChild(thisCellText) ;
    thisCell.appendChild(titleSpan) ;
    thisRow.appendChild(thisCell) ;
    CalendarTableBody.appendChild(thisRow) ;
    var thisRow = document.createElement("tr") ;


    for (var i=1;i<=7;i++){
        var thisCell = document.createElement("td") ;
        thisCell.align = "center" ;
        thisCell.width = "14%" ;
        thisCell.style.fontSize = SmallFontSize ;
        thisCell.style.borderLeft = "1px solid black" ;
        thisCell.style.borderRight = "1px solid black" ;

        thisCellText = document.createTextNode(weekdays[i]) ;
        thisCell.appendChild(thisCellText) ;
        thisRow.appendChild(thisCell) ;
    }

    CalendarTableBody.appendChild(thisRow) ;
    var thisRow = document.createElement("tr") ;
    dy = 1;
    // Special handling for the first week of the month
    for (var i=1;i<=7;i++) {
        // If the day is less than the day of the
        // week determined to be the first day
        // of the month, print a space in
        // this cell of the table.
        var thisCell = document.createElement("td") ;
        thisCell.align = "center" ;
        if (i <= dayofweek){
            thisCellText = document.createTextNode('\u00A0') ;
            thisCell.style.fontSize = FontSize ;
            thisCell.appendChild(thisCellText) ;
        }
        // Otherwise, write date and the event,
        // if any, in this cell of the table.
        else {
            ShowDate(yr,mo,dy,i,curmo,curdy,thisCell);
            dy++;
        }
        thisRow.appendChild(thisCell) ;
    }
    CalendarTableBody.appendChild(thisRow) ;
    var thisRow = document.createElement("tr") ;

    // Rest of the weeks . . .
    while (dy <= lastday) {
        for (var i=1;i<=7;i++) {
            // If the day is greater than the last
            // day of the month, print a space in
            // this cell of the table.
            var thisCell = document.createElement("td") ;
            thisCell.align = "center" ;
            if (dy > lastday) {
                thisCellText = document.createTextNode('\u00A0') ;
                thisCell.appendChild(thisCellText) ;
            }
            // Otherwise, write date and the event,
            // if any, in this cell of the table.
            else {
                ShowDate(yr,mo,dy,i,curmo,curdy,thisCell);
                dy++;
            }
            thisRow.appendChild(thisCell) ;
        }

        CalendarTableBody.appendChild(thisRow) ;
        var thisRow = document.createElement("tr") ;
    }


    var prevNext = document.createElement('p')
        prevNext.style.fontSize = SmallFontSize ;

    if  (yearmonth > FirstMonth) {
        var linkPrevious = document.createElement('a') ;
        linkPrevious.href = "Javascript: JumpTo(" + PrevYearMonth(yearmonth) + ") ;" ;
        var linkText = document.createTextNode(" View " + months[PrevMonth(mo)]) ;
        var leftArrowSpan = document.createElement("span") ;
//        leftArrowSpan.style.fontWeight = "bold" ;
        leftArrowSpan.appendChild(document.createTextNode("\u2190")) ;
        linkPrevious.appendChild(leftArrowSpan) ;
        linkPrevious.appendChild(linkText) ;
        linkPrevious.style.textDecoration="none" ;
        prevNext.appendChild(linkPrevious) ;

        var titleCell = CalendarTableBody.firstChild.firstChild ;
        titleCell.insertBefore(linkPrevious.cloneNode(true), titleCell.firstChild);
    }
    if  ((yearmonth > FirstMonth) && (yearmonth < LastMonth)) {
        var thisText = document.createTextNode("\u00A0 | \u00A0") ;
        prevNext.appendChild(thisText) ;
    }
    if (yearmonth < LastMonth) {
        var linkNext = document.createElement('a') ;
        linkNext.href = "Javascript: JumpTo(" + NextYearMonth(yearmonth) + ") ;" ;
        var linkText = document.createTextNode("View " + months[NextMonth(mo)] + " ");
        linkNext.appendChild(linkText) ;
        var rightArrowSpan = document.createElement("span") ;
//        rightArrowSpan.style.fontWeight = "bold" ;
        rightArrowSpan.appendChild(document.createTextNode("\u2192")) ;
        linkNext.appendChild(rightArrowSpan) ;
        linkNext.style.textDecoration="none" ;
        prevNext.appendChild(linkNext) ;

        var titleCell = CalendarTableBody.firstChild.firstChild ;
        titleCell.appendChild(linkNext.cloneNode(true));
    }

    CalendarTableBody.appendChild(thisRow) ;
    var thisRow = document.createElement("tr") ;
    var thisCell = document.createElement("td") ;
    thisCell.align = "center" ;
    thisCell.colSpan = 7 ;
    thisCell.appendChild(prevNext) ;
    thisRow.appendChild(thisCell) ;
    CalendarTableBody.appendChild(thisRow) ;
    var thisRow = document.createElement("tr") ;
    var thisCell = document.createElement("td") ;
    thisCell.align = "center" ;
    thisCell.colSpan = 7 ;
    thisCell.vAlign = "middle" ;
    var selectMonth = document.createElement("form") ;
    var formText = document.createTextNode("Jump to month:\u00A0\u00A0") ;
    selectMonth.appendChild(formText) ;
    selectMonth.style.fontSize = SmallFontSize ;
    var monthDropdown = document.createElement("select") ;
    BuildSelectionList(yearmonth, monthDropdown) ;
    selectMonth.appendChild(monthDropdown) ;
    thisCell.appendChild(selectMonth) ;
    thisRow.appendChild(thisCell) ;
    CalendarTableBody.appendChild(thisRow) ;
    TheCalendar.appendChild(CalendarTableBody) ;
}

// Display a date in the appropriate color, with events (if there are any)

function ShowDate(yr, mo, dy, dayofweek, currentmonth, currentday, thisCell) {
    var ind, HighlightEvent, tmp;

    thisCell.vAlign = "top" ;
    var MonthDayPara = document.createElement("p") ;
    MonthDayPara.style.textAlign = "right" ;
    MonthDayPara.style.fontSize = FontSize ;
    MonthDayPara.style.fontWeight = 'bold' ;
    MonthDayText = document.createTextNode(dy) ;
    MonthDayPara.appendChild(MonthDayText) ;
    HighlightEvent = true;
    if (dayofweek == SpecialDay) {
        MonthDayPara.style.color = ColorSpecialDay ;
        HighlightEvent = false;
    }
    if ((mo == currentmonth) && (dy == currentday)) {
        MonthDayPara.style.color = ColorToday ;
        HighlightEvent = false;
    }
    ind = (((yr * 100) + mo) * 100) + dy;
    if (Events[ind]) {
        if (HighlightEvent) {
            MonthDayPara.style.color = ColorEvent ;
        }
        Events[ind].style.fontSize = SmallFontSize ;
        thisCell.appendChild(MonthDayPara) ;
        thisCell.appendChild(Events[ind])  ;
    } else {
        thisCell.appendChild(MonthDayPara) ;
        EventText = document.createTextNode('\u00A0') ;
        var EventPara = document.createElement('p') ;
        EventPara.style.fontSize = SmallFontSize ;
        EventPara.appendChild(EventText) ;
        EventPara.appendChild(document.createElement("br")) ;
        EventPara.appendChild(EventText) ;
        thisCell.appendChild(EventPara) ;
    }
    thisCell.style.border = "solid"
    thisCell.style.borderColor = document.bgColor

}


// Remaining routines are utilities used above

function NumDaysIn(mo,yr) {
    if (mo==4 || mo==6 || mo==9 || mo==11) return 30;
    else if ((mo==2) && LeapYear(yr)) return 29;
    else if (mo==2) return 28;
    else return 31;
}

function LeapYear(yr) {
    if (((yr % 4 == 0) && yr % 100 != 0) || yr % 400 == 0) return true;
    else return false;
}

// fixes a Netscape 2 and 3 bug
function GetFullYear(d) { // d is a date object
    var yr;

    yr = d.getYear();
    if (yr < 1000)
        yr +=1900;
    return yr;
}

function PrevMonth(mth) {
    if (mth == 1) return 12;
    else return (mth-1);
}

function NextMonth(mth) {
    if (mth == 12) return 1;
    else return (mth+1);
}

function PrevYearMonth(yrmth) {
    if ((yrmth % 100) == 1) return ((yrmth-100)+11);
    else return (yrmth-1);
}

function NextYearMonth(yrmth) {
    if ((yrmth % 100) == 12) return ((yrmth-11)+100);
    else return (yrmth+1);
}

function JumpSelect() {
    var monthDropdown = document.getElementById('selectMonth') ;
    var thisyearmonth = monthDropdown.options[monthDropdown.selectedIndex].value ;
    JumpTo(thisyearmonth) ;
}

function JumpTo(thisyearmonth) {

    var mo = thisyearmonth % 100 ;
    var yr = (thisyearmonth - mo) / 100 ;

    var OldCalendar = document.getElementById('TheCalendarTable') ;

    var TheCalendar = document.createElement("table") ;
    BuildCalendar(TheCalendar, mo, yr) ;
    var scr = document.getElementById('CalendarHere') ;
    scr.parentNode.replaceChild(TheCalendar, OldCalendar) ;
}



function BuildSelectionList(current, monthDropdown) {
    var mo, yr, thisyearmonth;

    var index = 0 ;
    thisyearmonth = FirstMonth;
    monthDropdown.id = "selectMonth" ;
    monthDropdown.size = 1 ;
    monthDropdown.style.fontSize = SmallFontSize ;
    // Quotes around "JumpSelect() ;" make the next line stop working.
    monthDropdown.onchange = JumpSelect ;
    while (thisyearmonth <= LastMonth) {
        mo = thisyearmonth % 100 ;
        yr = (thisyearmonth - mo) / 100 ;
        var thisOption = document.createElement("option") ;
        thisOption.value = thisyearmonth ;
        if (thisyearmonth == current) {
            thisOption.selected = true ;
            thisOption.defaultSelected = true ;
        }
        thisOption.text = months[mo] + " " + yr ;
        monthDropdown.options.add(thisOption, index) ;
        index++;
        thisyearmonth = NextYearMonth(thisyearmonth);
    }
}

//  I found this function in Stoyan Stefanov's article at
//  http://www.sitepoint.com/article/take-command-ajax


makeHttpRequest(csv_file, 'CalendarizeContents');

function makeHttpRequest(url, callback_function)
{
    var http_request = false;

    if (window.XMLHttpRequest) { // Mozilla, Safari,...
        http_request = new XMLHttpRequest();
        if (http_request.overrideMimeType) {
            http_request.overrideMimeType('text/xml');
        }
    } else if (window.ActiveXObject) { // IE
        try {
            http_request = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
            try {
                http_request = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {}
        }
    }

    if (!http_request) {
        alert('Unfortunatelly you browser doesn\'t support this feature.');
        return false;
    }
    http_request.onreadystatechange = function() {
        if (http_request.readyState == 4) {
            if (http_request.status == 200) {
                eval(callback_function + '(http_request.responseText)');
            } else {
                alert('There was a problem with the request.(Code: ' + http_request.status + ')');
            }
        }
    }
    http_request.open('GET', url, true);
    http_request.send(null);
}

function CalendarizeContents(text) {
    BCCcsv_to_events(text);
    ShowCalendar();
}


//  A lot of the ideas in this function originated in the words (code) of
//  Laurent Bugnion (of GalaSoft) in replies to a question at
//  http://www.thescripts.com/forum/thread91725.html

function BCCcsv_to_events(csv_events) {

    var lines = csv_events.split('\n');
    for (i=0; i < lines.length; i++) {
        var One_Town_Event = lines[i].split( ',' ) ;

        // Change Date from Calendar Creator format to Kevin's Calendar format
        var strDate = One_Town_Event[0].split('/') ;
        if (strDate[0].length != 2) {
            if (strDate[0].length = 1) {
                strDate[0] = "0" + strDate[0] ;
            } else {
                strDate[0] = "01" ;
            }
        }
        if (strDate[1].length != 2) {
            if (strDate[1].length = 1) {
                strDate[1] = "0" + strDate[1] ;
            } else {
                strDate[1] = "01" ;
            }
        }
        if (strDate[2].length != 4) {
            if (strDate[2].length = 2) {
                strDate[2] = "20" + strDate[2] ;
            } else {
                strDate[2] = "1995" ;
            }
        }
        var Date_Str = strDate[2] + strDate[0] + strDate[1] ;
        Town_Event_Date = parseInt(Date_Str);
        // Extract the event text from the Calendar Creator .csv & strip quotes
        Town_Event_Text = One_Town_Event[3].substring( 1, One_Town_Event[3].length - 1);
        // Call DefineEvent with the appropriate null values in the other four spots
        DefineEvent(Town_Event_Date, Town_Event_Text, "", "", 0, 0);
    }
}
