// Copyright 2009 Google Inc.  All Rights Reserved.

/**
 * @fileoverview Javascript document for pulling blog
 *     feed data with Google Feed API.
 * Call Feed API and key on HTML page.
 * Set two required variables on HTML page:
 * REQUIRED: feed {object} The feed object that holds all blog data.
 * numberOfEntriesDefault {integer} Number of blog posts to display.
 * REQUIRED: numberOfEntries {integer} Function call to initEntries.
 * Set several optional variables on HTML page:
 * toggleEntries {string} Turn on/off ability to change number of
 * blog entries shown.
 * tracking {string} trackingOn/trackingLegacy/trackingOff.
 * Set type of Analytics tracking on page.
 * pageName {string} Set name of page for use in tracking.
 * errorMessageType {string} Choose a custom or default error message.
 * setEntryStyle {string} default/custom Create layout for generated HTML.
 *
 * @author dave carlsson
 */

/**
 * Part of the Google Feed API.
 * @param {string} feeds Loads the 'feeds' API.
 * @param {string} 1 Sets the version of API (version 1).
 */
google.load('feeds', '1');

/**
 * Extracts variables from the url based on the specified DELIMETER
 * @return {Array.<string>} Arry of variables parsed from URL.
 */
function parseURLVar() {
  var DELIMETERS = ['#', '\\?', '&'];
  var pipe = '|';
  var url = unescape(document.URL);
  var arrURL = [];
  var vars = {};
  var tempVar = [];

  for (var i = 0; i < DELIMETERS.length; i++) {
    var regx = new RegExp(DELIMETERS[i], 'ig');
    url = url.replace(regx, pipe);
  }
  arrURL = url.split(pipe);

  for (var i = 1; i < arrURL.length; i++) {
    tempVar = arrURL[i].split('=');
    vars[tempVar[0]] = tempVar[1];
  }
  return vars;
}

/**
 * Set initial number of posts displayed on the page
 * @return {number} Number of blog entries to display.
 */
function initializeEntries() {
  var numberOfPosts = parseURLVar()['posts'];
  if (numberOfPosts == 'all') {
    numberOfEntries = 1000;
  } else {
    if (typeof numberOfEntriesDefault === 'undefined') {
      numberOfEntriesDefault = 5;
    }
    numberOfEntries = numberOfEntriesDefault;
  }
  return numberOfEntries;
}

/**
 * Create HTML for outgoing link tracking.
 */
function addTracking() {
  var trackingCode = '';
  if (typeof tracking !== 'undefined') {
    if (tracking == 'trackingOn') {
      trackingCode = 'pageTracker._trackPageview(\'/outgoing/' +
                      pageName + '/showmore\')">';

    }
    if (tracking == 'trackingLegacy') {
      trackingCode = 'urchinTracker(\'/outgoing/' +
                     pageName +'/showmore\')">';
    }
  }
  else {
    trackingCode = '">';
  }
  return trackingCode;
}

/**
 * Create HTML to show more or fewer blog posts.
 * @param {number} numberOfEntries Number of blog entries being shown.
 * @param {Object} container HTML div object to display rendered data.
 */
function alterNumberPosts(numberOfEntries, container) {
  var showMorePosts = '';
  var showFewerPosts = '';
  var containerName = container.id;

  showMorePosts = '<p><a href="#posts=all" onclick="initialize(\'' +
                  containerName + '\', 1000); addTracking()"' + '>'+
                  'show all posts</a>';

  showFewerPosts = '<p><a href="#posts=default" onclick="initialize(\'' +
                   containerName + '\', ' + numberOfEntriesDefault + '); ' +
                   addTracking() + 'show fewer posts</a>';

  if (typeof toggleEntries !== 'undefined' &&
      toggleEntries == 'toggleEntriesOn') {
    if (numberOfEntries <= numberOfEntriesDefault) {
      container.innerHTML += showMorePosts;
    } else {
      container.innerHTML += showFewerPosts;
      numberOfEntries = numberOfEntriesDefault;
    }
  }
}

/**
 * Format blog data
 * @param {string} dateFull The unformatted date string from the blog feed.
 * @return {string} A human readable date.
 */
function getCleanDate(dateFull) {
  var date = dateFull.substr(5, dateFull.length - 20);
  return date;
}

/**
 * Convert blog post dates to yymmdd format to allow for sorting.
 * @param {string} dateFull The unformatted date string from the blog feed.
 * @return {string} sortableDate The blog post date in yyyymmdd format
 *     to allow for sorting posts by date.
 */
function getSortableDate(dateFull) {
  var dateClean = dateFull.substr(5, dateFull.length - 19);
  var year = dateFull.substr(12, dateClean.length - 8);
  var namedMonth = dateFull.substr(8, dateClean.length - 9);
  var day = dateFull.substr(5, dateClean.length - 10);
  var time = dateFull.substr(17, dateFull.length - 23);
  time = time.replace(/:/g, '');

  var months = {};
  months['Jan'] = '01';
  months['Feb'] = '02';
  months['Mar'] = '03';
  months['Apr'] = '04';
  months['May'] = '05';
  months['Jun'] = '06';
  months['Jul'] = '07';
  months['Aug'] = '08';
  months['Sep'] = '09';
  months['Oct'] = '10';
  months['Nov'] = '11';
  months['Dec'] = '12';
  var numericalMonth = months[namedMonth];
  var sortableDate = year + numericalMonth + day + time;
  return sortableDate;
}

/**
 * Blog posts start with posted by and two line breaks.
 * Split out author from snippet.
 * @param {string} post The text content of the blog post snippet.
 * @return {string} The blog post snippet with the author information
 *     stripped out and the snippet set to the proper length.
 */
function cleanSnippet(post) {
  var snippet = '';
  if (post.match('<br><br>')) {
    var snippetArray = post.split('<br><br>');
  } else if (post.match('<br /><br />')) {
    var snippetArray = post.split('<br /><br />');
  } else if (post.match('\n\n')) {
    var snippetArray = post.split('\n\n');
  }

  if (snippetArray) {
    for (var i = 2; i < snippetArray.length; i++) {
      snippetArray[1] += ' ' + snippetArray[i];
    }
    snippet = snippetArray[1];
  } else {
    snippet = post;
  }
  return snipSnippet(snippet);
}

/**
 * If the snippet is longer than specified below (here, 160 characters), it is
 * shortened.
 * This function will fix any errors when the automatic FeedBurner snippet
 * feature does not work correctly.
 * @param {string} snippet The blog post snippet with the author information
 *     stripped out.
 * @return {string} The blog post snippet with the author information
 *     stripped out and the snippet set to the proper length.
 */
function snipSnippet(snippet) {
  var EMPTY = ' ';
  var snippetLength = 160;

  if (snippet.length > snippetLength) {
    snippetLength = snippet.lastIndexOf(' ', snippetLength);
    snippet = snippet.substring(0, snippetLength);
    snippet += '&hellip;';
  }

  return snippet;
}

/**
 * Create error message if feed is down
 * @param {Object} container HTML div object to display rendered data.
 */
function displayErrorMessage(container) {
  var errorMessageHeader = '';
  var errorMessageBody = '';
  errorMessageHeader = '<h3 class="error-message">';
  errorMessageBody = '<p class="error-message">';

  if (typeof errorMessageType !== 'undefined' &&
      errorMessageType == 'errorMessageCustom') {
    errorMessageHeader += errorMessageHeaderText;
    errorMessageBody += errorMessageText;
  } else {
    errorMessageHeader += 'The blog feed is temporarily unavailable.';
  }
  errorMessageHeader += '</h3>';
  errorMessageBody += '</p>';
  container.innerHTML = errorMessageHeader + errorMessageBody;
}


/**
 * Associate each blog post entry with its sortable date to allow for
 * ordering posts by date, newest to oldest.
 * Call printPost function to generate HTML for page.
 * @param {object} entries Full data from blog feed.
 * @param {object} container HTML div object to display rendered data.
 */
function mapBlog(entries, container) {
  var blogMap = {};
  var sortableDates = [];

  for (var i = 0, entry; entry = entries[i]; i++) {
    var sortableDate = getSortableDate(entry.publishedDate);

    for (var dateKey in sortableDates) {
      if (sortableDates[dateKey] == sortableDate) {
        sortableDate = sortableDate + 1;
      }
    }

    sortableDates.push(sortableDate);
    blogMap[sortableDate] = entry;
  }

  sortableDates = sortableDates.sort();
  sortableDates = sortableDates.reverse();

  for (var date in sortableDates) {
    var date = parseInt(date);
    if (blogMap[sortableDates[date + 1]] != undefined) {
      if (blogMap[sortableDates[date]].title ==
          blogMap[sortableDates[date + 1]].title) {
        sortableDates[date] = null;
      }
    }
    if (sortableDates[date] != null) {
      printPost(blogMap[sortableDates[date]], container);
    }
  }
}

/**
 * Generate the HTML for a single blog post entry.
 * @param {string} entry The full data for a blog post.
 * @param {object} container HTML div object to display rendered data.
 */
function printPost(entry, container) {
  var post = '';
  var publishedDate = getCleanDate(entry.publishedDate);
  var snippet = cleanSnippet(entry.content);
  if (typeof setEntryStyle != 'undefined' && setEntryStyle == 'custom') {
    printPostCustom(container, entry, snippet, publishedDate);
  } else {
    post = '<p class="title"><a href="' + entry.link + '">' + entry.title +
           '</a></p><p class="date">' + publishedDate +
           '</p><p class="snippet">' + snippet + '</p>';
    container.innerHTML += post;
  }
}

/**
 * Load feed and variables for the page and initialize all content.
 * Call functions to build HTML content for the page or display error message.
 * @param {string} element The text string name for the ID of the container
 *     element that will hold the generated HTML on the page.
 * @param {number} numberOfEntriesDefault The number value of entries to
 *     display when first generating the HTML content for the page.
 */
function initialize(element, numberOfEntriesDefault) {
  feed.setResultFormat(google.feeds.Feed.MIXED_FORMAT);
  feed.setNumEntries(numberOfEntriesDefault);
  feed.load(function(result) {
    var posts = [];
    var dates = [];
    var sortable = [];
    var sorted = [];
    var container = document.getElementById(element);
    container.innerHTML = '';
      if (result.error) {
        displayErrorMessage(container);
      } else if (!result.error) {
        mapBlog(result.feed.entries, container);
        alterNumberPosts(numberOfEntriesDefault, container);
      }
  });
}
