// Copyright 2009 Google Inc.  All Rights Reserved.

/**
 * @fileoverview Javascript file to create HTML from a Picasa album RSS feed.
 *
 * Dependencies:
 *     Localized strings are stored in:
 *     http://www.google.com/press/js/picasa_feed_strings.js
 * Styles for modal dialog are located in:
 *     http://www.google.com/press/media_room/css/modal_dialog.css.
 *     HTML layout for modal is descripted in the CSS file.
 *
 * @author dcarlsson@google.com (dave carlsson)
 */

// Load the Google Feed API, version 1.
google.load('feeds', '1');

/**
 * Namespace for Google press websites.
 */
var press = press || {};

/**
 * Initializes functions used on press website.
 * @param {string} page Text to select which functions to initialize based on
 *     which page is being loaded.
 * @return {Object} Create a new instance of the constructor or stop loading
 *     JavaScript on the page.
 */
press.setUp = function(page) {
  if (page === 'pressImages') {
    return new press.Images();
  } else {
    return null;
  }
};

/**
 * Images class. Wrapper for all image page related JavaScript content.
 * @constructor
 */
press.Images = function() {
};

// Methods to be used throughout Google press center websites.
/**
 * Creates a message that some dynamic content is loading.
 * @param {string} containerId The HTML ID value of the DIV that will display
 *     the feed generated HTML.
 */
press.displayLoadingMessage = function(containerId) {
  var container = document.getElementById(containerId);
  var loadingMessage = '<div class="loading-message">' +
      '<h2>' + press.LOADING_TEXT + '&hellip;</h2>' +
      '<img src="/press/media_room/images/loading-32.gif" alt="" /></div>';

  container.innerHTML = loadingMessage;
};

/**
 * Escapes characters (<, >, ", &) in text strings.
 * @param {string} str The text string that will be escaped.
 * @return {string} The escaped version of the text string {@code str}.
 */
press.htmlEscape = function(str) {
  str = str.replace(/&/g, '&amp;');
  str = str.replace(/</g, '&lt;');
  str = str.replace(/>/g, '&gt;');
  str = str.replace(/\"/g, '&quot;');
  return str;
};

/**
 * Shows an in-page modal dialog box by updating CSS.
 */
press.displayModalDialog = function() {
  var modalDialog = document.getElementById('modal-dialog');
  var yOffset = window.pageYOffset;

  if (!yOffset) {
    yOffset = document.documentElement.scrollTop;
  }

  modalDialog.style.marginTop = yOffset + 'px';
  modalDialog.className = 'modal-dialog visible';
};

/**
 * Hides an in-page modal dialog box by updating CSS.
 */
press.hideModalDialog = function() {
  var modalDialog = document.getElementById('modal-dialog');

  modalDialog.className = 'modal-dialog invisible';
};

// Methods for press images pages.
/**
 * Takes the linked text used to open a Picasa album and generates a simplified
 * text string that can be used as a hash value in the HTML page URL to link
 * directly to that album's content.
 * @param {Array.<string>} feedLinkText The linked text on the HTML page used
 *     to open the content from a specific Picasa album.
 * @return {Array.<string>} A simplified text string that can be used as a URL
 *     hash value to link directly to an album's content.
 */
press.Images.prototype.cleanFeedLinkText = function(feedLinkText) {
  for (var i = 0, text; text = feedLinkText[i]; i++) {
    if (typeof text === 'string') {
      text = text.replace(/&nbsp;/g, '');
      feedLinkText[i] = text.toLowerCase().replace(/[^a-z0-9]/g, '');
    }
  }
  return feedLinkText;
};

/**
 * Creates a collection of anchor-link-friendly text elements and the Picasa
 * feed with which they're associated.
 * @return {Object} The album name/feed data pairs.
 */
press.Images.prototype.createAvailableFeedList = function() {
  var findFeedUri = /\http:\/\/picasaweb[^\']+/g;
  var findFeedLinkText = /\">[^<\/]+/g;
  var feedOptions = {};
  var listedAlbums = document.getElementById('album-list');

  if (!listedAlbums) {
    return feedOptions;
  }

  var feedLinkText = listedAlbums.innerHTML.match(findFeedLinkText);
  var feedUris = listedAlbums.innerHTML.match(findFeedUri);

  feedLinkText = this.cleanFeedLinkText(feedLinkText);

  for (var i = 0, albumName; albumName = feedLinkText[i]; i++) {
    feedOptions[albumName] = feedUris[i];
  }
  return feedOptions;
};

/**
 * Displays a modal dialog box and populates the box with the standard size
 * image of the thumbnail that was selected with links to the larger and full
 * sized versions.
 * @param {string} imageStandard The URI of the standard size Picasa image.
 * @param {string} imageLarge The URI of the large Picasa image.
 * @param {string} imageFullSize The URI of the full size Picasa image.
 */
press.Images.displaySelectedImage = function(imageStandard,
                                             imageLarge,
                                             imageFullSize) {
  press.displayModalDialog();

  var resultsContainer = document.getElementById('modal-results-container');
  var selectedImageInformation = '<img src="' + imageStandard + '" alt="" />' +
      '<p><a target="_blank" href="' + imageLarge + '">' +
       press.Images.PHOTO_TEXT_LARGE +
      '</a>&nbsp;|&nbsp;<a target="_blank" href="' + imageFullSize +
      '">' + press.Images.PHOTO_TEXT_FULL_SIZE + '</a></p>';

  resultsContainer.innerHTML = selectedImageInformation;
};

/**
 * Creates text to use as anchor links placed on the image names and
 * referenced when opening an image preview modal dialog on thumbnail click.
 * @param {string} imageStandard The URI of the standard size image.
 * @return {string} The text to use as anchor links.
 */
press.Images.generateAnchorLink = function(imageStandard) {
  var imageStandardSegments = imageStandard.split('/');
  var lastImageStandardSegmentPosition = imageStandardSegments.length - 1;
  var anchorLink = imageStandardSegments[lastImageStandardSegmentPosition];
  var anchorLinkPosition = 0;

  anchorLink = anchorLink.split('.')[anchorLinkPosition];
  return anchorLink;
};

/**
 * Takes a Picasa feed URI and displays album images and pertienent
 * information in the given container.
 * Loops through content items from the feed to populate the variables to hold
 * each relevant piece of information. Generates the HTML to diplay the image
 * item on the page. Hides the modal dialog box used to display an image
 * preview.
 * @param {string} picasaFeedUri The static portion of the feed URI for
 *     the RSS feed out of Picasa.
 * @param {string} containerId The DIV container to hold the outputed HTML.
 * @return {boolean} Stop or continue the loading of Javascript elements
 *     for the page depending on error state.
 */
press.Images.prototype.generateImageDisplay = function(picasaFeedUri,
                                                       containerId) {
  if (!containerId) {
    containerId = press.Images.DEFAULT_CONTAINER;
  }

  containerId = containerId;
  picasaFeedUri = encodeURI(picasaFeedUri);

  press.displayLoadingMessage(containerId);
  press.hideModalDialog();

  var feedOptions = this.createAvailableFeedList();
  var feedUri = this.getFeedUri(picasaFeedUri, feedOptions);
  var feed = new google.feeds.Feed(feedUri);

  feed.setResultFormat(google.feeds.Feed.MIXED_FORMAT);
  feed.setNumEntries(1000);
  feed.load(function(result) {
    if (!result.error) {
      var entries = result.feed.entries;
      var container = document.getElementById(containerId);
      var albumName = press.Images.getAlbumName(entries[0]);
      var picasaImageItem = '<h2>' + press.htmlEscape(albumName) + '</h2>';

      for (var i = 0, entry; entry = entries[i]; i++) {
        var imageName = press.Images.parseImageName(entry.title, 'name');
        var executiveTitle =
            press.Images.parseImageName(entry.title, 'title');
        var imageStandard = press.Images.parseStandardImageSource(entry);
        var imageSourceStringStart =
            press.Images.splitImageSourceString(imageStandard)[0];
        var imageSourceStringEnd =
            press.Images.splitImageSourceString(imageStandard)[1];
        var imageThumbnail =
            press.Images.getThumbnailImageSource(imageSourceStringStart,
                                                 imageSourceStringEnd);
        var imageLarge =
            press.Images.getLargeImageSource(imageSourceStringStart,
                                             imageSourceStringEnd);
        var imageFullSize =
            press.Images.getFullSizeImageSource(imageSourceStringStart,
                                                imageSourceStringEnd);
        var anchorLink = press.Images.generateAnchorLink(imageStandard);

        picasaImageItem += '<div class="picasa-image-item">' +
            '<div class="g-section g-tpl-75">' +
            '<div class="g-unit g-first">' +
            '<a href="#' + anchorLink +
            '" onclick="press.Images.displaySelectedImage(\'' +
            imageStandard + '\', \'' + imageLarge + '\', \'' +
            imageFullSize + '\');"><img src="' +
            imageThumbnail + '" alt="' + press.htmlEscape(imageName) + '" \/>' +
            '</a></div><div class="g-unit">' +
            '<h4>' + press.htmlEscape(imageName) +
            '</h4><p>' + press.htmlEscape(executiveTitle) + '</p>' +
            '<p><a target="_blank" href="' + imageStandard +
            '">' + press.Images.PHOTO_TEXT_SMALL +
            '</a>&nbsp;|&nbsp;' +
            '<a target="_blank" href="' + imageLarge +
            '">' + press.Images.PHOTO_TEXT_LARGE +
            '</a>&nbsp;|&nbsp;' +
            '<a target="_blank" href="' + imageFullSize +
            '">' + press.Images.PHOTO_TEXT_FULL_SIZE + '</a></p>' +
            '</div></div></div>';
      }
    } else {
      return false;
    }

    container.innerHTML = picasaImageItem;
  });
};

/**
 * Displays a linked list of select hi-resolution photos hosted on
 * google.com as press resources.
 * @param {string} hiresImagesText The text string to use as a title for
 *     the list of high resolution images.
 */
press.Images.prototype.generateImageList = function(hiResImagesText) {
  var imageListContainer =
      document.getElementById(press.Images.DEFAULT_CONTAINER);
  var absoluteImagePathRoot = 'http://www.google.com/press/images/';
  var hiResImageText = hiResImagesText.firstChild.data;
  var imageListContent = '<div class="image-content-container-hires">' +
      '<h2>' + hiResImageText + '</h2><ul class="hires-images">';

  press.hideModalDialog();
  press.displayLoadingMessage(press.Images.DEFAULT_CONTAINER);

  for (var i = 0, image; image = press.Images.HI_RES_IMAGE_LIST[i]; i++) {
    imageListContent += '<li><a href="' + absoluteImagePathRoot +
        image + '">' + image + '</a></li>';
  }

  imageListContainer.innerHTML = imageListContent + '</ul></div>';
};

/**
 * Get the name of the Picasa album from the feed.
 * @param {Object} entry A single content item from the Picasa feed.
 * @return {string} The name of the Picasa album.
 */
press.Images.getAlbumName = function(entry) {
  var albumName = entry.content.match(/\/[^\?]+/);
  var albumIdPrefix = 'Press Center Media - ';
  var cleanAlbumIdPrefix = /\W/g;

  albumIdPrefix = albumIdPrefix.replace(cleanAlbumIdPrefix, '');

  var albumNameStartPosition = albumIdPrefix.length;
  var findCapitalLetter = /([A-Z]{1})/g;
  var findDotSuffix = /(Org)/g;

  albumName = albumName.toString();

  var albumNameSections = albumName.split('/');
  var albumNameText = albumNameSections.length - 1;

  albumName = albumName.split('/')[albumNameText];
  albumName = albumName.slice(albumNameStartPosition, albumName.length);

  if (albumName.search(findDotSuffix) != -1) {
    var dotSuffix = albumName.match(findDotSuffix);
    dotSuffix = '.' + dotSuffix.toString().toLowerCase();
    albumName = albumName.replace(findDotSuffix, dotSuffix);
  } else {
    albumName = albumName.replace(findCapitalLetter, ' $1');
  }
  return albumName;
};

/**
 * Checks the page URL to see if an existing Picasa album feed can be loaded.
 * @param {string} picasaFeedUri The URI for the RSS feed out of Picasa.
 * @param {Object} feedOptions The album name/feed data pairs.
 * @return {string} A URI for a Picasa album feed.
 */
press.Images.prototype.getFeedUri = function(picasaFeedUri, feedOptions) {
  switch (picasaFeedUri) {
    case 'loadPageDefault':
      if (document.location.hash) {
        var urlAlbumName = document.location.hash;
        urlAlbumName = urlAlbumName.substr(1);

        for (var albumName in feedOptions) {
          if (feedOptions[urlAlbumName]) {
            var feedUri = feedOptions[urlAlbumName];
          }
        }
      }

      if (!feedUri) {
        feedUri = 'http://picasaweb.google.com/data/feed/base/user/' +
                  'Ogogster/albumid/5306874076921636609?' +
                  'authkey=Gv1sRgCJuPwYOG6JrpNw';
      }
      break;

   default:
     var feedUri = picasaFeedUri;
  }
  return feedUri;
};

/**
 * @param {string} imageSourceStringStart String for the first part of URI of
 *     the image.
 * @param {string} imageSourceStringEnd String for the last
 *     part of URI of the image.
 * @return {string} The URI for the full size
 *     version of the image.
 */
press.Images.getFullSizeImageSource = function(imageSourceStringStart,
                                               imageSourceStringEnd) {
  return imageSourceStringStart + '/' + imageSourceStringEnd;
};

/**
 * @param {string} imageSourceStringStart String for the first
 *     part of URI of the image.
 * @param {string} imageSourceStringEnd String for the last
 *     part of URI of the image.
 * @return {string} The URI for the thumbnail version of the image.
 */
press.Images.getThumbnailImageSource = function(imageSourceStringStart,
                                                imageSourceStringEnd) {
  return imageSourceStringStart + '/s144/' + imageSourceStringEnd;
};

/**
 * Takes the caption information from the Picasa feed to derive the name of
 * the image. The image name contains the person's name and position.
 * For images not depicting people or not including a position the
 * executiveTitle will contain a blank string. The entry title is generated
 * by the image caption.
 * @param {string} title The entry title for the Picasa feed item.
 * @param {string} elementToReturn Sets the value of the return string to
 *     be either the image name or other (executive's title).
 * @return {Array.<string>} The edited title
 *     information of the image to give the name and title of the
 *     person, where applicable.
 */
press.Images.parseImageName = function(title, elementToReturn) {
  var checkImageTitle = /,\s{0,}\n/;
  if (checkImageTitle.test(title)) {
    var imageName = title.split('\n')[0];
    var executiveTitle = title.split('\n')[1];
    var finalCommaPosition = imageName.lastIndexOf(',');

    imageName = imageName.substring(0, finalCommaPosition);
  } else {
    var imageName = title;
    var executiveTitle = '';
  }
  return elementToReturn == 'name' ? imageName : executiveTitle;
};

/**
 * Gets the URI for the standard sized image.
 * @param {Object} entry A single content item from the Picasa feed.
 * @return {string} The URI of the standard size image.
 */
press.Images.parseStandardImageSource = function(entry) {
  var imageStandard = entry.content.match(/src="[^"]+/);

  imageStandard = imageStandard.toString();
  imageStandard = imageStandard.split('src="')[1];
  return imageStandard;
};

/**
 * Get parts of string for image URI.
 * Used to derive thumbnail and full sized image URI's.
 * @param {string} imageStandard The URI of the standard size image.
 * @return {Array.<string>} First and final sections of image URI.
 */
press.Images.splitImageSourceString = function(imageStandard) {
  return imageStandard.split('/s288/');
};

/**
 * Gets the URI for the full size image.
 * @param {string} imageSourceStringStart String for the first
 *     part of URI of the image.
 * @param {string} imageSourceStringEnd String for the last
 *     part of URI of the image.
 * @return {string} The URI for the large
 *     version of the image.
 */
press.Images.getLargeImageSource = function(imageSourceStringStart,
                                            imageSourceStringEnd) {
  return imageSourceStringStart + '/s800/' + imageSourceStringEnd;
};

// Press strings.
/**
 * Text for loading message.
 * @const
 * @type {string}
 */
press.LOADING_TEXT = LOADING_TEXT;

// Press images strings.
/**
 * Image size indictor objects (content = text).
 * These are used when creating links to different sized images in Picasa.
 * These are required for each use of the picasa_feed.js file.
 */

/**
 * Text for small photo.
 * @const
 * @type {string}
 */
press.Images.PHOTO_TEXT_SMALL = PHOTO_TEXT_SMALL;

/**
 * Text for large photo.
 * @const
 * @type {string}
 */
press.Images.PHOTO_TEXT_LARGE = PHOTO_TEXT_LARGE;

/**
 * Text for full size photo.
 * @const
 * @type {string}
 */
press.Images.PHOTO_TEXT_FULL_SIZE = PHOTO_TEXT_FULL_SIZE;

/**
 * Default HTML ID for container to hold generated information.
 * @const
 * @type {string}
 */
press.Images.DEFAULT_CONTAINER = 'image-content-container';

/**
 * List of available high resolution images (content = text).
 * @const
 * @type {Array.<string>}
 */
press.Images.HI_RES_IMAGE_LIST =
    ['google_logo.zip', 'alan_eustace.zip', 'alfred_spector.zip',
    'amit_singhal.zip', 'ben_fried.zip', 'benjamin_treynor.zip',
    'bill_coughran.zip', 'bradley_horowitz.zip', 'brown_shona.zip',
    'craig_silverstein.zip', 'daniel_alegre.zip', 'dave_girouard.zip',
    'david_drummund.zip', 'david_eun.zip', 'david_lawee.zip',
    'david_radcliffe.zip', 'dennis_woodside.zip', 'doug_garland.zip',
    'eric_schmidt.zip', 'francoise_brougher.zip', 'jeff_dean.zip',
    'jeff_huber.zip', 'joan_braddi.zip', 'john_herlihy.zip',
    'jonathan_rosenberg.zip', 'kent_walker.zip',
    'larry_page.zip', 'laszlo_bock.zip', 'marissa_mayer.zip',
    'megan_smith.zip', 'nikesh_arora.zip', 'omid_kordestani.zip',
    'page_brin.zip', 'patrick_pichette.zip', 'penry_price.zip',
    'salar_kamangar.zip', 'sanjay_ghemawat.zip', 'sergey_brin.zip',
    'shiva_shivakumar.zip', 'susan_wojcicki.zip', 'udi_manber.zip',
    'urs_holzle.zip', 'vic_gundotra.zip', 'vint_cerf.zip'];
