// Copyright 2008 Google Inc.  All Rights Reserved.

/**
 * @fileoverview General functions for the help center
 * Included in wrapper_hc.cs
 *
 * @author dereklei@google.com (Derek Lei),
 * @author heathercash@google.com (Heather Cash)
 */


var ERROR_DIV_ID = 'hcError';
var STAR_ON = 'http://www.google.com/help/hc/images/star-on-transp-15.gif';
var STAR_OFF = 'http://www.google.com/help/hc/images/star-off-transp-15.gif';
var NEWBIE_PROMO_DIV_ID = 'newbiePromo';

function correctLangCode_default(lang){
  s = window.location;
  s = s.toString();

  if (lang == "zh-CN")
    correctedLang = "zh_CN";
  else if (lang == "zh-CN_CN")
    correctedLang = "zh_CN";
  else if (lang == "zh-TW")
    correctedLang = "zh_TW";
  else if (lang == "zh-TW_TW")
    correctedLang = "zh_TW";
  else if (lang == "pt-BR")
    correctedLang = "pt_BR";
  else if (lang == "pt-BR_BR")
    correctedLang = "pt_BR";
  else if (lang == "en-GB")
    correctedLang = "en_GB";
  else if (lang == "en-GB_GB")
    correctedLang = "en_GB";
  else if (lang == "en-US")
    correctedLang = "en_US";

  s = s.replace(lang, correctedLang);
  location.replace(s);

  return correctedLang;
}

function setCookies_default(cookieName,cookieValue,calledFrom,days) {
  if (cookieValue == "") {
    var cookieValue = getQueryVariable_default("hl");
  }
  if (cookieValue) {
    var today = new Date();
    var expire = new Date();
    if (!days) {
      days = 365;
    }
    expire.setTime(today.getTime() + 3600000*24*days);

    cookie  = cookieName + "=" + escape(cookieValue);
    cookie += ";expires=" + expire.toGMTString();
    cookie += ";path=" + cookie_path;
    if(cookie_domain != "")
      cookie += ";domain=" + cookie_domain;
    document.cookie = cookie;
  }
  if (calledFrom == "dropdown") {
    newURL = new String(window.location);
    newURL = newURL.replace("hl=", "hlrm=");
    if(newURL.search(/#/i)>=0) {
      tempURL = newURL.split('#');
      if(tempURL[0].search(/hlrm=/i)>=0) {
        tempURL[0]=tempURL[0].replace(/(hlrm=((?:[a-z][a-z5][a-z]?(?:[-_][a-zA-Z0-9]{2,4})?)?))/i, 'hlrm='+cookieValue);
        newURL = tempURL[0]+((tempURL[1]!= undefined)?'#'+tempURL[1]:'');
      } else {
        if(tempURL[0].search(/\?/i)>=0) {
          newURL = tempURL[0]+'&hlrm='+cookieValue+((tempURL[1]!= undefined)?'#'+tempURL[1]:'');
        } else {
          newURL = tempURL[0]+'?hlrm='+cookieValue+((tempURL[1]!= undefined)?'#'+tempURL[1]:'');
        }
      }
    }
    window.location.href = newURL;
  }
}

function getQueryVariable_default(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split("&");
  for (var i=0;i<vars.length;i++) {
    var pair = vars[i].split("=");
    if (pair[0] == variable) {
      return pair[1];
    }
  }
 }

function searchValidate(theForm) {
   if (theForm.query.value=='') {
     alert(lang_search_blank);
     return false;
   }
   return true;
}

function getCookie() {

  var args = getCookie.arguments;
  var name = args[0];
  var sep = args[1];

  var start = document.cookie.indexOf(name + "=");
  var len = start + name.length + 1;
  if ((!start) &&
    (name != document.cookie.substring(0, name.length))) {
    return null;
  }
  if (start == -1) {
    return null;
  }
  var end = document.cookie.indexOf(sep, len);
  if (end == -1) {
    end = document.cookie.length;
  }
  return unescape(document.cookie.substring(len, end));
}


function showLayer(layer){
 try {
 document.getElementById(layer).style.display = "block";
 } catch(e){}
}
function showLayerDefault(layer){
 try {
 document.getElementById(layer).style.display = "";
 } catch(e){}
}
function hideLayer(layer){
 try {
 document.getElementById(layer).style.display = "none";
 } catch(e){}
}

function toggleLayer(id) {
  var obj = document.getElementById(id);
  if (obj) {
    if (obj.style.display == "none") {
      obj.style.display = "block";
    } else {
      obj.style.display = "none";
    }
  }
}

function toggleLayerDefault(id) {
  var obj = document.getElementById(id);
  if (obj) {
    if (obj.style.display == "none") {
      obj.style.display = "";
    } else {
      obj.style.display = "none";
    }
  }
}

function toggleZippy(layer){
 try {
   document.getElementById(layer).className = (document.getElementById(layer).className == "expand")? "collapse": "expand";
 } catch(e){}
}


function showAll(node){
   /* shows all children of "node"  This is for testing purposes. */
  var treeList = '';
  if (node.nodeType ==1 /*Node.ELEMENT_NODE */){
    var holder;
    var child;
    for (var children = node.childNodes, i=0; i <children.length; i++){
      child = children[i];
      holder = 'child ' + i + ' id: ' + child.id + '\tnodeType: ' + child.nodeType + '\n';
      treeList += holder;
      if (child.nodeType == 1){
        child.style.display = "block";
      }
    }
  }
}


function hideAll(node){
  /* shows all children of "node"  This is for testing purposes. */
  var treeList = '';
  if (node.nodeType ==1 /*Node.ELEMENT_NODE */){
    var holder;
    var child;
    for (var children = node.childNodes, i=0; i <children.length; i++){
      child = children[i];
      holder = 'child ' + i + ' id: ' + child.id + '\tnodeType: ' + child.nodeType + '\n';
      treeList += holder;
      if (child.nodeType == 1){
        child.style.display = "none";
      }
    }
  }
}

function nextElement(node){ //grabs the next non-text element
  /* returns the next sibling of "node"
     where next sibling is a Node.ELEMENT_NODE nodeType */
  var k = node.nextSibling;
  while (k.nodeType != 1 /*not Node.ELEMENT_NODE*/){
    k = k.nextSibling;
  }
  return k;
}

function showNode(node) {if (node.nodeType == 1) node.style.display = "";}
function hideNode(node){if (node.nodeType == 1) node.style.display = "none";}

/**
 * Finds all radio buttons in node and clear them.
 * @param {Object} node Element that we want to clear radio buttons for.
 */
function uncheckRadios(node) {
  if (node.nodeType == 1) {
    var tagArray =
      document.getElementById(node.id).getElementsByTagName('input');
    for (var i = 0; i < tagArray.length; i++) {
      if (tagArray[i].type == 'radio') {
        tagArray[i].checked = false;
      }
    }
  }
}

function hideBelow(node){ //hides everything below the level of node
  /* calls hideNode() on all siblings coming after "node"
     where next sibling is a Node.ELEMENT_NODE nodeType */
  var k = nextElement(node);
  while (k.style.display == "block" || k.style.display == ""){
    hideNode(k);
    uncheckRadios(k);
    k = nextElement(k);
  }
}

function setNext(currNode, nextNode){
  /* makes sure "nextNode" comes after "currNode"
     calls showNode() on the "nextNode" */
  if (currNode.parentNode.id == nextNode.parentNode.id){ //same parents?
    var old_node = nextElement(currNode);
    //replace if nextNode is not immediately nextElement of currNode
    if(old_node.id != nextNode.id){
      var parent = currNode.parentNode;
      var new_node = parent.removeChild(nextNode);
      old_node = parent.replaceChild(new_node, old_node);
      parent.appendChild(old_node);
      old_node = nextElement(currNode);
    }
    showNode(old_node);
  } else {
    return;
  }
}

function getNext(curr, next){
  /* uses the "curr" and "next" layer names and grab their respective node elements
     calls hideBelow() on the node associated with "curr"
     calls setNext() on nodes associated with "curr and "next" */
  var n = document.getElementById(curr);
  var m = document.getElementById(next);

  hideBelow(n);
  setNext(n, m);
}

function showOnly(parent, child){
  var p = document.getElementById(parent);
  var c = document.getElementById(child);
  hideAll(p);
  showNode(c);
}


function check_radio(formname, forminput) {
  radioObj = document.forms[formname].elements[forminput];
  if(!radioObj)
    return "";
  var radioLength = radioObj.length;
  if(radioLength == undefined) {
    if(radioObj.checked) {
      return radioObj.value;
    } else {
      return "";
    }
  }
  for(var i = 0; i < radioLength; i++) {
    if (radioObj[i].checked) {
      return radioObj[i].value;
    }
  }
  return "";
}

function mirrorRadios(radioButton) {
  var radios = document.getElementsByName('search_type');
  for (var i = 0; i < radios.length; i++) {
    if (radios[i].value == radioButton.value) {
      radios[i].checked = true;
      radioButton.focus();
    }
  }
}



var map = null;
var geocoder = null;

function load() {
  if (GBrowserIsCompatible()) {
    geocoder = new GClientGeocoder();
  }
}

function showAddress(address) {
  if (geocoder) {
    geocoder.getLatLng(
      address,
        function(point) {
          if (!point) {
            document.getElementById('errortxt').style.display='block';
          } else {
            var addressq = address.replace(/ /g, "+");
            document.getElementById('maplink').innerHTML="<br>It looks like you're searching for a location. You can find <a href=http://maps.google.com/?q="
              + addressq + "&z=8 onclick=\"urchinTracker('/outbound/helpcenter/geocodesearch')\">results for " + address + " in Google Maps</a>.<br><br>";
          }
       }
    );
  }
}

/**
 * Creates an XMLHttpRequest object, ready to be used to make a request.
 * Handles browser compatibility.
 *
 * @return {XMLHttpRequest} A fresh XMLHttpRequest.
 */
function createXmlHttpRequest() {
  var http_request = false;
  if (window.XMLHttpRequest) { // Mozilla, Safari, IE7...
    http_request = new XMLHttpRequest();
  } else if (window.ActiveXObject) { // IE6 and older
    http_request = new ActiveXObject('Microsoft.XMLHTTP');
  }
  return http_request;
}

/**
 * Makes an asyncronous GET request to the specified url, ignoring the result.
 *
 * @param {string} url The URL to request.
 */
function makeRequest(url) {
  var http_request = createXmlHttpRequest();
  if (http_request) {
    http_request.open('GET', url, true);
    http_request.send(null);
  }
}

/**
 * Sends an asyncronous POST request to the specified URL with the specified
 * POST parameters. The given callback function will be called on completion of
 * the request, with the XMLHttpRequest object passed to it as the only
 * parameter.
 *
 * @param {string} url The URL to request.
 * @param {string} params The body of the POST request.
 * @param {Function} callback The callback function to be called on completion.
 */
function postUrl(url, params, callback) {
  var xhr = createXmlHttpRequest();
  xhr.onreadystatechange = function() { callback(xhr) };
  xhr.open('POST', url, true);
  xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  xhr.setRequestHeader('Content-length', params.length);
  xhr.setRequestHeader('Connection', 'close');
  xhr.send(params);
}

// adds label to form.query
// optional 3rd arg is temp query field name
//  if it exists, then copy value from that field,
//  append label, then set result to form.query
function addLabel(form, label){
  var args = addLabel.arguments;
  var tempFieldname = args[2];
  var finalValue = (tempFieldname != null) ? form[tempFieldname].value : form.query.value;

  if (finalValue != ""){
    finalValue += " label:" + label;
    form.query.value = finalValue;
    return true;
  }
  return false;
}

/**
 * Product recommendations - used in module_recommend.cs
 *
 * Called in body onload if Config.RecEng.Enabled set in config.hdf
 * Makes an RPC call to the Recommendation Engine service
 *   to get a Google product to recommend to the user.
 * Passes in a callback function, showRecommendation,
 *   that displays the recommendation on the page.
 *
 * @param {string} type the Recommendation Engine divides the Google world into
 *   Business and Consumer products and each request indicates which group it's part
 *   of. Set in config.hdf - should be either CONSUMER or BUSINESS.
 * @param {string} gaiaName Gaia's name for the Help Center product making the
 *   request. Identifies the product displaying the Recommendation and avoids
 *   recommending a product to users when they are using the product. Set in URLs
 *   array.
 * @param {string} language the Recommendation Engine will only return
 *   recommendations that match the language.
 */

function getRecommendations(type, gaiaName, language) {
  if (document.getElementById("rec")) {
    var recEng = new goog.RecEng();

    recEng.config = recEng[type];
    recEng.location = "helpCenter";
    if (gaiaName) {
      recEng.caller = gaiaName;
    }
    recEng.lang = language;
    recEng.nRecs = 1;                       // # of recommendations to fetch
    recEng.divs = [ "rec" ];                // ids of divs to populate
    recEng.layout = showRecommendation;
    recEng.recommend();                     // fetch and populate
  }
}

/**
 * Callback function passed into the Recommendation Engine.
 * Called for each recommendation that is returned.
 * Gives us complete control over the layout of a
 * recommendation.
 *
 * @param {string} divId name of the div in which to display the recommendation
 * @param {Object} rec the Recommendation object to be displayed in divId
 */

function showRecommendation(divId, rec) {
  document.getElementById(divId + "-iconImage").src = rec.iconImage;
  document.getElementById(divId + "-title").innerHTML = rec.shortTitle;
  document.getElementById(divId + "-title").href = rec.callToActionUrl;
  document.getElementById(divId + "-description").innerHTML = rec.shortDescription;
  document.getElementById(divId).style.display = "";
}


/**
 * Called from search box (searchbox_center.cs) if user clicks Search Web
 * Does a search on Google.com
 *
 * @param {Element} form The calling form
 */

function searchWeb(form) {
  var query = form.elements["temp_query"].value;

  if (query == ""){
    alert(searchbox_warning);
  }
  else {
    window.location = url_searchbox + "&q=" + query;
  }
  return false;
}


/**
 * Called from search box (searchbox_center.cs) if user clicks Search Help
 * or presses Enter from the search box
 * Does a search w/in the HC
 *
 * @param {Element} form The calling form
 */

function searchHelp(form) {
  form.elements["query"].value = form.elements["temp_query"].value;

  // if user has refined their last query, then this one should be
  // refined too
  if(global_more_value) {
    form.elements["query"].value += " more:" + global_more_value;
  }

  // if search_all_langs is set, then CSE Search Across Languages is enabled
  // so we need to add inurl:hl=xx to the query to get the proper language
  // results
  if(global_search_all_langs) {
    form.elements["query"].value += " inurl:hl=" + hc_lang;
  }
  return true;
}


/**
 * Goes to a URL
 *
 * @param {string} url The URL to grab
 */

function openURL(url) {
  document.location = url;
}


/**
 * Sets a cookie for this HC, so we know the user has
 * seen the newbie promo already
 * Called from hideNewbiePromo(), and also from the <a href>
 * in the text of the promo
 */

function setNewbieCookie() {
  setCookies_default(global_newbie_cookie, 1, '', '30');
}


/**
 * Hides the newbie promo and sets a cookie
 */

function hideNewbiePromo() {
  hideLayer(NEWBIE_PROMO_DIV_ID);
  setNewbieCookie();
}

/**
 * Shows an error at the top of the page (below the breadcrumbs)
 *
 * @param {string} e The error message to display
 */

function showError(e) {
  document.getElementById(ERROR_DIV_ID).innerHTML = e +
    ' (<a href="javascript:hideLayer(ERROR_DIV_ID)">Dismiss</a>)';
  showLayer(ERROR_DIV_ID);
}


/**
 * Marks the current page as bookmarked / unbookmarked on the client side,
 * displays the correct icon
 *
 * @param {boolean} b Whether the page should now be bookmarked, or not
 */

function markBookmarked(b) {
  global_bookmarked = b;
  document.getElementById('bookmarkIcon').src = b ? STAR_ON : STAR_OFF;
}


/**
 * If current page is bookmarked, this unbookmarks it, and vice-versa
 */

function toggleBookmark() {
  hideLayer(ERROR_DIV_ID);
  var action = global_bookmarked ? 'remove' : 'add';
  url = global_hc_bookmark[action].url;

  var params = 'xt=' +  global_hc_bookmark[action].token;
  if (action == 'add') {
    params += '&title=' + escape(document.title);
    params += '&url=' + escape(document.location);
  }

  var callback = function(req) {
    if (req.readyState == 4) {
      // if error, show error and toggle bookmark back
      if (req.status != 204) {
        markBookmarked(!global_bookmarked);
        showError('Error saving bookmark: ' + req.status);
      }
    }
  };
  postUrl(url, params, callback);
  markBookmarked(!global_bookmarked);
}

/**
  * This function dynamically adds an additional field to 
  * the fieldset specified in the function params. Field
  * may be of any type, also specified in the params.
  *
  * @param {string} field (base field name (will have _# appended))
  * @param {string} area (fieldset id (will have _area appended))
  * @param {string} fieldtype (type of field [file/text])
*/
function addField(field, area, fieldtype) {
if(!document.getElementById) return;

  var field_area = document.getElementById(area);
  var all_inputs = field_area.getElementsByTagName("input");

  var last_item = all_inputs.length - 1;
  var last = all_inputs[last_item].id;
  var count = Number(last.split("_")[1]) + 1;

  if(document.createElement) {
    var input = document.createElement("input");
    var a = document.createElement('a');

    input.id = field+"_"+count;
    a.textContent = global_lang_ifield_remove;
    a.href = "javascript:deleteField('"+field+"','"+count+"');";
    a.id = field+"_a"+count;
    input.name = input.id;
    input.type = fieldtype;

    field_area.appendChild(input);
    field_area.appendChild(a);
  }

}

/**
  * This function dynamically removes an additional field from
  * the fieldset specified in the function params. Field
  * and related remove link will be removed.
  *
  * @param {string} field (base field name (will have _# appended))
  * @param {int} count (# of the field in the list)
*/
function deleteField(field, count) {
  var linkId = field+"_a"+count;
  var elId = field+"_"+count;
  var elToRem = document.getElementById(elId);
  var linkToRem = document.getElementById(linkId);
  elToRem.parentNode.removeChild(elToRem);
  linkToRem.parentNode.removeChild(linkToRem);
}

/**
 * Toggles the state of a star icon. This will do odd things to any image
 * passed to it which is not a star icon.
 *
 * @param {Element} img The img element displaying the star.
 */
function toggleStarIcon(img) {
  img.src = (img.src == STAR_ON)? STAR_OFF : STAR_ON;
}

/**
 * Toggles the starred status of an item on the starred items page.
 *
 * @param {Element} img The img element of the star icon.
 * @param {string} removeUrl The URL to unset the starred status of the item.
 * @param {string} addUrl The URL to set the starred status of the item.
 * @param {string} removeToken The XSRF token to unset the starred status of the
                   item.
 * @param {string} addToken The XSRF token to set the starred status of the
                   item.
 * @param {string} helpcenter The ID of the helpcenter the item belongs to.
 * @param {string} starredUrl The URL of the starred item.
 * @param {string} starredTitle The title of the starred item.
 */
function toggleStar(img, removeUrl, addUrl, removeToken, addToken, helpcenter,
                    starredUrl, starredTitle) {
  var wasStarred = (img.src == STAR_ON);
  var url = wasStarred ? removeUrl : addUrl;
  var params = 'xt=' + escape(wasStarred ? removeToken : addToken);
  params += '&hc=' + escape(helpcenter);
  params += '&title=' + escape(starredTitle);
  params += '&url=' + escape(starredUrl);
  callback = function(xhr) {
    if (xhr.readyState == 4) {
      if (xhr.status != 204) {
        toggleStarIcon(img);
      }
    }
  };
  postUrl(url, params, callback);
  toggleStarIcon(img);
}

/**
 * Iterates over the items in the starred items page and renders a star by
 * each.
 */
function renderStars() {
  var imgs = document.getElementById('starreditemcontent')
      .getElementsByTagName('img');
  for (var i = 0; i < imgs.length; i++) {
    // TODO(roryparle): Replace this with goog.dom.classes.has when
    // Closure-izing this file.
    if (/\bstar\b/.test(imgs[i].className)) {
      imgs[i].src = STAR_ON;
    }
  }
}

/**
 * Tests the limit of a text box and does now allow further input.
 * Must use substring instead of return false to allow deletion
 * of characters. 
 *
 * @param {element} el The field element being monitored.
 * @param {int} limit Max # of characters allowed.
 */
function testLimit(el, limit) {
  if (el.value.length > (limit-1)) {
    el.value = el.value.substring(0, limit-1);
  }
  return true;
}

/**
 * Modifies a text field's counter span to display # characters
 * remaining within the limit.
 *
 * @param {element} el The field element being monitored.
 * @param {int} spanId Unique id of span counter. 
 * @param {int} limit Max # of characters allowed.
 */
function incrementCounter(el, spanId, limit) {
  var spanObj = document.getElementById(spanId);
  if (spanObj) {
    if (limit - el.value.length < 0) {
      content = 0;
    } else {
      content = limit - el.value.length;
    }
    spanObj.removeChild(spanObj.firstChild);
    spanObj.appendChild(document.createTextNode(content));
  }
}

