function aigCalender(id) {
    if (id == null)
        id = "";
    var cal = {
        container: null,
        calDateTbID: id + '_calDateTb',
        calHeadMdID: id + '_calHeadMd',
        HeadYrID: id + '_HeadYr',
        popUpNodeId: id + '_popUpNode',
        eventsDataUrl: '/date',
        eventsUrl: '/eventPages',
        currentDate: new Date(),
        currentEvents: null,
        timeout_id: null,
        popUpAlign: 'right',
        //allow only one events popup hover div for the calendar
        popupExists: false,
        //distinguish this var from eventDate, which is used elsewhere in this file
        eventDateForPopup: null,
        // Reference for number of days per month
        calInfo: new Array(),

        Init: function() {

            this.calInfo[0] = { days: 31, name: 'January' };
            this.calInfo[1] = { days: 28, name: 'February' };
            this.calInfo[2] = { days: 31, name: 'March' };
            this.calInfo[3] = { days: 30, name: 'April' };
            this.calInfo[4] = { days: 31, name: 'May' };
            this.calInfo[5] = { days: 30, name: 'June' };
            this.calInfo[6] = { days: 31, name: 'July' };
            this.calInfo[7] = { days: 31, name: 'August' };
            this.calInfo[8] = { days: 30, name: 'September' };
            this.calInfo[9] = { days: 31, name: 'October' };
            this.calInfo[10] = { days: 30, name: 'November' };
            this.calInfo[11] = { days: 31, name: 'December' };

        },

        DrawCalendarDatesData: function() {

            var startDay = 0; // start day of the week (0 - 6) for the month
            var daysInMonth = 0; // number of days in the current month
            var currDate = 1; // current day of the month being displayed
            var dateTable = document.getElementById(this.calDateTbID); // table that contains calendar dates
            var tableRow = null; // row of dates table

            if (null != dateTable) {

                // setup calendar
                this.currentDate.setDate(1); // set to first day of month

                // get day of the week for the first of the month
                startDay = this.currentDate.getDay();

                // get number of days in the month
                daysInMonth = this.calInfo[this.currentDate.getMonth()].days;

                // check for February leap year
                if (1 == this.currentDate.getMonth()) {

                    var currYear = this.currentDate.getFullYear(); // current year (four digit)

                    // if leap year, add an extra day
                    if (true == IsLeapYear(currYear)) {
                        daysInMonth++;
                    }
                }

                // loop through 6 rows (weeks) for each month (the last row being blank for months that only have 5 weeks)
                for (var week = 0; week < 6; week++) {

                    tableRow = dateTable.insertRow(dateTable.rows.length);

                    // loop through each day in the week
                    for (var dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {

                        // check if a date should be printed for this day
                        if ((0 == week) && (dayOfWeek < startDay)) {
                            // if not, then display a blank day
                            this.AddDateCell(tableRow, '\xA0', 0, 0, 0);
                        }
                        else {
                            // display date if there are dates to display
                            if (daysInMonth >= currDate) {
                                var month = this.currentDate.getMonth();
                                var day = currDate;
                                var checkDate = '';
                                var eventDate = '';

                                // setup date to check for events
                                month++;
                                if (month < 10) {
                                    month = '0' + month.toString();
                                }
                                if (day < 10) {
                                    day = '0' + day.toString();
                                }
                                checkDate = this.currentDate.getFullYear().toString() + month + day;
                                if ((null != this.currentEvents) && (null != this.currentEvents[checkDate])) {
                                    eventDate = checkDate;
                                }
                                this.AddDateCell(tableRow, currDate, eventDate, this.currentDate.getFullYear(), month);
                                currDate++;
                            }
                            else {
                                // if not, then display a blank day
                                this.AddDateCell(tableRow, '\xA0', false, 0, 0);
                            }
                        }
                    }

                    tableRow = null;
                }

                // add submit event row
                tableRow = dateTable.insertRow(dateTable.rows.length);

                if (false && null != tableRow) {
                    var tableCell = null;
                    var tableDataContainer = null;
                    var cellData = null;

                    tableCell = tableRow.insertCell(tableRow.cells.length);
                    tableCell.colSpan = 7;

                    tableDataContainer = document.createElement('div');
                    tableDataContainer.className = 'calendarWg-submit-event-container';
                    tableDataContainer = tableCell.appendChild(tableDataContainer);

                    cellData = document.createElement('a');
                    cellData.href = this.eventsUrl + '#submit-new-event';

                    cellData = tableDataContainer.appendChild(cellData);
                    cellData.appendChild(document.createTextNode('Submit New Event'));

                    tableDataContainer = null;
                    tableCell = null;
                    cellData = null;
                }
            }

            return;

        },

        DrawCalendarHeading: function() {

            var headingContainer = null; // heading container DOM object
            var headingControl = null; // calendar control DOM object that resides in the heading container
            var headingText = null; // contains either the month or year of the current calendar

            if (null != this.container) {

                // create heading container
                headingContainer = document.createElement('div');
                headingContainer.className = 'calendarWg-heading-container';

                // append heading container
                this.container.appendChild(headingContainer);

                /*
                The order of creation below is important, as the styles
                are set to 'float: right'.  Should this change, then
                the order below may need to be changed as well.

			    Because with a 'float: right' style, the first element
                will be on the far right, the order below must be
                from right-to-left, rather than left-to-right.
                */

                // create next month control
                var myObj = this;
                headingControl = document.createElement('div');
                headingControl.className = 'calendarWg-control calendarWg-control-next';
                headingControl.onclick = function() { myObj.CalendarMonthNext(); };
                headingControl.appendChild(document.createTextNode('\xa0'));

                // append next control and remove DOM reference
                headingContainer.appendChild(headingControl);

                // append year (four-digit)
                headingText = document.createElement('div');
                headingText.className = 'calendarWg-heading-year';
                headingText.id = this.HeadYrID;
                headingText = headingContainer.appendChild(headingText);
                headingText.appendChild(document.createTextNode(this.currentDate.getFullYear()));

                // append month name
                headingText = document.createElement('div');
                headingText.className = 'calendarWg-heading-month';
                headingText.id = this.calHeadMdID;
                headingText = headingContainer.appendChild(headingText);
                headingText.appendChild(document.createTextNode(this.calInfo[this.currentDate.getMonth()].name));

                // create previous month control
                headingControl = document.createElement('div');
                headingControl.className = 'calendarWg-control calendarWg-control-prev';
                headingControl.onclick = function() { myObj.CalendarMonthPrev(); };
                headingControl.appendChild(document.createTextNode('\xa0'));

                // append previous control and remove DOM reference
                headingContainer.appendChild(headingControl);
            }

            return;
        },

        DrawCalendarDatesHeader: function() {

            var dayOfWeekTable = null; // table that contains the day of the week headings
            var tableContainer = null; // table container for the day of the week table header
            var tableRow = null; // row in day of weeks table
            var tableCell = null; // cell in day of weeks table

            if (null != this.container) {

                // create date table
                dayOfWeekTable = document.createElement('table');
                dayOfWeekTable.id = this.calDateTbID;
                dayOfWeekTable.cellSpacing = 0;
                dayOfWeekTable.cellPadding = 0;
                dayOfWeekTable.border = 0;

                // append table
                this.container.appendChild(dayOfWeekTable);

                // add row for day of week headings
                tableRow = dayOfWeekTable.insertRow(dayOfWeekTable.rows.length);
                var dayName = ['Su', 'Mo', 'Tu', 'We', 'Tu', 'Fr', 'Sa'];
                for (var i = 0; i < 7; i++) {
                    tableCell = tableRow.insertCell(tableRow.cells.length);
                    tableContainer = document.createElement('div');
                    tableContainer.className = 'calendarWg-date-heading';
                    tableContainer = tableCell.appendChild(tableContainer);
                    tableContainer.appendChild(document.createTextNode(dayName[i]));

                }

            }

            return;
        },

        DrawCalendar: function(containerId) {

            this.container = document.getElementById(containerId);

            if (null != this.container) {

                this.RequestDates();
                this.DrawCalendarHeading();
                this.DrawCalendarDatesHeader();
                this.DrawCalendarDatesData();
            }

            return;
        },

        createDailyEventsPopup: function(eventDateForPopup, tableDataContainer) {
            var myObj = this;

            //allow only one popup for calendar
            if (true == this.popupExists) {
                clearTimeout(this.timeout_id);
                this.destroyDailyEventsPopup();
            }

            if (false == this.popupExists) {

                //AJAX call to get actual data
                var innerHtml = this.getDailyEventsForPopup(eventDateForPopup);
                if (innerHtml != null && innerHtml.length > 0) {
                    var popupNode = document.createElement('div');
                    popupNode.className = 'popUpNodeCalendar';
                    popupNode.setAttribute('id', this.popUpNodeId);
                    this.popupExists = true;
                    popupNode.onmouseover = function() { myObj.cancelTimeout(); };
                    popupNode.onmouseout = function() { myObj.setTimeoutForDailyEventsPopup(1000); };
                    popupNode.innerHTML = innerHtml;

                    var popupTarget = document.getElementById(eventDateForPopup);
                    this.appendPopupToDocumentBody(popupNode, popupTarget);
                }
            }
        },

        appendPopupToDocumentBody: function(popupNode, popupTarget) {
            var clientY = document.body.scrollHeight;
            var windowHeight = 0;
            windowHeight = this.getWindowHeight(windowHeight);

            var scrollPos = 0;
            scrollPos = this.getScrollBarPosition(scrollPos);

            //get the offset of the tableDataContainer (which is the parent
            // of date link on the calendar.  we want to attach the popup
            // to the document just to the right of the tableDataContainer
            var arr_winDimensions = new Array();
            arr_winDimensions['height'] = 0;
            arr_winDimensions['width'] = this.container.offsetLeft;
            if (this.popUpAlign == 'right')
                arr_winDimensions['width'] += this.container.offsetWidth;
            arr_winDimensions = this.getOffsetDimensions(popupTarget, arr_winDimensions);

            //must adjust for differences in browser positioning
            var isBrowserIE = this.isIE();
            if (true === isBrowserIE)
                //IE requires a slight adjustment to move the control to the left and down 
                arr_winDimensions['height'] += 0;
            else
                //FF requires moving the control further left and down than IE
                arr_winDimensions['height'] += 20;

            //now absolutly position the element and append it to the document's body.
            popupNode.style.position = "absolute";
            popupNode.style.top = arr_winDimensions['height'] + 'px';
            if (this.popUpAlign == 'right') 
                popupNode.style.left = (arr_winDimensions['width'] - 450) + 'px';
            else
                popupNode.style.left = (arr_winDimensions['width'] + 5 ) + 'px';

            popupNode.style.fontFamily = "sans-serif";
            document.body.appendChild(popupNode);

        },

        getOffsetDimensions: function(targetElement, arr_winDimensions) {

            if (null != targetElement && targetElement.offsetParent) {
                while (targetElement = targetElement.offsetParent) {
                    arr_winDimensions['height'] += targetElement.offsetTop;
                }
            }
            return arr_winDimensions;
        },


        cancelTimeout: function() {
            if (null !== this.timeout_id && true === this.popupExists) {
                clearTimeout(this.timeout_id);
                this.timeout_id = null;
            } else {
                this.destroyDailyEventsPopup();
            }
        },

        setTimeoutForDailyEventsPopup: function(timeToLive) {
            var myObj = this;
            if (null !== this.timeout_id) {
                this.cancelTimeout();
                this.destroyDailyEventsPopup();
            }
            if ((document.getElementById(this.popUpNodeId))) {
                if (null == this.timeout_id && true === this.popupExists) {
                    this.timeout_id = setTimeout(function() { myObj.destroyDailyEventsPopup(); }, timeToLive);
                } else {
                }
            }
        },

        destroyDailyEventsPopup: function() {

            if (true === this.popupExists) {
                //get the element containing the <a> tag
                if ((document.getElementById(this.popUpNodeId)) && (null !== this.timeout_id)) {
                    var currentDaysPopup = document.getElementById(this.popUpNodeId);
                    var currentPopupParentElement = currentDaysPopup.parentNode;
                    currentPopupParentElement.removeChild(currentDaysPopup);
                    this.timeout_id = null;
                    //this is the only place where popupExists should be set to false
                    this.popupExists = false;
                }

            }
        },

        AddDateCell: function(tableRow, cellData, eventDate, currYear, currMonth) {

            var tableCell = null;
            var tableDataContainer = null;
            var eventLink = null;
            var myObject = this;

            if (null != tableRow) {

                tableCell = tableRow.insertCell(tableRow.cells.length);
                tableDataContainer = document.createElement('div');
                tableDataContainer.className = 'calendarWg-date';
                if ('' != eventDate) {
                    tableDataContainer.className += ' calendarWg-date-event';
                    tableDataContainer = tableCell.appendChild(tableDataContainer);
                    eventLink = document.createElement('a');
                    eventLink.href = this.eventsUrl + '/' + eventDate + '.htm';

                    //added to easily get parent node of the current date's element for positioning the popup div.
                    eventLink.setAttribute("id", eventDate);

                    // add event listeners to link for mouse over/out
                    eventLink.onmouseover = function() {
                        myObject.createDailyEventsPopup(eventDate, tableDataContainer);
                    };
                    var myObj = this;
                    eventLink.onmouseout = function() { myObj.setTimeoutForDailyEventsPopup(500); };
                    eventLink = tableDataContainer.appendChild(eventLink);
                    eventLink.appendChild(document.createTextNode(cellData));
                }
                else {
                    tableDataContainer = tableCell.appendChild(tableDataContainer);
                    tableDataContainer.appendChild(document.createTextNode(cellData));
                }

                tableDataContainer = null;
                tableCell = null;
            }

            return;
        },

        CalendarMonthPrev: function() {

            var monthHeading = document.getElementById(this.calHeadMdID);
            var yearHeading = document.getElementById(this.HeadYrID);
            var month = this.currentDate.getMonth(); // get current month

            // check if month is January
            if (0 == month) {

                // decrement year and set month to December
                var year = this.currentDate.getFullYear() - 1;
                this.currentDate.setFullYear(year);
                month = 11;
            }
            else {
                // decrement month index
                month--;
            }

            // set new month in global calendar
            this.currentDate.setMonth(month);

            // get new events
            this.RequestDates();

            // replace month name on calendar
            if (null != monthHeading) {
                this.RemoveChildNodes(monthHeading);
                monthHeading.appendChild(document.createTextNode(this.calInfo[this.currentDate.getMonth()].name));
            }

            // replace year on calendar
            if (null != yearHeading) {
                this.RemoveChildNodes(yearHeading);
                yearHeading.appendChild(document.createTextNode(this.currentDate.getFullYear()));
            }

            // remove old dates
            this.RemoveDates();

            // create new dates
            this.DrawCalendarDatesData();

            return;
        },

        CalendarMonthNext: function() {

            var monthHeading = document.getElementById(this.calHeadMdID);
            var yearHeading = document.getElementById(this.HeadYrID);
            var month = this.currentDate.getMonth(); // get current month

            // check if month is December
            if (11 == month) {

                // increment year and set month to January
                var year = this.currentDate.getFullYear() + 1;
                this.currentDate.setFullYear(year);
                month = 0;
            }
            else {
                // increment month index
                month++;
            }

            // set new month in global calendar
            this.currentDate.setMonth(month);

            // get new events
            this.RequestDates();

            // replace month name on calendar
            if (null != monthHeading) {
                this.RemoveChildNodes(monthHeading);
                monthHeading.appendChild(document.createTextNode(this.calInfo[this.currentDate.getMonth()].name));
            }

            // replace year on calendar
            if (null != yearHeading) {
                this.RemoveChildNodes(yearHeading);
                yearHeading.appendChild(document.createTextNode(this.currentDate.getFullYear()));
            }

            // remove old dates
            this.RemoveDates();

            // create new dates
            this.DrawCalendarDatesData();

            return;
        },

        IsLeapYear: function(year) {

            var isLeapYear = false;

            /*
            A year is a leap year if it is divisible by 4.  If the year is also divisible
            by 100, then it is not a leap year UNLESS it is also divisible by 400.
            */
            if (0 == (year % 4)) {

                // preliminarily set leap year to true
                isLeapYear = true;

                // is year divisible by 100?
                if (0 == (year % 100)) {

                    // if year is also not divisible by 400, then it is not a leap year
                    if (0 != (year % 400)) {
                        isLeapYear = false;
                    }
                }
            }

            return isLeapYear;
        },

        RemoveDates: function() {

            var dateTable = document.getElementById(this.calDateTbID);

            if (null != dateTable) {

                // remove all but the header row
                while (1 < dateTable.rows.length) {

                    // remove all cells
                    while (0 < dateTable.rows[1].cells.length) {

                        // remove cells and data from cells
                        this.RemoveChildNodes(dateTable.rows[1].cells[0]);
                        dateTable.rows[1].deleteCell(0);
                    }

                    // remove table row
                    dateTable.deleteRow(1);
                }
            }

            return;
        },

        RemoveChildNodes: function(container) {

            while (true == container.hasChildNodes()) {
                this.RemoveChildNodes(container.lastChild);
                container.removeChild(container.lastChild);
            }

            return;
        },

        getDailyEventsForPopup: function(eventDateForPopup) {
            var dailyEventRequest = this.GetXmlRequest();
            var dailyEventRequest_url = this.eventsDataUrl + '/'
                + this.currentDate.getFullYear() + '/'
                + (this.currentDate.getMonth() + 1) + '/'
                + eventDateForPopup + '.htm';
            //var dailyEventString = '';  //hold the result
            // the result of the query will be a markup-formatted string which will be ready for insertion into the popup div.

            var dailyEvents = null;
            if (null != dailyEventRequest) {
                dailyEventRequest.open('GET', dailyEventRequest_url, false);
                dailyEventRequest.send(null);
                if (dailyEventRequest.status == 200)
                    dailyEvents = dailyEventRequest.responseText;
            }
            //console.log(dailyEvents);	
            return dailyEvents;
        },

        RequestDates: function() {

            var request = this.GetXmlRequest();
            var request_url = this.eventsDataUrl + '/'
                + this.currentDate.getFullYear() + '/'
                + (this.currentDate.getMonth() + 1) + '/dates.htm';

            if (null != request) {
                request.open('GET', request_url, false);
                request.send(null);
                if (request.status == 200)
                    this.currentEvents = eval("(" + request.responseText + ")");
                else
                    this.currentEvents = [];
            }

            return;
        },

        GetXmlRequest: function() {

            var obj_xml_request = null;

            // firefox, Opera, Safari
            try {
                obj_xml_request = new XMLHttpRequest();
            }
            catch (e) {

                // Internet Explorer
                try {
                    obj_xml_request = new ActiveXObject('Msxml2.XMLHTTP');
                }
                catch (e) {

                    // Internet Explorer (alternative)
                    try {
                        obj_xml_request = new ActiveXObject('Microsoft.XMLHTTP');
                    }
                    catch (e) {
                        alert('Sorry, your browser does not support AJAX.');
                    }
                }
            }

            return obj_xml_request;
        },

        getWindowHeight: function(windowHeight) {
            if (!window.innerHeight) {
                //using IE
                if (0 == document.documentElement.clientHeight) {
                    //using IE quirks mode
                    windowHeight = document.body.clientHeight;
                } else {
                    //using IE strict
                    windowHeight = document.documentElement.clientHeight;
                }
            } else {
                // NOT using IE
                windowHeight = window.innerHeight;
            } //!win.innerHeight

            return windowHeight;
        },

        isIE: function() {
            if ('number' == typeof (window.pageYOffset)) {
                //NOT IE
                return false;

            } else if (document.body && document.body.scrollTop) {
                //DOM compliant IE
                return true;

            } else if (document.documentElement && document.documentElement.scrollTop) {
                //IE 6 standards compliant mode
                return true;
            }
        },

        getScrollBarPosition: function(scrollPos) {
            if ('number' == typeof (window.pageYOffset)) {
                // non-IE
                scrollPos = window.pageYOffset;
            } else if (document.body && document.body.scrollTop) {
                // DOM compliant IE
                scrollPos = document.body.scrollTop;
            } else if (document.documentElement && document.documentElement.scrollTop) {
                //IE6 standards compliant mode
                scrollPos = document.documentElement.scrollTop;
            }

            return scrollPos;
        }
    };

    cal.Init();
    return cal;
}






