// Copyright 2010 Google Inc. All Rights Reserved.

/**
 * @fileoverview This code generates partner listings based off of the users IP
 * address. It iterates through our data starting at a distance of +-.1
 * latitude/longitude from the user and then continues in +-.05 incriments
 * until the set limit of results is reached.
 */

/**
 * A generic function to reduce code verbosity. It returns the DOM object.
 * @param {string} id The id of the DOM object being referenced.
 * @return {HTMLElement} Returns the DOM object.
 */
function $(id) {
  return document.getElementById(id);
}

/**
 * Transform text into a URL slug.
 * @param {string} text The text you want to slugify.
 * @return {string} Returns slugified text.
 */
function slugify(text) {
  text = text.replace(/[^-a-zA-Z0-9,&\s]+/gi, '');
  text = text.replace(/-+/g, '_');
  text = text.replace(/\s+/g, '-');
  return text.toLowerCase();
}

/**
 * Using the google API to parse feeds.
 */
google.load('feeds', '1');

var DELIM = '%%';
var gaStr = new gaStrings();
var dataFromFeed = [];
var j = 0;
var geoLat = 37.3860517; //Default Mountain View, CA
var geoLng = -122.0838511; //Default Mountain View, CA
var DATA = {
  'en_ALL' : [36.778261, -119.4179324],  //California
  'cs_ALL' : [14.4803549, 121.039046],   //Czechoslovakia
  'da_ALL' : [56.26392, 9.501785],       //Denmark
  'de_ALL' : [51.165691, 10.451526],     //Germany
  'en_uk' : [55.378051, -3.435973],      //United Kingdom
  'es_ALL' : [40.463667, -3.74922],      //Spain
  'fi_ALL' : [61.92411, 25.748151],      //Finland
  'tl_ALL' : [12.879721, 121.774017],    //Philippines
  'fr_ALL' : [46.227638, 2.213749],      //France
  'hu_ALL' : [47.162494, 19.503304],     //Hungary
  'id_ALL' : [-0.789275, 113.921327],    //Indonesia
  'it_ALL' : [41.87194, 12.56738],       //Italy
  'ja_ALL' : [36.204824, 138.252924],    //Japan
  'ko_ALL' : [35.907757, 127.766922],    //Korea
  'nl_ALL' : [52.132633, 5.291266],      //Netherlands
  'no_ALL' : [60.472024, 8.468946],      //Norway
  'pl_ALL' : [51.919438, 19.145136],     //Poland
  'pt-BR_ALL' : [-14.235004, -51.92528], //Brazil
  'pt-PT_ALL' : [39.399872, -8.224454],  //Portugal
  'ru_ALL' : [61.52401, 105.318756],     //Russia
  'sv_ALL' : [60.128161, 18.643501],     //Sweden
  'th_ALL' : [15.870032, 100.992541],    //Thailand
  'tr_ALL' : [38.963745, 35.243322],     //Turkey
  'zh-CN_ALL' : [35.86166, 104.195397],  //China
  'zh-TW_ALL' : [23.69781, 120.960515],  //Taiwan
  'bg_ALL' : [42.733883, 25.48583],      //Bulgaria
  'ca_ALL' : [39.4519, 27.4576],         //Catalan
  'el_ALL' : [39.074208, 21.824312],     //Greece
  'lt_ALL' : [55.169438, 23.881275],     //Lithuania
  'sk_ALL' : [60.2854314, 10.4138],      //Slovakia
  'vi_ALL' : [14.058324, 108.277199]     //Vietnam
};

if (DATA[gaStr.geoLocation]) {
  geoLat = DATA[gaStr.geoLocation][0];
  geoLng = DATA[gaStr.geoLocation][1];
}

/**
 * Iterates through an array finding duplicates, it creates a new array while
 *     doing this but skips over the entries that are duplicates. dataFromFeed
 *     is then overwritten by the new array.
 * @param {Array} arrayToBeUniqued Supplied array to function so that the items
 *     in it may be uniqued.
 * @return {Array} returns Array uniqued by partner name and closest location.
 */
function uniqueArray(arrayToBeUniqued) {
  var arr = [];
  for (var i = 0, len = arrayToBeUniqued.length; i < len; i++) {
    var tmpHolder = '';

    if (arrayToBeUniqued[i + 1] &&
        arrayToBeUniqued[i].split(DELIM)[1] ==
        arrayToBeUniqued[i + 1].split(DELIM)[1]) {
      tmpHolder = arrayToBeUniqued[i];

      for (i++; arrayToBeUniqued[i] && tmpHolder.split(DELIM)[1] ==
           arrayToBeUniqued[i].split(DELIM)[1]; i++) {

        if (Number(arrayToBeUniqued[i].split(DELIM)[0]) <
            Number(tmpHolder.split(DELIM)[0])) {
          tmpHolder = arrayToBeUniqued[i];
        }
      }
      arr.push(tmpHolder);
      i--;
    } else {
      arr.push(arrayToBeUniqued[i]);
    }
  }
  return arr;
}

/**
 * Converts a lat/long point to a radian.
 * @param {number} degree latitude or longitude point.
 * @return {number} Returns the radian of submitted point.
 */
function toRadians(degree) {
  return degree * (Math.PI / 180);
}

/**
 * Figure out mileage using the Haversine formula.
 * @param {number} lat1 Latitude of the user.
 * @param {number} lat2 Latitude of the partner being measured.
 * @param {number} long1 Longitude of the user.
 * @param {number} long2 Longitude of the partner being measured.
 * @return {number} distance Returns the distance in miles between the
 *     two submitted sets of coordinates.
 */
function getDistance(lat1, lat2, long1, long2) {
  var radianLat1 = toRadians(lat1);
  var radianLat2 = toRadians(lat2);
  var radianLong1 = toRadians(long1);
  var radianLong2 = toRadians(long2);
  var radianDistanceLat = radianLat1 - radianLat2;
  var radianDistanceLong = radianLong1 - radianLong2;
  var sinLat = Math.sin(radianDistanceLat / 2.0);
  var sinLong = Math.sin(radianDistanceLong / 2.0);
  var a = Math.pow(sinLat, 2.0) +
      Math.cos(radianLat1) *
      Math.cos(radianLat2) *
      Math.pow(sinLong, 2.0);
  var distance = 3959. * 2 * Math.asin(Math.min(1, Math.sqrt(a)));

  return distance;
}

/**
 * Iterates through a spreadsheet data source first finding partners that are
 *     in  close proximity to the users IP address based on latitude and
 *     longitude. It does so starting in incriments of +-.1 and proceeds at
 *     incriments of +-.5 if the end of the data set is reached and the limit
 *     of required results has not yet been reached. It does this 20 times and
 *     then it will increase the search scope by +-20. When a row in the data
 *     source matchew the search critera it is inserted in an array. Once the
 *     limit is reached the array is used to display the entries. If no user
 *     lat/long is available the default will be Mountain View, CA.
 * @param {Array} feedData Array created from JSON data.
 */
function createPartnerArrayForUser(feedData) {
  var userLat = google.loader.ClientLocation ?
      google.loader.ClientLocation.latitude :
      geoLat;
  var userLng = google.loader.ClientLocation ?
      google.loader.ClientLocation.longitude :
      geoLng;

  for (var row = 0; row < feedData.length; row++) {

    if (feedData[row]['products'].indexOf('Analytics') > -1 &&
        feedData[row]['latlong']) {
      var latlng = feedData[row]['latlong'];

      for (var i = 0, len = feedData[row]['latlong'].split(':').length;
           i < len; i++) {
        var lat = parseFloat(latlng.split(':')[i].split(',')[0]);
        var lng = parseFloat(latlng.split(':')[i].split(',')[1]);
        var distanceFromOrigin = getDistance(userLat, lat, userLng, lng);
        var mileMeasure = 100000000 + Math.round(distanceFromOrigin);
        dataFromFeed.push(mileMeasure + DELIM +
            feedData[row]['name'] + DELIM +
            feedData[row]['regions'] + DELIM +
            feedData[row]['products'] + DELIM +
            feedData[row]['contact'] + DELIM +
            feedData[row]['website'] + DELIM +
            feedData[row]['websitedisplay'] + DELIM +
            feedData[row]['pdfstitle'] + DELIM +
            feedData[row]['pdfslink']);
      }
    }
  }
  dataFromFeed = uniqueArray(dataFromFeed);
  dataFromFeed.sort();
  displayPartnerResults();
}

/**
 * Link creator. It is used in other functions to reduce code verbosity.
 * @param {string} ahref The href of the link.
 * @param {string} aonclick The onclick of the link.
 * @param {string} aclass The class of the link.
 * @param {string} text The text the link is around.
 * @param {string} aid The id of the link.
 * @return {string} Returns the built link.
 */
function createLink(ahref, aonclick, aclass, text, aid) {
  var link = '<a ';
      link += ahref ? 'href="' + ahref + '" ' : '';
      link += aonclick ? 'onclick="' + aonclick + '" ' : '';
      link += aclass ? 'class="' + aclass + '" ' : '';
      link += aid ? 'id="' + aid + '" ' : '';
      link += '>' + text + '</a>';

  return link;
}

/**
 * HTML generator to display an entry for a listed partner. It is used in other
 *     functions to reduce code verbosity.
 * @param {string} website The partners website.
 * @param {string} name The partners name.
 * @param {string} tracking Name of partner lowercased and spaces removed, used
 *     for tracking and setting up ids.
 * @param {string} contact The partners contact information.
 * @param {string} products Container for partner product offering.
 * @param {string} regions Container for partner region information.
 * @param {string} pdfsTitle Container for the PDF Title information.
 * @param {string} pdfsLink Container for the PDF Link information.
 * @return {string} Returns the built HTML.
 */
function createHTML(website, name, tracking, contact, products, regions,
    pdfsTitle, pdfsLink) {
  var products_icon = '';
  if (products.indexOf('Analytics') > -1) {
    products_icon += '<img src="images/gaac_icon_analytics.png"' +
        'class="ga-consultant-icon"> ' + gaStr.analytics;
  }
  if (products.indexOf('Urchin') > -1) {
    products_icon += '<img src="images/gaac_icon_urchin.png"' +
        'class="ga-consultant-icon"> ' + gaStr.urchin;
  }
  if (products.indexOf('Website Optimizer') > -1) {
    products_icon += '<img src="images/ga-wso.gif"' +
        'class="ga-consultant-icon"> ' + gaStr.websiteOptimizer;
  }

  var htmlOutput = '<div class="ga-consultant-container"><strong>' +
    createLink(website, '', '', name) + '</strong><br/><div>' +
    contact.replace(/ ([\w]*@[^ ]*)/gi, ' <a href="mailto:$1">$1</a>') +
    '</div><div class="ga-consultant-highlight"><strong>' +
        gaStr.product + '</strong>: ' + products_icon + '</div>' +
        '<div class="ga-consultant-highlight"><strong>' +
        gaStr.region + '</strong>: ' + regions + '</div>';
  if (pdfsTitle != 'undefined') {
    var pdfsTitleArr = pdfsTitle.split('**');
    var pdfsLinkArr = pdfsLink.split('**');
    htmlOutput += '<div class="ga-consultant-highlight success"><strong>' +
        gaStr.successStories + '</strong><ul>';
    for (var i = 0, len = pdfsTitleArr.length; i < len; i++) {
       htmlOutput += '<li><a href="' + pdfsLinkArr[i].replace(/^%/,'') + '">' +
           pdfsTitleArr[i] + '</a>';
    }
    htmlOutput += '</ul></div>';
  }
  htmlOutput += '</div>';

  return htmlOutput;
}

/**
 * Iterates through the dataFromFeed array to display the partners in different
 *     ways based on the users interaction with the page.
 * @param {string} direction Assigned by the users request to go forward or back
 *     in the data set.
 * @param {string} submittedRegion Assigned by the users request to filter based
 *     on region/subregion.
 * @param {string} submittedProduct Assigned by the users request to filter
 *     based on product.
 */
function displayPartnerResults(direction, submittedRegion, submittedProduct) {
  var htmlOut = '';
  var prevButton = $('prev_button');
  var nextButton = $('next_button');
  var partnerControl = $('partner_control');
  var increment = 10;
  var displayProduct = ($('formProduct').value == 'all') ?
      '' : $('formProduct').value;
  var displayRegion = ($('formRegion').value == 'all') ?
      '' : $('formRegion').value;
  var divSubRegions = $('sub_regions');
  var formSubRegions = divSubRegions.getElementsByTagName('select');

  if (direction == 'prev') {
    j -= increment;
  } else {
    j += increment;
  }

  if (submittedRegion) {
    toggleSubRegions(submittedRegion);
    if (submittedRegion == 'all') {
      j = increment;
    }
  }

  for (var i = 0, len = formSubRegions.length; i < len; i++) {
    if (formSubRegions[i].style.display == 'block') {
       var displayRegion = formSubRegions[i].value;
    }
  }

  var emptySet = true;
  for (var i = 0, len = dataFromFeed.length; i < len; i++) {
    var arrItem = dataFromFeed[i].split(DELIM);
    var regions = arrItem[2];
    var products = arrItem[3];

    if (slugify(regions).indexOf(displayRegion) > -1 &&
      slugify(products).indexOf(displayProduct) > -1) {
      var name = arrItem[1];
      var tracking = name.replace(/ /, '').toLowerCase();
      var contact = arrItem[4];
      var website = arrItem[5];
      var websitedisplay = arrItem[6];
      var filter = (submittedProduct) ? products : regions;
      var pdfsTitle = arrItem[7];
      var pdfsLink = arrItem[8];

      if ((displayRegion == '' &&
        displayProduct != '') ||
        displayRegion != '') {
        htmlOut +=
          createHTML(website, name, tracking, contact, products, regions,
              pdfsTitle, pdfsLink);
        partnerControl.style.display = 'none';
        emptySet = false;
      } else if (displayRegion == '' &&
        i < j &&
        i >= j - increment) {
        htmlOut +=
          createHTML(website, name, tracking, contact, products, regions,
              pdfsTitle, pdfsLink);
        partnerControl.style.display = 'block';
        prevButton.disabled = (j == increment) ?
          true : false;
        nextButton.disabled = (j + increment > dataFromFeed.length) ?
          true : false;
        emptySet = false;
      }
    }
  }
  if (emptySet) {
    $('no_results').style.display = 'block';
  } else {
    $('no_results').style.display = 'none';
  }
  $('output').innerHTML = htmlOut;
}

/**
 * Toggles the display of each partner contact listing. It also switches out
 *     the Contact Information text with a close icon.
 * @param {string} layer The id of the layer that contains the contact info.
 */
function toggleDisplay(layer) {
  var layerStyle = $(layer).style;
  var contactLayer = $('l_' + layer);
  var closed = gaStr.contact;
  var open = '<img src="images/icons/ga-icon-window-close.gif"' +
      'class="ga-consultant-window-close">';
  layerStyle.display = (layerStyle.display == 'block' ||
      layerStyle.display == '') ? 'none' : 'block';
  contactLayer.innerHTML = (contactLayer.innerHTML == closed) ? open : closed;
}

/**
 * Filters the partner results based on the users filter request.
 * @param {string} region The users filter request for a region/subregion.
 */
function toggleSubRegions(region) {
  var subRegion = $('sub_regions').getElementsByTagName('select');
  var noMatch = 0;
  for (var i = 0, len = subRegion.length; i < len; i++) {
    if (subRegion[i].id.substring(0, 3) ==
        $('formRegion').value.substring(0, 3)) {
          subRegion[i].style.display = 'block';
    } else {
      subRegion[i].style.display = 'none';
      noMatch++;
    }
  }
  if (noMatch == subRegion.length) {
    $('sub_regions').style.display = 'none';
  } else {
    $('sub_regions').style.display = 'block';
  }
}

/**
 * Toggles the visibility of the filters and changes the arrow icons next to
 *     the link.
 */
function toggleFilter() {
  var filterState = $('filter-control').style;
  var imgState = $('filter-img');
  var filterTxt = $('filter-txt');

  if (filterState.display == 'block') {
    filterState.display = 'none';
    imgState.src = imgState.src.replace('up', 'down');
    filterTxt.innerHTML =
        filterTxt.innerHTML.replace(gaStr.hide, gaStr.view);
  } else {
    filterState.display = 'block';
    imgState.src = imgState.src.replace('down', 'up');
    filterTxt.innerHTML =
        filterTxt.innerHTML.replace(gaStr.view, gaStr.hide);
  }
}

/**
 * Clears the partner filters when the user selects to do so via the Clear
 *     Filters button in the UI.
 */
function clearFilters() {
  $('formRegion').selectedIndex = 0;
  $('formProduct').selectedIndex = 0;
  var formSubRegions = $('sub_regions').getElementsByTagName('select');
  for (var i = 0, len = formSubRegions.length; i < len; i++) {
    formSubRegions[i].selectedIndex = 0;
  }
  displayPartnerResults('', 'All');
}

/**
 * Calls the filters the createPartnerArrayForUser using the spreadsheet feed
 *     syntax. It loads on body load.
 */
function initialize() {
  var formElements = [
    $('formRegion'),
    $('unitedstatesdd'),
    $('latinamericadd'),
    $('europedd'),
    $('middleeastdd'),
    $('asiapacificdd')
  ];
  var feedUrl = 'http://spreadsheets.google.com/feeds/list/' +
      'pcO-d8z1IPLrdWkaXVzaQaw/od6/public/basic';

  gweb.feed.loadSpreadsheet(createPartnerArrayForUser, feedUrl, false);
  gweb.events.listen($('filter-clear'), 'click', clearFilters);
  gweb.events.listen($('prev_button'), 'click', function() {
    displayPartnerResults('prev');
  });
  gweb.events.listen($('next_button'), 'click', function() {
    displayPartnerResults('next');
  });
  for (var i in formElements) {
    gweb.events.listen(formElements[i], 'change', function() {
      displayPartnerResults('', this.value);
    });
  }
  gweb.events.listen($('formProduct'), 'change', function() {
    displayPartnerResults('', this.value, true);
  });
}

