var MAX_LENGTH = 90;  // default image size of max(width, height)
var RESULTS_LIMIT = 12;

/**
 * Escapes the given string, so it is HTML safe.
 * @param {string} html The input HTML to escape.
 * @return {string} The escaped HTML.
 */
function escapeHtml(html) {
  var s = '' + html;
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}

/**
 * Escapes the given URL.
 * @param {string} url The URL to escape.
 * @return {string} The escaped URL.
 */
function escapeUrl(url) {
  return url.replace(/</g, '%3C').replace(/>/g, '%3E').replace(/"/g, '%22');
}

/**
 * Escape a string, so that we can embed the string in the js code inside
 * another string.
 * @param {string} str The string to escape.
 * @return {string} The escaped string.
 */
function escapeJsString(str) {
  return str.replace('\\', '\\\\').replace('\"', '\\\"').replace('\'', '\\\'');
}

/**
 * Strips off all HTML tags.
 * @param {string} html The input HTML.
 * @return {string} The stripped version of HTML.
 */
function stripOffHtmlTags(html) {
  var s = '' + html;
  return s.replace(/\<[^\>]+\>/g, '');
}

function isArray(obj) {
  if (obj.constructor.toString().indexOf('Array') == -1) {
    return false;
  } else {
    return true;
  }
}

function getHTMLOneEntryList(thumb, title, href, price) {
  var s = '<tr class="cse-commerce-result"><td>' +
           (thumb ? '<a class="url" href="' + href + '">' +
           '<img src="' + thumb + '" border="0"></a>' :
           '') + '</td><td><a class="url" href="' + href + '">' +
           title + '</a></td><td>' + ' ' + price +
           '</td></tr>';
  return s;
}

function getHTMLOneEntryGrid(thumb, title, href, price) {
  var s = '<li class="result-grid"><div class="result-cont-grid">';
  s += thumb ? '<p class="result-image-grid"><a class="url" href="' +
       href + '"><img border="0" src="' + thumb +
       '"></a></p>' : '';

  /*if (title.length > 15) {
    title = title.substring(0, 12) + '...';
  }*/

  s += '<h3 class="result-h3-grid"><a wrap=soft href="' +
       href + '">' + title + '</a></h3><b>' + price + '</b></div>';

  return s;
}

function imgOnLoad(img, maxLength) {
  if (!maxLength) {
    maxLength = MAX_LENGTH;
  }
  var w = img.width;
  var h = img.height;
  if (w > h) {
    img.width = maxLength;
    img.height = maxLength * h / w;
  } else {
    img.height = maxLength;
    img.width = maxLength * w / h;
  }
}

function getPromotions(promotions) {
  // Create promotions section at the top.
  var str = '';
  if (promotions) {
    for (var i = 0, item; item = promotions.g$promotion[i]; ++i) {
      str += '<div class="cse-commerce-promotion">';
      str += '<table><tr>';
      if (item.g$image_link) {
        str += '<td class="cse-commerce-promotion-image" width="' +
            MAX_LENGTH + '">';
        str += '<a href="' + escapeUrl(item.g$link.$t) + '">';
        str += '<img src="' + escapeUrl(item.g$image_link.$t);
        str += '" height="' + MAX_LENGTH + '" onload="imgOnLoad(this)"></img>';
        str += '</a>';
        str += '</td>';
      }
      str += '<td class="cse-commerce-promotion-title">' +
             '<strong><a href="' + escapeUrl(item.g$link.$t) + '\">' +
             escapeHtml(stripOffHtmlTags(item.g$title.$t)) + '</a></strong>';
      if (item.g$snippet) {
        str += '<br/><span>' + escapeHtml(item.g$snippet.$t) + '</span>';
      }
      str += '</div></td></tr></table></div>';
    }
  }
  return str;
}

function getThumbnail(view, item) {
  var thumb;

  if ('image_link' in item.getAttributes()) {
    var thumbs = {};  // dictionary, key is height, value is url string.

    var thumb_list = item.getAttribute('image_link')['gm$thumbnail'];
    for (var j = 0; j < thumb_list.length; ++j) {
      var thumb_obj = thumb_list[j];
      thumbs[thumb_obj['height']] = thumb_obj['$t'];
    }
    thumb = (view == 'grid') ? thumbs[120] : thumbs[90];
    thumb = escapeUrl(thumb);
  }
  return thumb;
}

function getHTML(entries, promotions, view, gridImage, listImage) {
  var imagePrefix = 'http://www.google.com/cse/images/commerce/';

  if (view == 'grid') {
    if (gridImage) {
      gridImage.src = imagePrefix + 'grid_view_selected.png';
      gridImage.style.display = '';
    }
    if (listImage) {
      listImage.src = imagePrefix + 'list_view_unselected.png';
      listImage.style.display = '';
    }
  } else {
    if (gridImage) {
      gridImage.src = imagePrefix + 'grid_view_unselected.png';
      gridImage.style.display = '';
    }
    if (listImage) {
      listImage.src = imagePrefix + 'list_view_selected.png';
      listImage.style.display = '';
    }
  }

  var s = getPromotions(promotions);

  s += view == 'grid' ? '<div id="cse-main-div">' : '<table><colgroup>' +
               '<col id="cse-commerce-image">' +
               '<col id="cse-commerce-description">' +
               '<col id="cse-commerce-price"></colgroup><tbody>';

  for (var i = 0, item; item = entries[i]; ++i) {
    var title = item.getTitle().getText();
    var description = item.getContent().getText();
    var href = item.getLink('alternate').getHref();
    var price = item.getAttribute('price').getValue();
    price = price.substring(0, price.indexOf("usd"));
    price = "$" + parseFloat(price).toFixed(2);
    var thumb = getThumbnail(view, item);

    title = escapeHtml(title);
    href = escapeUrl(href);
    price = escapeHtml(price);
    s += view == 'grid' ? getHTMLOneEntryGrid(thumb, title, href, price) :
                 getHTMLOneEntryList(thumb, title, href, price);
  }

  s += view == 'list' ? '</tbody></table>' : '';
  return s;
}

function handleBucketNode(attrib, type) {
  if (!('high' in attrib)) {
    var idx = attrib['$t'].indexOf('..*');
    if (idx > 0) {
      attrib['display'] = 'Over $' + parseFloat(attrib['low']).toFixed(2);
    }
    return;
  }

  var isInt = type.indexOf('int') == 0;
  var typeLen = type.length;
  var hasUnit = (typeLen > 4) && (type.slice(typeLen - 4) == 'Unit');
  var error = isInt ? 1 : 0.01;

  var high = parseFloat(attrib['high']);
  var low = 'low' in attrib ? parseFloat(attrib['low'], 10) : 0;
  high = Math.max(high - error, low);

  low = 'low' in attrib ? low.toString() : '*';
  var tempValue = low + '..' + high;
  var displayTitle = "$" + parseFloat(low).toFixed(2) + ' - $' + parseFloat(high).toFixed(2);
  if (low == '*') {
    displayTitle = 'Under $' + parseFloat(high).toFixed(2);
  } else if (low == high) {
    displayTitle = low;
  }

  /*if (hasUnit) {
    var idx = attrib['$t'].indexOf(' ');
    if (idx > 0) {
      tempValue += attrib['$t'].slice(idx);
      displayTitle += attrib['$t'].slice(idx);
    }
  }*/

  attrib['$t'] = tempValue;
  attrib['display'] = displayTitle;
}

function getCountry(country) {
  country = country.toLowerCase();
  if (country == 'uk') {
    country = 'gb';
  }
  return country;
}

function getCurrency(country) {
  switch (country) {
    case 'gb':
      return 'gbp';
    case 'au':
      return 'aud';
    case 'de':
      return 'eur';
    case 'jp':
      return 'jpy';
    default:
      return 'usd';
  }
}

/**
 * Initializes Commerce Search preview code.
 *
 * Note: This script requires http://www.google.com/jsapi to be included
 * in your HTML page:
 * <script src="http://www.google.com/jsapi" type="text/javascript"></script>
 */
function initializeCommerceSearch(customerId,
                                  cx,
                                  resultsPanel,
                                  unfilteredAttrsPanel,
                                  filteredAttrsPanel,
                                  country,
                                  opt_doneCallback,
                                  opt_errorHandler,
                                  opt_currency,
                                  opt_language,
                                  opt_gridImage,
                                  opt_listImage,
                                  opt_itemtype) {
  google.load('gdata', '1.x');
  var baseUrlPrefix = 'http://www.google.com/base/feeds/';
  var baseService;

  // Global refinement vars.
  var sortOrder = 'match';
  var currentPage = 1;
  var queryString = '';
  var allEntries;
  var allAttrEntries;
  var viewPref = 'grid';
  var allPromotions;
  var gridImage = opt_gridImage;
  var listImage = opt_listImage;
  var filtersMap = {};  // Map which maps an attribute to a filter key.
  var typesMap = {};  // Map which maps an attribute to a type name.
  var unfilteredAttrs = unfilteredAttrsPanel;
  var filteredAttrs = filteredAttrsPanel;
  var reqCountry = getCountry(country);
  var currency = opt_currency ? opt_currency : getCurrency(reqCountry);
  var language = opt_language ? opt_language : 'en';
  var itemtype = opt_itemtype ? opt_itemtype : 'products';
  
  // This callback will run when the snippets feed query has complete
  // Customize based on which attributes you want to display.
  var handleSnippetsFeed = function(result) {
    var spellingSuggestions = [];
    for (var i = 0, item; item = result.feed.link[i]; ++i) {
      if (item.rel == 'http://schemas.google.com/g/2006#spellcorrection' &&
          item.title) {
        spellingSuggestions.push(item.title);
      }
    }
    if (opt_doneCallback) {
      var totalResults = result.feed.getTotalResults().getValue();
      var totalPages = Math.ceil(totalResults / RESULTS_LIMIT);
      opt_doneCallback(result.feed, spellingSuggestions, currentPage,
                       totalPages);
    }

    allEntries = result.feed.entry;
    allPromotions = result.feed.g$promotions;
    var str = getHTML(allEntries, allPromotions, viewPref, gridImage,
                      listImage);
    resultsPanel.innerHTML = str;
  };

  function truncateAndAddEllipses(nChars, str) {
    if (str.length > nChars) {
      return str.substring(0, nChars - 3) + '...';
    } else {
      return str;
    }
  }

  var getValues = function(t) {
    return ('gm$bucket' in t) ? t['gm$bucket'] : t.getValues();
  }

  // This callback will run when the snippets feed query has completed.
  var handleAttributesFeed = function(result) {
    var attrsFilter = '';
    var attrsUnfilter = '';
    var temp;

    allAttrEntries = result.feed.entry;

    for (var i = 0, item; item = allAttrEntries[i]; ++i) {
      var t = item.getAttribute();
      var attribs = getValues(t);
      typesMap[t.name] = t.type;

      if (filtersMap[t.name]) {
        var count = '';
        for (var j = 0, attrib; attrib = attribs[j]; ++j) {
          if (attrib['$t'] == filtersMap[t.name]['value']) {
            count = attrib['count'];
            break;
          }
        }

        attrsFilter += '<div><h4>By ' + t.name +
                       '</h4><div class="cse-commerce-facet">';
        switch(t.name){
          case 'color':
            attrsFilter += '<ul><li class="g-color"><img src="/lib/thestoragestore/' + trim(escapeHtml(filtersMap[t.name]['display'])).replace(' ','-') + '.gif" /></li>'
            break;
          default:
            attrsFilter += '<ul><li><b>' + truncateAndAddEllipses(20, escapeHtml(filtersMap[t.name]['display']));
            if (count != '') {
              attrsFilter += '(' + escapeHtml(count) + ')';
            }
            attrsFilter += '</b></li>';
            break;
        }

        attrsFilter += '<li><a href="javascript:void(0)" ' +
            'onClick="javascript:applyFilter(\'' + escapeJsString(t.name) +
            '\', null, null)">View all</a></li>';
        attrsFilter += '</ul></div></div>';
      } else {
        attrsUnfilter += '<div id=attr' + i + '>';
        attrsUnfilter += showBuckets(i, false);
        attrsUnfilter += '</div>';
      }
    }

    if (attrsFilter != '') {
      filteredAttrs.innerHTML = attrsFilter;
      filteredAttrs.style.display = '';
    } else {
      filteredAttrs.style.display = 'none';
    }

    if (attrsUnfilter != '') {
      unfilteredAttrs.innerHTML = attrsUnfilter;
      unfilteredAttrs.style.display = '';
    } else {
      unfilteredAttrs.style.display = 'none';
    }
  };

  function sortNumRange(attrib1, attrib2) {
    var low1 = 'low' in attrib1 ? parseFloat(attrib1['low']) : 0;
    var low2 = 'low' in attrib2 ? parseFloat(attrib2['low']) : 0;
    return low1 - low2;
  }

  // This function shows the buckets in an unfiltered facet. If all is set to
  // true all facets are shown with a "less" option if there are more than 5
  // facets. If all is set to false only 5 facets are shown with a "more..."
  // option.
  function showBuckets(i, all) {
    var entry = allAttrEntries[i];
    var attr = entry.getAttribute();
    var str = '<h4>By ' + attr.name +
              '</h4><div class="cse-commerce-facet"><ul>';
    var attribs = getValues(attr);
    var attrType = attr['type'];
    var isBucketType = 'gm$bucket' in attr;
    var showLess = false;
    var showMore = false;

    if (attribs.length <= 1) {
      return '';
    }

    attribs.sort(sortNumRange);

    for (var j = 0, attrib; attrib = attribs[j]; ++j) {
      if (j > 4) {
        if (!all) {
          showMore = true;
          break;
        } else {
          showLess = true;
        }
      }
      if (isBucketType) {
        handleBucketNode(attrib, attrType);
      }
      var displayTitle = 'display' in attrib ? attrib['display'] : attrib['$t'];
      var count = escapeHtml(attrib['count']);
      switch(attr.name){
        case 'color':
          str += '<li class="g-color"><a href="javascript:void(0)" ' +
                 'onClick="javascript:applyFilter(\'' + escapeJsString(attr.name) +
                 '\', \'' + escapeJsString(attrib['$t']) + '\', \'' +
                 escapeJsString(displayTitle) + '\')">' +
                 '<img src="/lib/thestoragestore/' + trim(escapeHtml(displayTitle)).replace(' ','-') + '.gif" />' +
                 '</a></li>';
          break;
        default:
          str += '<li><a href="javascript:void(0)" ' +
                 'onClick="javascript:applyFilter(\'' + escapeJsString(attr.name) +
                 '\', \'' + escapeJsString(attrib['$t']) + '\', \'' +
                 escapeJsString(displayTitle) + '\')">' +
                 truncateAndAddEllipses(20, escapeHtml(displayTitle)) +
                 '(' + count + ')</a></li>';
          break;
      }
    }
    if (showLess) {
      str += '<li class="less"><a href="javascript:void(0)" ' +
          'onClick="javascript:showBucket(' + i + ',false)">Less...</a></li>';
    } else if (showMore) {
      str += '<li class="more"><a href="javascript:void(0)" ' +
          'onClick="javascript:showBucket(' + i + ',true)">More...</a></li>';
    }
    str += '</ul></div>';
    return str;
  }

  function showBucketsDiv(index, all) {
    var div = document.getElementById('attr' + index);
    if (div) {
      div.innerHTML = showBuckets(index, all);
    }
  }

  // This callback will run if getSnippetFeed throws any errors.
  var handleError = function(error) {
    var message = error.cause ? error.cause.statusText :
        (error.message ? error.message : error);
    if (opt_errorHandler) {
      opt_errorHandler(message);
    } else {
      alert(message);
    }
  };

  // This function is called to clear the results pane.
  function clearResults() {
    if (gridImage) {
      gridImage.style.display = 'none';
    }

    if (listImage) {
      listImage.style.display = 'none';
    }

    resultsPanel.innerHTML = '';
  }

  function containSpecialChar(str) {
    var specialChars = '\\-|:=[]()*#<>+?!/&,%".';
    for (var i = 0; i < specialChars.length; ++i) {
      var sc = specialChars.charAt(i);
      if (str.indexOf(sc) >= 0) {
        return true;
      }
    }
    return false;
  }

  // Here we construct the call to Base using the GDATA API.
  // We make two requests:
  //  - One to fetch the search results
  //  - The other to get the attribute counts & buckets
  function getMyFeed(q) {
    if (q == '') {
      handleError('Empty query');
      return;
    }
    if (customerId == '') {
      handleError('Missing or invalid customer ID');
      return;
    }
    queryString = q.replace(/#/g, '%23');
    serveAds(queryString);
    baseService = new google.gdata.gbase.GoogleBaseService('Commerce-Demo');
    var query = new google.gdata.gbase.SnippetsQuery(
        baseUrlPrefix + 'snippets');
    query.setFullTextQuery(queryString);
    var baseQuery = '[customer id:' + customerId + ']';
    baseQuery += '[item type:' + itemtype + ']';
    baseQuery += '[target country:' + reqCountry + ']';
    baseQuery += '[item language:' + language + ']';

    for (var key in filtersMap) {
      if (filtersMap[key]) {
        var val = filtersMap[key]['value'];
        if (typesMap[key] != 'text' || containSpecialChar(val)) {
          // partial match
          baseQuery += '[' + key + ':' + val + ']';
        } else {
          // exact match for text type
          baseQuery += '[' + key + '=="' + val + '"]';
        }
      }
    }

    query.setBq(baseQuery);
    if (sortOrder == 'match') {
      query.setOrderby('auto');
    } else if (sortOrder == 'price_low') {
      query.setOrderby('price(float ' + currency + ')');
      query.setSortorder('ascending');
    } else if (sortOrder == 'price_high') {
      query.setOrderby('price(float ' + currency + ')');
      query.setSortorder('descending');
    } else if (sortOrder == 'name') {
      query.setOrderby('title(text)');
      query.setSortorder('ascending');
    }

    query.setStartIndex((currentPage - 1) * RESULTS_LIMIT + 1);
    query.setMaxResults(RESULTS_LIMIT);
    query.setParam('cx', cx);
    query.setParam('content', 'promotions,thumbnails');

    baseService.getSnippetsFeed(query, handleSnippetsFeed, handleError);

    // Get attributes.
    var attributes = new google.gdata.gbase.AttributesQuery(baseUrlPrefix +
                                                            'attributes');
    attributes.setFullTextQuery(queryString);
    attributes.setBq(baseQuery);
    attributes.setParam('cx', cx);
    attributes.setParam('max-values', '20');
    attributes.setParam('bucketing', 'auto');

    baseService.getAttributesFeed(attributes, handleAttributesFeed,
                                  handleError);
  };

  // Called when we submit a new search term.
  function formSubmit(query, order) {
    currentPage = 1;

    if (order) {
      sortOrder = order;
    } else {
      sortOrder = 'match';
      filtersMap = {};
    }

    clearResults();
    $("#searchText").blur();
    getMyFeed(query);
  };

  // Called when we submit a new spelling correction.
  function spellSubmit(query) {
    currentPage = 1;
    clearResults();
    getMyFeed(query);
  }

  // Called when we navigate to the given page.
  function pageSubmit(page) {
    currentPage = page;
    clearResults();
    getMyFeed(queryString);
  }

  // Called when we view to change the view
  function changeView(view, resultsPanel) {
    viewPref = view;
    resultsPanel.innerHTML = getHTML(allEntries, allPromotions, view, gridImage,
                                     listImage);
  }

  // Called when a filter is applied.
  function applyFilter(query, key, value, display) {
    currentPage = 1;
    filtersMap[key] = value ? {'value': value, 'display': display} : null;
    clearResults();
    getMyFeed(query);
  }

  return {
    'formSubmit': formSubmit,
    'spellSubmit': spellSubmit,
    'pageSubmit': pageSubmit,
    'changeView': changeView,
    'applyFilter': applyFilter,
    'showBucketsDiv': showBucketsDiv };
}

// Returns the HTML text for the found text message.
function printFoundText(query, currentPage, totalResults) {
  query = escapeHtml(query);
  if (totalResults > 0) {
    var endIndex = Math.min(currentPage * RESULTS_LIMIT, totalResults);
    var startIndex = (currentPage - 1) * RESULTS_LIMIT + 1;
    return ['Results ',
            startIndex.toString(),
            ' - ',
            endIndex.toString(),
            ' of about ',
            totalResults.toString(),
            ' for <string>',
            query,
            '</string>'].join('');
  } else {
    return '0 results for <strong>' + query + '</strong>';
  }
}

function printPageLink(text, page, link, last) {
  var html = '';
  if (link) {
    html += '<a href="javascript:void(0);" onclick="pageSubmit(' + page +
        ');">';
  } else {
    html += '<strong>';
  }
  html += text;
  html += link ? '</a>' : '</strong>';
  if (!last) {
    html += '&nbsp;|&nbsp;';
  }
  return html;
}

// Returns the HTML text for the paging bar.
function printPageBar(currentPage, totalPages) {
  var PAGES_ONSCREEN = 10;  // We display 10 page links at once.

  if (totalPages <= 0) {
    return '';
  }

  var pagesStart = currentPage - Math.floor((PAGES_ONSCREEN - 1) / 2);
  var pagesEnd = currentPage + Math.floor(PAGES_ONSCREEN / 2);
  if (pagesStart < 1) {
    var delta = 1 - pagesStart;
    pagesStart = 1;
    pagesEnd += delta;
    if (pagesEnd > totalPages) {
      pagesEnd = totalPages;
    }
  } else if (pagesEnd > totalPages) {
    var delta = pagesEnd - totalPages;
    pagesEnd = totalPages;
    pagesStart -= delta;
    if (pagesStart < 1) {
      pagesStart = 1;
    }
  }

  var str = [];
  if (currentPage > 1) {
    str.push(printPageLink('&lsaquo; Previous', currentPage - 1, true, false));
  }
  for (var i = pagesStart; i <= pagesEnd; ++i) {
    str.push(printPageLink(i, i, i != currentPage,
                           i == totalPages && currentPage == totalPages));
  }
  if (currentPage < totalPages) {
    str.push(printPageLink('Next &rsaquo;', currentPage + 1, true, true));
  }
  return str.join('');
}

function trim(str){
	return str.replace(/^\s+|\s+$/g,"");
}
function serveAds(query){
  var pageOptions = {
  'pubId' : 'pub-5905364257116217',
  'query' : query,
  'linkTarget' : '_blank'
  }
  var adblock1 = {
  'container' : 'adblock1',
  'number' : 3,
  'width' : 'auto',
  'lines' : 2,
  'fontFamily' : 'arial',
  'fontSizeTitle' : '14px',
  'fontSizeDescription' : '14px',
  'fontSizeDomainLink' : '14px'
  };
  new google.ads.search.Ads(pageOptions, adblock1);
}
