/* Loads the Google data JavaScript client library */
google.load("gdata", "1.x");
var itemList = null;
var kinesisList = null;
var isIE = ((document.all) ? true : false);
var classesURL = 'http://www.google.com/calendar/feeds/5q9suibt2l8veimt1tqftsjv14@group.calendar.google.com/public/full';
var kinesisURL = 'http://www.google.com/calendar/feeds/fskvgof2sr7r219glm0vbgq484@group.calendar.google.com/public/full';
var classesLoaded = false;
var kinesisLoaded = false;

/* Our initial load of the schedule will be today's date. Later, future weeks of the 
   schedule may get looked at.
*/
var curSearchDate = getFirstDayOfSearchWeek(flushTime(new Date()));
var curKinesisDate = getFirstDayOfSearchWeek(flushTime(new Date()));
var isFuture = false;

var ajaxDir = 'http://www.lifelikeluster.com/ajax/';

function prepAnnounce(msg) {
    var s = msg.toString();

    s = s.replace(/[[]b](.*?)[[]\/b]/g, "<b>$1</b>");
    s = s.replace(/[[]i](.*?)[[]\/i]/g, "<i>$1</i>");
    s = s.replace(/[[]u](.*?)[[]\/u]/g, "<u>$1</u>");
    s = s.replace(/[[]url=(.*?)](.*?)[[]\/url]/g, "<a href='$1' target='_blank'>$2</a>");

    return s;
}

jQuery.fn.center = function() {
    this.css("position", "absolute");
    this.css("top", ($(window).height() - this.height()) / 2 + $(window).scrollTop() + "px");
    this.css("left", ($(window).width() - this.width()) / 2 + $(window).scrollLeft() + "px");
    return this;
}

jQuery.fn.showLoad = function(isShow) {
    this.css("display", (isShow) ? "inline" : "none");
}

$(document).ready(function() {
    //Getting the scheduling announcements via JSONP and jQuery.
    $.getJSON(ajaxDir + "getannouncements.aspx?callback=?", function(data) {
        $.each(data, function(i, item) {
            $('<li></li>')
                 .html(prepAnnounce(item['note']))
                 .appendTo('#announcementList ul');
        });
    });

    //Enabling the click function of the "next week" link.
    $("#future").click(function() {
        $("#listTable").empty();
        $("#kinesisTable").empty();
        checkFuture(curSearchDate);
        setHeader(curSearchDate);
        loadCalendar(curSearchDate, classesURL, listEvents);
        loadCalendar(curKinesisDate, kinesisURL, listKinesis);
    });

    //Enabling the click function of the "last week" link.
    $("#past").click(function() {
        $("#listTable").empty();
        $("#kinesisTable").empty();
        curSearchDate.setDate(curSearchDate.getDate() - 14);
        curKinesisDate.setDate(curKinesisDate.getDate() - 14);
        checkFuture(curSearchDate);
        setHeader(curSearchDate);
        loadCalendar(curSearchDate, classesURL, listEvents);
        loadCalendar(curKinesisDate, kinesisURL, listKinesis);
    });

    //Enabling the click function of the "current week" link.
    $("#current").click(function() {
        $("#listTable").empty();
        $("#kinesisTable").empty();
        curSearchDate = getFirstDayOfSearchWeek(flushTime(new Date()));
        checkFuture(curSearchDate);
        setHeader(curSearchDate);
        loadCalendar(curSearchDate, classesURL, listEvents);
        loadCalendar(curKinesisDate, kinesisURL, listKinesis);
    });
});

function init() {
  // init the Google data JS client library with an error handler
    itemList = document.getElementById('listTable');
    kinesisList = document.getElementById('kinesisTable');
    google.gdata.client.init(handleGDError);

    //Show the date range for the current week.
    checkFuture(curSearchDate);
    setHeader(curSearchDate);
    loadCalendar(curSearchDate, classesURL, listEvents);
    loadCalendar(curKinesisDate, kinesisURL, listKinesis);
}

/**
 * Uses Google data JS client library to retrieve a calendar feed from the specified
 * URL. The feed is controlled by several query parameters and a callback 
 * function is called to process the feed results.
 *
 * @param {Date} searchDate is the date that is used for a search.
 * @param {String} calURL is the URL of the Google Calendar to return results from.
 * @param {function} callBackFunc is the callback function to call once results come back.
 */  
function loadCalendar(searchDate, calURL, callBackFunc) {
    $("#loadingBox").showLoad(true);
  var service = new 
      google.gdata.calendar.CalendarService('clubzum-clubzum.com-1.0');
  var query = new google.gdata.calendar.CalendarEventQuery(calURL);
  query.setOrderBy('starttime');
  query.setSortOrder('ascending');
  query.setSingleEvents(true);
  var workDate = new Date();
  
  workDate = searchDate;
  workDate = getFirstDayOfSearchWeek(workDate);

  // Create and set the minimum and maximum start time for the date query
  var startMin = google.gdata.DateTime.fromIso8601(getIso8601Date(workDate, false));
  var startMax = google.gdata.DateTime.fromIso8601(getIso8601Date(workDate, true));

  query.setMinimumStartTime(startMin);
  query.setMaximumStartTime(startMax);
  query.setMaxResults(75);

  service.getEventsFeed(query, callBackFunc, handleGDError);
}

/**
 * Callback function for the Google data JS client library to call with a feed 
 * of events retrieved.
 *
 * Creates an unordered list of events in a human-readable form.  This list of
 * events is added into a div called 'events'.  The title for the calendar is
 * placed in a div called 'calendarTitle'
 *
 * @param {json} feedRoot is the root of the feed, containing all entries 
 */ 
function listEvents(feedRoot) {
    var entries = feedRoot.feed.getEntries();
    try {
        renderEvents(entries, itemList);
    }
    catch (e) {
        alert(e);
    }

    classesLoaded = true;
    if (classesLoaded)
        $("#loadingBox").showLoad(false);
}

function listKinesis(feedRoot) {
    var entries = feedRoot.feed.getEntries();
    try {
        renderEvents(entries, kinesisList);
    }
    catch (e) {
        alert(e);
    }

    kinesisLoaded = true;
    if (classesLoaded && kinesisLoaded) {
        $("#loadingBox").showLoad(false);
        classesLoaded = false;
        kinesisLoaded = false;
    }
}

function renderEvents(calEntries, resultsTable) {
    var currentDay = 1;
    var isFirst = true;

    var len = calEntries.length;

    for (var i = 0; i < len; i++) {
        var entry = calEntries[i];
        var title = entry.getTitle().getText();
        var startDateTime = null;
        var startJSDate = null;
        var endDateTime = null;
        var endJSDate = null;
        var times = entry.getTimes();

        var curEventID = entry.getId();
        var idFromHref = "";

        if (times.length > 0) {
            startDateTime = times[0].getStartTime();
            startJSDate = startDateTime.getDate();
            endDateTime = times[0].getEndTime();
            endJSDate = endDateTime.getDate();
        }
        var locations = entry.getLocations();
        var where = null;
        if (locations.length > 0) {
            where = locations[0].getValueString();
        }
        var entryLinkHref = null;
        if (entry.getHtmlLink() != null) {
            entryLinkHref = entry.getHtmlLink().getHref();
            if (entryLinkHref.indexOf("eid=") > -1)
                idFromHref = entryLinkHref.substr(entryLinkHref.indexOf("eid=") + 4, entryLinkHref.length - entryLinkHref.indexOf("eid="));
        }

        //Custom object data:
        custom = null;

        try {

            if (entry.getContent() != null) {
                var getJSON = "cData = " + entry.getContent().getText();
                eval(getJSON);
                custom = cData;
            }
        }
        catch (error) {
            //Problem getting custom properties. Create an object with all defaults set to nothing for display.
            //This is better than the app crashing.
            custom = { "instructor": "TBA", "reservation": false };
        }

        if (startJSDate.getDay() != currentDay) {
            currentDay = startJSDate.getDay();
            isFirst = true;
            addSpacerRow(resultsTable);
        }

        addRow(
        resultsTable
        , currentDay
        , isFirst
        , formatTimeString(startJSDate) + "-" + formatTimeString(endJSDate)
        , title
        , where
        , custom
        );
        if (isFirst)
            isFirst = false;
    } // End for loop
}

function addRow(resultsTbl, dayNum, isFirst, time, className, loc, custom)
{
    var instr, max, resQuired, isNew, isFee, isSub, subName, isNewTime, canceled, feeAmount, hilite;
    instr = ((custom.instructor != null) ? custom.instructor : '');
    resQuired = ((custom.reservation != null) ? custom.reservation : false);
    isNew = ((custom.isnew != null) ? custom.isnew : false);
    isFee = ((custom.fee != null) ? custom.fee : false);
    isSub = (custom.sub != null);
    subName = ((custom.sub != null) ? custom.sub : '');
    isNewTime = ((custom.newtime != null) ? custom.newtime : false);
    canceled = ((custom.canceled != null) ? custom.canceled : false);
    hilite = ((custom.hilite != null) ? custom.hilite : false);
    max = ((custom.max != null) ? custom.max : 50);
    feeAmount = ((custom.feeamount != null) ? custom.feeamount : 0);

    if (resultsTbl != null)
    {
        var todaysDate = new Date();
        var todayHiLite = false;
        if(todaysDate.getDay() == dayNum && !isFuture)
            todayHiLite = true;
                       
        var row = document.createElement('tr');
        row.setAttribute('valign','top');
        var col1 = document.createElement('td');
        //					<td class="subbrownlight" width="7" bgcolor="#E0D7C7">&nbsp;</td>
        applyClass('subbrownlight', col1);
        col1.setAttribute('width', '7');
        //Background colors: single class hilite overwrites all, then current day background, then normal.
        if(hilite)
            col1.setAttribute('bgColor', '#ffffff');
        else if (todayHiLite)
            col1.setAttribute('bgColor', '#A3CDEB');
        else
            col1.setAttribute('bgColor', '#E0D7C7');
        
        col1.appendChild(document.createTextNode('\u00a0'));
        row.appendChild(col1);

        var col2 = document.createElement('td');
        //					<td class="subbrown" width="48" bgcolor="#E0D7C7">Mon</td>
        col2.setAttribute('width', '48');
        if (hilite) {
            col2.setAttribute('bgColor', '#ffffff');
            applyClass('subbrownlight', col2);
        }
        else if (todayHiLite)
        {
            col2.setAttribute('bgColor', '#A3CDEB');
            applyClass('subblue', col2);
        }    
        else
        {
            col2.setAttribute('bgColor', '#E0D7C7');
            applyClass('subbrown', col2);
        }    
        col2.setAttribute('vAlign', 'top');
        if(isFirst)
            col2.appendChild(document.createTextNode(getDayName(dayNum)));
        else
            col2.appendChild(document.createTextNode('\u00a0'));
        row.appendChild(col2);
        
        var col3 = document.createElement('td');
        //					<td class="subbrownlight" width="15">&nbsp;</td>
        applyClass('subbrownlight', col3);
        col3.setAttribute('width', '15');
        if (hilite)
            col3.setAttribute('bgColor', '#ffffcc');
        else if (todayHiLite)
            col3.setAttribute('bgColor', '#ffffff');
        col3.appendChild(document.createTextNode('\u00a0'));
        row.appendChild(col3);
        
        var col4 = document.createElement('td');
        //					<td class="subbrownlight" width="96">6:30-7:30A</td>
        applyClass(((isNewTime == true) ? 'newTime' : 'subbrownlight'), col4);

        col4.setAttribute('width', '96');
        col4.setAttribute('vAlign', 'top');
        if (hilite)
            col4.setAttribute('bgColor', '#ffffcc');
        else if (todayHiLite)
            col4.setAttribute('bgColor', '#ffffff');
        if (!isNewTime)
            col4.appendChild(document.createTextNode(time));
        else
        {
            var newTimeSpan = document.createElement('span');
            newTimeSpan.setAttribute('title', 'Please note new start time for this class.');
            newTimeSpan.appendChild(document.createTextNode(time));
            col4.appendChild(newTimeSpan);
        }
        row.appendChild(col4);

        var col5 = document.createElement('td');
        //										<td class="subbrownlight" width="20">&nbsp;</td>
        applyClass('subbrownlight', col5);
        if (hilite)
            col5.setAttribute('bgColor', '#ffffcc');
        else if (todayHiLite)
            col5.setAttribute('bgColor', '#ffffff');
        col5.setAttribute('width', '20');
        col5.setAttribute('align', 'right');

        if(isFee)
        {
            var astx = document.createElement('img');
            //<img src="img/icon_res.gif" alt="icon" width="10" height="10" style="padding-top: 4px">
            astx.setAttribute('src','img/icon_fee.gif');
            astx.setAttribute('alt','icon');
            astx.setAttribute('width','10');
            astx.setAttribute('height','10');
            col5.appendChild(astx);
        }
        if (resQuired) {
            var astx = document.createElement('img');
            //<img src="img/icon_res.gif" alt="icon" width="10" height="10" style="padding-top: 4px">
            astx.setAttribute('src', 'img/icon_res.gif');
            astx.setAttribute('alt', 'icon');
            astx.setAttribute('width', '10');
            astx.setAttribute('height', '10');
            col5.appendChild(astx);
        }
        if (resQuired || isFee) {
            col5.setAttribute('style', 'padding-top: 4px');
        }

        if(!resQuired && !isFee)
            col5.appendChild(document.createTextNode('\u00a0'));
        
        row.appendChild(col5);

        var col6 = document.createElement('td');
        //					<td class="subbrown" width="179">Cycling</td>
        applyClass('subbrown', col6);
        //col6.setAttribute('width', '179');
        if (hilite)
            col6.setAttribute('bgColor', '#ffffcc');
        else if (todayHiLite)
            col6.setAttribute('bgColor', '#ffffff');
        col6.setAttribute('vAlign', 'top');
        col6.appendChild(document.createTextNode(uniReplace(className)));
        if(isNew)
        {
            col6.appendChild(document.createTextNode('\u00a0'));
            var newSpan = document.createElement('span');
            applyClass('subblue', newSpan);
            newSpan.appendChild(document.createTextNode('NEW!'));
            col6.appendChild(newSpan);            
        }
        row.appendChild(col6);

        var col7 = document.createElement('td');
        //					<td class="subbrownlight" width="108">Jessamyn</td>
        var thisClass = 'subbrownlight';
        if(isSub && !canceled)
            thisClass = 'subInstructor';
        else if(canceled)
            thisClass = 'subCanceled';
                
        applyClass(thisClass, col7);
        col7.setAttribute('width', '120');
        if (hilite)
            col7.setAttribute('bgColor', '#ffffcc');
        else if (todayHiLite)
            col7.setAttribute('bgColor', '#ffffff');
        col7.setAttribute('vAlign', 'top');
        if(canceled)
        {
            var offSpan = document.createElement('span');
            offSpan.setAttribute('title', 'This class is canceled this week.');
            offSpan.appendChild(document.createTextNode('CANCELED'));
            col7.appendChild(offSpan);
        }
        else{
            if(isSub)
            {
                var subSpan = document.createElement('span');
                subSpan.setAttribute('title', subName + ' is subbing for ' + instr + ' for this class.');
                subSpan.appendChild(document.createTextNode(subName));
                col7.appendChild(subSpan);
            }
            else
                col7.appendChild(document.createTextNode(instr));
        }    
        row.appendChild(col7);
        
        var col8 = document.createElement('td');
        //					<td class="subbrownlight" width="82">Cycling Area</td>
        applyClass('subbrownlight', col8);
        col8.setAttribute('width', '150');
        if (hilite)
            col8.setAttribute('bgColor', '#ffffcc');
        else if (todayHiLite)
            col8.setAttribute('bgColor', '#ffffff');
        col8.setAttribute('vAlign', 'top');
        col8.appendChild(document.createTextNode(loc));
        row.appendChild(col8);

        resultsTbl.appendChild(row);
    }
}

function uniReplace(val) {
    val = val.replace(/&#8482;/, '\u2122');
    val = val.replace(/&Uuml;/, 'Ü');
    return val;
}

/**
 * Builds a header string indicating the week being displayed in the grid.
 */

function setHeader(date)
{
    var workDate = new Date(date.toString());
    var header = document.getElementById('scheduleHeader');
    var startMonth = workDate.getMonth();
    var result = getMonthName(startMonth) + " " + workDate.getDate() + "-";
    workDate.setDate(workDate.getDate()+6);
    if(startMonth != workDate.getMonth())
        result += getMonthName(workDate.getMonth()) + " ";
        
    result += workDate.getDate();
    
    header.innerHTML = "Schedule for " + result;
}

function getFirstDayOfSearchWeek(dayObj)
{
  if(dayObj.getDay() == 0)
  {
     dayObj.setDate(dayObj.getDate()-6);
  }
  else if (dayObj.getDay() > 1)
  {
     dayObj.setDate(dayObj.getDate()-dayObj.getDay() + 1);
  }
  
  return dayObj;
}

function checkFuture(dateObj)
{
  var futureDate = getFirstDayOfSearchWeek(flushTime(new Date()));

  isFuture = !((futureDate.getMonth() == dateObj.getMonth()) && (futureDate.getDate() == dateObj.getDate()) && (futureDate.getYear() == dateObj.getYear()));
  if(!isFuture)
  {
    $("#past").css("display", "none");
    $("#current").css("display", "none");
 }
  else
  {
    $("#past").css("display", "inline");
    $("#current").css("display", "inline");
  }
}

/**
 * Adds a leading zero to a single-digit number.  Used for displaying dates.
 */
function padNumber(num) {
  if (num <= 9) {
    return "0" + num;
  }
  return num;
}

/**
 * Cross-platform function for applying CSS classes to elements.
 */
function applyClass(className, item)
{
    if(isIE)
        item.className = className;
    else
        item.setAttribute('class', className);
}

/**
 * Sets a datetime objects time to all zeroes.
 */
function flushTime(dateObj)
{
    dateObj.setHours(0);
    dateObj.setMinutes(0);
    dateObj.setSeconds(0);
    dateObj.setMilliseconds(0);
    return dateObj;
}
/**
 * Gets a properly formatted date string to use with Google calendar.
 */
function getIso8601Date(date, addDay)
{
    if(addDay)
    {
        date.setDate(date.getDate()+7);
    }   
    var result = date.getFullYear() + "-" + padNumber(date.getMonth()+1) + "-" + padNumber(date.getDate());

    return result;
}

/**
 * Formats a timestring for display in the schedule grid.
 */
function formatTimeString(startJSDate)
{
    var suffix = "A";
    var hour = startJSDate.getHours();
    
    if(hour >= 12)
        suffix = "P";
        
    hour = (hour > 12) ? hour - 12 : hour;

    return hour + ":" + 
          padNumber(startJSDate.getMinutes()) + suffix;
}

/**
 * Returns a month by name from the JS Date.
 */
function getMonthName(num)
{
    var MonthArray = new Array("January", "February", "March",
                               "April", "May", "June",
                               "July", "August", "September",
                               "October", "November", "December") 
    return MonthArray[num];
}

/**
 * Returns a day by name from the JS Date.
 */
function getDayName(num)
{   
    var DayArray = new Array("Sun", "Mon", "Tue",
                               "Wed", "Thu", "Fri",
                               "Sat") 
    return DayArray[num];
}

/**
 * Adds a spacer row to the schedule listing.
 */
function addSpacerRow(resultsTable)
{
    if(resultsTable != null)
    {            
        var row = document.createElement('tr');
        var col1 = document.createElement('td');
        applyClass('subblue', col1);
        col1.setAttribute('colSpan', '8');
        var img = document.createElement('img');
        img.setAttribute('src','img/space.gif');
        img.setAttribute('width','10');
        img.setAttribute('height','20');
        img.setAttribute('border','0');
        col1.appendChild(img);
        row.appendChild(col1);

        resultsTable.appendChild(row);

        var row2 = document.createElement('tr');
        col1 = document.createElement('td');
        applyClass('subblue', col1);
        col1.setAttribute('colSpan', '8');
        col1.setAttribute('bgColor', '#E0D7C7');
        img = document.createElement('img');
        img.setAttribute('src','img/space.gif');
        img.setAttribute('width','3');
        img.setAttribute('height','3');
        img.setAttribute('border','0');
        col1.appendChild(img);
        row2.appendChild(col1);

        resultsTable.appendChild(row2);
        
        var row3 = document.createElement('tr');
        col1 = document.createElement('td');
        applyClass('subblue', col1);
        col1.setAttribute('colSpan', '8');
        img = document.createElement('img');
        img.setAttribute('src','img/space.gif');
        img.setAttribute('width','10');
        img.setAttribute('height','8');
        img.setAttribute('border','0');
        col1.appendChild(img);
        row3.appendChild(col1);

        resultsTable.appendChild(row3);
    }
}

/**
 * Callback function for the Google data JS client library to call when an error
 * occurs during the retrieval of the feed.  Details available depend partly
 * on the web browser, but this shows a few basic examples. In the case of
 * a privileged environment using ClientLogin authentication, there may also
 * be an e.type attribute in some cases.
 *
 * @param {Error} e is an instance of an Error 
 */
function handleGDError(e) {
  document.getElementById('jsSourceFinal').setAttribute('style', 
      'display:none');
  if (e instanceof Error) {
    /* alert with the error line number, file and message */
    alert('Error at line ' + e.lineNumber +
          ' in ' + e.fileName + '\n' +
          'Message: ' + e.message);
    /* if available, output HTTP error code and status text */
    if (e.cause) {
      var status = e.cause.status;
      var statusText = e.cause.statusText;
      alert('Root cause: HTTP error ' + status + ' with status text of: ' + 
            statusText);
    }
  } else {
    alert(e.toString());
  }
}
    
//attach the init function.
google.setOnLoadCallback(init);