/* $Id$ */

/**
 * @file
 * jQuery Bedework JSON feed parser.
 *
 * Initialize instances for each different output type. The script will take in
 * as input a JSON object (generated from Bedework) and output through the
 * callback (formatter) function provided upon initialization.
 */
(function($) {
  var area;
  var eventsGlobal = [];
  var limit = 0;
  $.fn.parseFeed = function(_callback, _area, _categories, max, dateRangeMin, dateRangeMax, _exclude, singleDate) {
    eventsGlobal = [];
    if (max != "undefined") {
      limit = max;
    }
    // If we are pulling multiple events, but a single date
    if (singleDate != true)
      singleDate = false;
    else
      var singleDateStart = 0;
    this.each(function() {
      var events = this.bwEventList.events;

      $(events).each(function(k) {
        // If event is not confirmed, then should not exist in feed
        if (events[k].status.toLowerCase() !== "confirmed") {
          return;
        }

        // Default to all events being valid
        events[k].valid = 1;

        // If no categories defined, all events are valid anyways
        if (_categories instanceof Array && _categories.length > 0) {
          var i;
          for (i = 0; i < _categories.length; i++) {
            // Check if all categories defined are contained in BW object
            // At the end of each iteration, bit should be 1 or 0
            if ($.inArray(_categories[i], events[k].categories) == -1) {
              events[k].valid = 0;
              return;
            }
            else {
              events[k].valid = 1;
            }
          }
        }

        // Exclude events with these categories
        if (_exclude instanceof Array && _exclude.length > 0) {
          var j;
          for (j = 0; j < _exclude.length; j++) {
            // Check if all categories defined are contained in BW object
            // At the end of each iteration, bit should be 1 or 0
            if (!($.inArray(_exclude[j], events[k].categories) == -1)) {
              events[k].valid = 0;
              return;
            }
            else {
              events[k].valid = 1;
            }
          }
        }

        // Split our UTC start date string into appropriate variables
        var s_year = events[k].start.datetime.substr(0,4);
        var s_month = events[k].start.datetime.substr(4,2);
        var s_day = events[k].start.datetime.substr(6,2);
        var s_hour = events[k].start.datetime.substr(9,2);
        var s_second = events[k].start.datetime.substr(11,2);
        var s_date = new Date(s_year, s_month-1, s_day, s_hour, s_second);

        // Split our UTC end date string into appropriate variables
        var e_year = events[k].end.datetime.substr(0,4);
        var e_month = events[k].end.datetime.substr(4,2);
        var e_day = events[k].end.datetime.substr(6,2);
        var e_hour = events[k].end.datetime.substr(9,2);
        var e_second = events[k].end.datetime.substr(11,2);
        var e_date = new Date(e_year, e_month-1, e_day, e_hour, e_second);
    
        // Reformat using plugin's method
        var event_start = s_date.getTime();
        var event_end = e_date.getTime();
        
        // If available, check date ranges against start
        if (dateRangeMin instanceof Date) {
          // Event is valid in range iff end date exceeds dateRangeMin
          if (event_end < dateRangeMin.getTime()) {
            events[k].valid = 0;
            return;
          }
        }

        // If available, check date ranges against end
        if (dateRangeMax instanceof Date) {
          // Event is valid in range iff start date before dateRangeMax
          if (event_start > dateRangeMax.getTime()) {
            events[k].valid = 0;
            return;
          }
        }

        // Re-write our x-properties for new format
        if (typeof events[k].xproperties.length == "number") {
          var xprop = events[k].xproperties;
          events[k].xproperties = null;
          var x = new Object;
          $(xprop).each(function(i) {
            for(var j in xprop[i]) {
              x[j] = xprop[i][j].values.text;
            }
          });
          events[k].xproperties = x;
        }
        // Re-write for legacy format
        else if (typeof events[k].xproperties['X-BEDEWORK-ALIAS'] == "object") {
          var xprop = events[k].xproperties;
          events[k].xproperties = null;
          if (xprop['X-BEDEWORK-ALIAS'])
            xprop['X-BEDEWORK-ALIAS'] = xprop['X-BEDEWORK-ALIAS'].values.text;
          if (xprop['X-BEDEWORK-EVENT-TYPE'])
            xprop['X-BEDEWORK-EVENT-TYPE'] = xprop['X-BEDEWORK-EVENT-TYPE'].values.text;
          if (xprop['X-BEDEWORK-IMAGE'])
            xprop['X-BEDEWORK-IMAGE'] = xprop['X-BEDEWORK-IMAGE'].values.text;
          if (xprop['X-BEDEWORK-SUBMITTEDBY'])
            xprop['X-BEDEWORK-SUBMITTEDBY'] = xprop['X-BEDEWORK-SUBMITTEDBY'].values.text;
          if (xprop['X-BEDEWORK-SUPPLIMENTAL-URL'])
            xprop['X-BEDEWORK-SUPPLIMENTAL-URL'] = xprop['X-BEDEWORK-SUPPLIMENTAL-URL'].values.text;
          events[k].xproperties = xprop;
        }

        // Create new event object for easier formatting
        var e = [];
        e['guid'] = events[k].guid;
        e['rid'] = events[k].recurrenceId;
        e['title'] = events[k].summary;
        e['link'] = events[k].link;
        e['oneliner'] = events[k].description;
        e['thumb'] = "";
        if (events[k].xproperties['X-BEDEWORK-IMAGE']) {
          e['thumb'] = events[k].xproperties['X-BEDEWORK-IMAGE'];
        }
        e['taxonomy'] = "";
        if (events[k].xproperties['X-BEDEWORK-EVENT-TYPE']) {
          e['taxonomy'] = events[k].xproperties['X-BEDEWORK-EVENT-TYPE'];
        }
        if (events[k].xproperties['X-BEDEWORK-SUPPLIMENTAL-URL']) {
          e['ticketing'] = events[k].xproperties['X-BEDEWORK-SUPPLIMENTAL-URL'];
        }
        e['where'] = events[k].location.address.replace("EMPAC ", "");
        e['start'] = s_date;
        e['end'] = e_date;

        // Setup event type bits
        e['ticketed'] = (e['ticketing'] ? 1 : 0);
        e['free'] = !events[k].ticketed;
        e['invite'] = (($.inArray("OpenToInviteesOnly", events[k].categories) > -1) ? 1 : 0);

        // Check for events existing on same day
        if (singleDate && singleDateStart) {
          if (s_year + ":" + s_month + ":" + s_day != singleDateStart) {
            events[k].valid = 0;
            return;
          }
        }

        // Check to see if event is already in array
        if (eventsGlobal.length > 0) {
          $(eventsGlobal).each(function(i) {
            if ((eventsGlobal[i]['guid']+eventsGlobal[i]['rid']) == (events[k].guid+events[k].recurrenceId)) {
              events[k].valid = 0;
              return;
            }
          });
        }

        // If the event is a valid filtered event, then push to return array
        if (events[k].valid == 1) {
          if (singleDate && !singleDateStart) {
            singleDateStart = s_year + ":" + s_month + ":" + s_day;
          }
          eventsGlobal.push(e);
        }
      });
    });

    // Default to listing view formatter
    if (_callback == "undefined" || !(typeof $.fn[_callback] == "function")) {
      _callback = "formatListing";
    }

    // Process only valid events
    area = _area;

    // Limit our events if specified
    if (limit > 0 && !singleDate) {
      eventsGlobal = eventsGlobal.splice(0, limit);
    }
    if (eventsGlobal.length < 1) {
      $(_area).hide();
      return;
    }
    test = eventsGlobal;

    return $.fn[_callback](eventsGlobal);
  }

  // Returns date (string) in proper format according to given formatter
  $.fn.dateFormat = function(d, f) {

    // Special characters
    var special = ['m', 'd', 'y', 'h', 'i', 'n', 'w', 'a'];
    // Month names and abbreviations
    var mFull = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    var mAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    var dFull = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    var dAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

    // Our current pattern
    var p = '';
    // Return string
    var r = '';
    for (var i = 0; i < f.length; i++) {
      // Current character
      var cp = f.charAt(i);
      p += cp;
      // This is where we check for each pattern and substitute appropriate date value
      switch (p) {
        case "N":
          r += mFull[d.getMonth()]; // Full month name
          p = '';
          break;
        case "n":
          r += mAbbr[d.getMonth()]; // 3-letter month name
          p = '';
          break;
        case "W":
          r += dFull[d.getDay()]; // Full day name
          p = '';
          break;
        case "w":
          r += dAbbr[d.getDay()]; // 3-letter day name
          p = '';
          break;
        case "M":
          r += (d.getMonth()+1 < 10 ? '0' : '') + parseInt(d.getMonth()+1); // Month with leading zeros
          p = '';
          break;
        case "m":
          r += d.getMonth()+1; // Month
          p = '';
          break;
        case "D":
          r += (d.getDate() < 10 ? '0' : '') + d.getDate(); // Day with leading zeros
          p = '';
          break;
        case "d":
          r += d.getDate(); // Day
          p = '';
          break;
        case "y":
          r += substr(d.getFullYear(), 2, 2); // Last 2 digits of year
          p = '';
          break;
        case "Y":
          r += d.getFullYear(); // Full 4-character date representation (YYYY-format)
          p = '';
          break;
        case "H":
          var h = d.getHours();
          if (h > 12) {
           h -= 12;
          }
          else if (h == 0) {
            h = 12;
          }
          r += (h < 10 ? '0' : '') + h; // Hours with leading zeros
          p = '';
          break;
        case "h":
          var h = d.getHours();
          if (h > 12) {
            h -= 12;
          }
          else if (h == 0) {
            h = 12;
          }
          r += h; // Hours
          p = '';
          break;
        case "I":
          r += (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); // Minutes with leading zeros
          p = '';
          break;
        case "i":
          r += d.getMinutes(); // Minutes
          p = '';
          break;
        case "A":
          r += (d.getHours() >= 12 ? "PM" : "AM"); // Capital AM or PM
          p = '';
          break;
        case "a":
          r += (d.getHours() >= 12 ? "pm" : "am"); // Lowercase am or pm
          p = '';
          break;
        default:
          // This preserves all other characters in our pattern so characters like commas, slashes, etc
          // are preserved and outputted with the variables.
          if ($.inArray(cp.toLowerCase(), special) == -1) {
            r += cp;
            p = '';
          }
          break;
      }
    }

    return r;
  }

  // Default season index formatter
  $.fn.formatListing = function(events) {
    var innerHTML = '';
    $(events).each(function(i) {
      if ($.fn.dateFormat(this.start, "N d") != $.fn.dateFormat(this.end, "N d")) {
        var dateFormat = "N d";
        var showEnd = true;
      }
      else {
        var dateFormat = "W N d, h:I A";
        var showEnd = false;
      }
      // Setup the start and end dates
      var start = $.fn.dateFormat(this.start, dateFormat);
      var end = $.fn.dateFormat(this.end, dateFormat);

      innerHTML += "\n" + '<div class="' + (i % 2 == 0 ? "even" : "odd") + '"><img src="' + this.thumb + '"><p class="taxo">' + this.taxonomy + '</p><h3><a href="' + this.link + '">' + this.title + '</a></h3><p class="date">' + start + (showEnd ? ' &ndash; ' + end : '') + ' |  ' + this.where + '</p><p>' + this.oneliner + '</p></div>';
    });
    $(area).append(innerHTML);
  }

  // Default sidebar index formatter
  $.fn.formatSidebar = function(events) {
    var dateFormat = "M/D";
    $(events).each(function(i) {
      // Setup the start and end dates
      var start = $.fn.dateFormat(this.start, dateFormat);
      var end = $.fn.dateFormat(this.end, dateFormat);

      $(area).html($(area).html() + "\n" + '<p class="linkSm">' + this.taxonomy.toUpperCase() + '<br />' + start + (start != end ? ' &ndash; ' + end : '') + ' &mdash; <a href="' + this.link + '"><em>' + this.title + '</em></a></p>');
    });
  }

  // Default preview formatter
  $.fn.formatPreview = function(events) {
    var dateFormat = "W N d, h:I A";
    var innerHTML = '';

    // Some mathematics to divide into two columns
    var split = Math.ceil(events.length/2);
    innerHTML += "\n<td>";
    $(events).each(function(i) {
      // Setup the start and end dates
      var start = $.fn.dateFormat(this.start, dateFormat);
      var end = $.fn.dateFormat(this.end, dateFormat);
      if (i == split) {
        innerHTML += "\n</td><td>";
      }
      innerHTML += "\n" + '<ul><li class="category">' + this.taxonomy + '</li><li class="title"><a href="' + this.link + '">' + this.title + '</a></li><li class="date">' + start + '</li></ul>';
    });
    $(area).append(innerHTML + "\n</td>");
  }

  // Default formatter for Up Next from EMPAC
  $.fn.formatUpNext = function(events) {
    var innerHTML = '<h5>UP NEXT FROM EMPAC:</h5>';

    $(events).each(function(i) {
      if ($.fn.dateFormat(this.start, "N d") != $.fn.dateFormat(this.end, "N d")) {
        var dateFormat = "N d";
        var showEnd = true;
      }
      else {
        var dateFormat = "W N d, h:I A";
        var showEnd = false;
      }
      var start = $.fn.dateFormat(this.start, dateFormat);
      var end = $.fn.dateFormat(this.end, dateFormat);
		  innerHTML += '<h4>' + this.taxonomy.toUpperCase() + '</h4><h2><a href="' + this.link + '">' + this.title + '</a></h2><p class="date">' + start + (showEnd ? ' &ndash; ' + end : '') + '</p><p class="normal">' + this.oneliner + '<br />';

		  if (this.invite) {
		    innerHTML += '<span class="tix">BY INVITATION ONLY</span>';
		  }
		  else if (this.taxonomy.toUpperCase() == "WORKSHOP") {
		    innerHTML += '<a class="tix" href="' + this.link + '">&raquo; More Information</a>';
		  }
		  else if (this.ticketed) {
		    innerHTML += '<a class="tix" href="' + this.ticketing + '">&raquo; Buy Tickets</a>';
		  }
		  else if (this.free) {
		    innerHTML += '<span class="tix">FREE + Open to the Public</span>';
		  }
		  innerHTML += '</p>';
    });

    $(area).append(innerHTML);
  }

  // Default formatter for Upcoming Events
  // Remove url for summer 05.25 skj <h4><a href="/events/2011/spring/">UPCOMING EVENTS</a></h4>
  $.fn.formatUpcoming = function(events) {
    var innerHTML  = '<h4><a href="/events/2012/spring/">UPCOMING EVENTS</a></h4>';
        innerHTML += '<div id="area">';

    $(events).each(function(i) {
      if ($.fn.dateFormat(this.start, "N d") != $.fn.dateFormat(this.end, "N d")) {
        var dateFormat = "N d";
        var showEnd = true;
      }
      else {
        var dateFormat = "W N d, h:I A";
        var showEnd = false;
      }
      var start = $.fn.dateFormat(this.start, dateFormat);
      var end = $.fn.dateFormat(this.end, dateFormat);
      innerHTML += '<div class="' + (i % 2 == 0 ? "even" : "odd") + '"><h3><a href="' + this.link + '">' + this.title + '</a></h3><p class="date">' + start + (showEnd ? ' &ndash; ' + end : '') + ' |  ' + this.where + '</p><p>' + this.oneliner + '</p></div>';
    });
    innerHTML += "</div>";
     // Remove url for summer 05.25 skj <p align="right" class="normal"><a href="events/2011/spring/">&raquo; SPRING 2011 schedule</a></p>

   // innerHTML += '<p align="right" class="normal"><a href="events/2011/spring/">&raquo; SPRING 2011 schedule</a></p>';
    $(area).append(innerHTML);
  }

  // Default formatter for On View
  $.fn.formatOnView = function(events) {
    var dateFormat = 'N d, Y';
 // Remove url for summer 05.25 skj <h4><a href="/events/2011/spring/">ON VIEW</a></h4>
  
    var innerHTML  = '<h4>ON VIEW</h4>';
        innerHTML += '<div id="exhibit">';
        innerHTML += '<ul>';

    $(events).each(function(i) {
      var end = $.fn.dateFormat(this.end, dateFormat);
      innerHTML += '<li class="static"><a href="' + this.link + '">' + this.title + '</a></li><li class="date">THRU ' + end.toUpperCase() + '</li>';
    });
    innerHTML += "</ul>";
    innerHTML += "</div>";
    $(area).append(innerHTML);
  }
})(jQuery);

