/*------------------------------------------------------------------------
 * Set of function used for google search stuff.
 *
 * Dependencies:
 *  dojo
 *
 * Author:
 *  g stoianov
 *
 * @version $Id: siteSearch.js,v 1.9 2010/10/29 12:56:59 obo Exp $
 *
 *-----------------------------------------------------------------------*/

dojo.require("dojo.data.ItemFileWriteStore");

//some static values for the results pane, must be updated with the search xsp
var statics = {
  RESULT_PANE:               "searchResultsPane",
  ALL_RESULTS:               "all_search_results_",
  PDF_RESULTS:               "pdf_search_results_",
  HTML_RESULTS:              "html_search_results_",
  XLS_RESULTS:               "xls_search_results_",
  CSV_RESULTS:               "csv_search_results_",
  REQUIRED_PARAMS:           ["tabId","start","form", "as_q", "q"],
  ALL_RESULTS_ID:            "lev1_1",
  PDF_RESULTS_ID:            "lev1_2",
  HTML_RESULTS_ID:           "lev1_3",
  XLS_RESULTS_ID:            "lev1_4",
  CSV_RESULTS_ID:            "lev1_5"
};

//some static values for control ids, must be updated with the search xsp
var controlIds = {
  SEARCH_STACK_CONTAINER_ID: "searchStackContainer",
  RESULT_PANE_ID:            "tabs_level1",
  Q:                         "q",
  AS_Q:                      "as_q",
  AS_EPQ:                    "as_epq",
  AS_OQ:                     "as_oq",
  AS_EQ:                     "as_eq",
  AS_OCCT:                   "as_occt",
  NUM:                       "num",
  AS_FILETYPE:               "as_filetype",
  SORT:                      "sort",
  TAB_IDS:                   [statics.ALL_RESULTS_ID,
                              statics.PDF_RESULTS_ID,
                              statics.HTML_RESULTS_ID,
                              statics.XLS_RESULTS_ID,
                              statics.CSV_RESULTS_ID]
};

var currForm  = "basic";    //which form is viewed
var currTab   = "lev1_1";   //which tab is viewed
var currStart = "";         //which is the current start record for the viewed tab
var q         = "";
var as_q      = "";
var as_epq    = "";
var as_oq     = "";
var as_eq     = "";
var num       = "10";
var sort      = "";

var memStore = new dojo.data.ItemFileWriteStore(
{ data:
    {
        identifier: "memory",
        label:  "memory",
        items:  [
                  {
                    memory: "CURRENT_FORM", value: "basic"
                  },
                  {
                    memory: "CURRENT_TAB", value: "lev1_1"
                  },
                  {
                    memory: "CURRENT_START", value: ""
                  },
                  {
                    memory: "Q", value: ""
                  },
                  {
                    memory: "AS_Q", value: ""
                  },
                  {
                    memory: "AS_EPQ", value: ""
                  },
                  {
                    memory: "AS_OQ", value: ""
                  },
                  {
                    memory: "AS_EQ", value: ""
                  },
                  {
                    memory: "NUM", value: "10"
                  },
                  {
                    memory: "SORT", value: ""
                  }
                ]
    }
});

memStore.fetchItemByIdentity({
  identity: "CURRENT_FORM",
  onItem: function(item, request) {
    currForm = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "CURRENT_TAB",
  onItem: function(item, request) {
    currTab = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "CURRENT_START",
  onItem: function(item, request) {
    currStart = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "Q",
  onItem: function(item, request) {
    q = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "AS_Q",
  onItem: function(item, request) {
    as_q = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "AS_EPQ",
  onItem: function(item, request) {
    as_epq = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "AS_OQ",
  onItem: function(item, request) {
    as_oq = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "AS_EQ",
  onItem: function(item, request) {
    as_eq = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "NUM",
  onItem: function(item, request) {
    num = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

memStore.fetchItemByIdentity({
  identity: "SORT",
  onItem: function(item, request) {
    sort = item;
  },
  onError: function(item, request) {
    console.log("mem error on: " + item);
  }
});

// Set the value of a dijit.Form control from an HTTP formatted URL query string
// so that the underlying memory and view are updated.
// Note: This method is for single-valued controls i.e. only the first value is
// used even if many exist in the query string
// @return True if a match is found and the values set, false if not
var setSingleQueryParam = function(that, queryParams) {
  var params = _encodeQueryParams(queryParams).split("&");
  var nvp = [];
  var i = 0;
  var name = "";
  var value = "";

  for( ; i < params.length; i++) {
    //name value pairs split
    nvp = params[i].split("=");
    name = nvp[0] ? nvp[0] : ""; //avoid undefined and nulls
    value = nvp[1] ? nvp[1] : "";
    //console.log("> > > " + i + " : " + name + " -> " + value);
    if (name === that._ctrlId) {
      //console.log("> > match found.");
      that.setStoreValue(value);
      that.setFormValue(_convertAmpersand(decodeURI(value)));
      return true;
    }
  }
  return false;
};

// coverts %26 ampersand to the opposite &
_convertAmpersand = function(ampersandContainingString) {
  //console.log(" Convert ampersand in: " + ampersandContainingString);
  var encAmpValues = [];
  var ampValues = [];
  var encAmpIndex = ampersandContainingString.indexOf('%26');
  var ampIndex = ampersandContainingString.indexOf('&');
  var i = 0;
  var out = "";

  if(encAmpValues >= 0) {
    //split on the encrypted and add the &'s
    encAmpValues = ampersandContainingString.split('%26');

    for( ; i < encAmpValues.length; i ++) {
      out += encAmpValues[i] + "&";
    }
    out = out.substring(0, out.lastIndexOf("&"));
  }

  //console.log(" returning out: " + out);
  return out;
};


var Q = {
  _ctrlId:     "q",
  _paramName:  "q",
  getStoreValue: function() {
    return memStore.getValue(q,"value");
  },
  setStoreValue: function(val) {
    memStore.setValue(q, "value", val);
  },
  getFormValue: function() {
    return dijit.byId(this._ctrlId).getValue();
  },
  setFormValue: function(val) {
    return dijit.byId(this._ctrlId).setValue(val);
  },
  getQueryParam: function() {
    return "&" + this._paramName + "=" + this.getStoreValue() ;
  },
  setFromQueryParam: function(queryParams) {
    return setSingleQueryParam(this, queryParams);
  }
};

var AS_Q = {
  _ctrlId:     "as_q",
  _paramName:  "as_q",
  getStoreValue: function() {
    return memStore.getValue(as_q,"value");
  },
  setStoreValue: function(val) {
    memStore.setValue(as_q, "value", val);
  },
  getFormValue: function() {
    return dijit.byId(this._ctrlId).getValue();
  },
  setFormValue: function(val) {
    return dijit.byId(this._ctrlId).setValue(val);
  },
  getQueryParam: function() {
    return "&" + this._paramName + "=" + this.getStoreValue();
  },
  setFromQueryParam: function(queryParams) {
    return setSingleQueryParam(this, queryParams);
  }
};

var AS_EPQ = {
  _ctrlId:     "as_epq",
  _paramName:  "as_epq",
  getStoreValue: function() {
    return memStore.getValue(as_epq,"value");
  },
  setStoreValue: function(val) {
    memStore.setValue(as_epq, "value", val);
  },
  getFormValue: function() {
    return dijit.byId(this._ctrlId).getValue();
  },
  setFormValue: function(val) {
    return dijit.byId(this._ctrlId).setValue(val);
  },
  getQueryParam: function() {
    return "&" + this._paramName + "=" + this.getStoreValue();
  },
  setFromQueryParam: function(queryParams) {
    return setSingleQueryParam(this, queryParams);
  }
};

var AS_OQ = {
  _ctrlId:     "as_oq",
  _paramName:  "as_oq",
  getStoreValue: function() {
    return memStore.getValue(as_oq,"value");
  },
  setStoreValue: function(val) {
    memStore.setValue(as_oq, "value", val);
  },
  getFormValue: function() {
    return dijit.byId(this._ctrlId).getValue();
  },
  setFormValue: function(val) {
    return dijit.byId(this._ctrlId).setValue(val);
  },
  getQueryParam: function() {
    return "&" + this._paramName + "=" + this.getStoreValue();
  },
  setFromQueryParam: function(queryParams) {
    return setSingleQueryParam(this, queryParams);
  }
};

var AS_EQ = {
  _ctrlId:     "as_eq",
  _paramName:  "as_eq",
  getStoreValue: function() {
    return memStore.getValue(as_eq,"value");
  },
  setStoreValue: function(val) {
    memStore.setValue(as_eq, "value", val);
  },
  getFormValue: function() {
    return dijit.byId(this._ctrlId).getValue();
  },
  setFormValue: function(val) {
    return dijit.byId(this._ctrlId).setValue(val);
  },
  getQueryParam: function() {
    return "&" + this._paramName + "=" + this.getStoreValue();
  },
  setFromQueryParam: function(queryParams) {
    return setSingleQueryParam(this, queryParams);
  }
};

var NUM = {
  _ctrlId:     "num",
  _paramName:  "num",
  getStoreValue: function() {
    return memStore.getValue(num,"value");
  },
  setStoreValue: function(val) {
    memStore.setValue(num, "value", val);
  },
  getFormValue: function() {
    return dijit.byId(this._ctrlId).getValue();
  },
  setFormValue: function(val) {
    return dijit.byId(this._ctrlId).setValue(val);
  },
  getQueryParam: function() {
    return "&" + this._paramName + "=" + this.getStoreValue();
  },
  setFromQueryParam: function(queryParams) {
    return setSingleQueryParam(this, queryParams);
  }
};

var SORT = {
  _ctrlId:     "sort",
  _paramName:  "sort",
  getStoreValue: function() {
    return memStore.getValue(sort,"value");
  },
  setStoreValue: function(val) {
    memStore.setValue(sort, "value", val);
  },
  getFormValue: function() {
    return dijit.byId(this._ctrlId).getValue();
  },
  setFormValue: function(val) {
    //has colons which get URL encoded
    return dijit.byId(this._ctrlId).setValue(unescape(val));
  },
  getQueryParam: function() {
    return "&" + this._paramName + "=" + this.getStoreValue();
  },
  setFromQueryParam: function(queryParams) {
    return setSingleQueryParam(this, queryParams);
  }
};

var AdvancedForm = {
  //the list of dijit controls that make up the form
  controls: [AS_Q, AS_EPQ, AS_OQ, AS_EQ, NUM, SORT],
  //get the values of the form as a query string
  formToQuery: function() {
    var out = "";
    for(i = 0; i < this.controls.length; i++) {
      out += this.controls[i].getQueryParam();
    }
    return out;
  },
  //sets the visible and memory values of the form
  //based on a query string
  formFromQuery: function(queryString) {
    for(i = 0; i < this.controls.length; i++) {
      this.controls[i].setFromQueryParam(queryString);
    }
  },
  //puts the view in memory
  formViewToMemory: function() {
    for(i = 0; i < this.controls.length; i++) {
      this.controls[i].setStoreValue(this.controls[i].getFormValue());
    }
  },
  formViewFromMemory: function() {
    for(i = 0; i < this.controls.length; i++) {
      this.controls[i].setFormValue(this.controls[i].getStoreValue());
    }
  }
};

var BasicForm = {
  controls: Q,
  formToQuery: function() {
    return Q.getQueryParam();
  },
  formFromQuery: function(queryString) {
    Q.setFromQueryParam(queryString);
  },
  formViewToMemory: function() {
    Q.setStoreValue(Q.getFormValue());
  }
};

//initializes everything from hash if available
init = function() {
  var valid = _isHashValid();
  var t = "";

  if(valid) {
    _saveHashValues(); //save them for load results
    if(memStore.getValue(currForm, "value") == "basic") {
      BasicForm.formFromQuery(valid); //restore state from hash saved query
      switchSearchForms("basic");
    } else if (memStore.getValue(currForm, "value") == "advanced") {
      AdvancedForm.formFromQuery(valid);
      switchSearchForms("advanced");
    }

    t = memStore.getValue(currTab,"value");
        //move to tab
        dijit.byId(controlIds.RESULT_PANE_ID).selectChild(memStore.getValue(currTab, "value"));
        //display results and page to the exact page (in mem)
        _loadTabResults(t, _getQuery());

    //load the other tabs at start 0 i.e. on page 1, loop no-go xhr doesn't return here
    memStore.setValue(currStart, "value", "0");
    var q = _getQuery();
    switch(t) {
      case statics.ALL_RESULTS_ID:
        _loadTabResults(statics.PDF_RESULTS_ID, q);
        _loadTabResults(statics.HTML_RESULTS_ID, q);
        _loadTabResults(statics.XLS_RESULTS_ID, q);
        _loadTabResults(statics.CSV_RESULTS_ID, q);
        break;
      case statics.PDF_RESULTS_ID:
        _loadTabResults(statics.ALL_RESULTS_ID, q);
        _loadTabResults(statics.HTML_RESULTS_ID, q);
        _loadTabResults(statics.XLS_RESULTS_ID, q);
        _loadTabResults(statics.CSV_RESULTS_ID, q);
        break;
      case statics.HTML_RESULTS_ID:
        _loadTabResults(statics.ALL_RESULTS_ID, q);
        _loadTabResults(statics.PDF_RESULTS_ID, q);
        _loadTabResults(statics.XLS_RESULTS_ID, q);
        _loadTabResults(statics.CSV_RESULTS_ID, q);
        break;
      case statics.XLS_RESULTS_ID:
        _loadTabResults(statics.ALL_RESULTS_ID, q);
        _loadTabResults(statics.HTML_RESULTS_ID, q);
        _loadTabResults(statics.PDF_RESULTS_ID, q);
        _loadTabResults(statics.CSV_RESULTS_ID, q);
        break;
      case statics.CSV_RESULTS_ID:
        _loadTabResults(statics.ALL_RESULTS_ID, q);
        _loadTabResults(statics.HTML_RESULTS_ID, q);
        _loadTabResults(statics.XLS_RESULTS_ID, q);
        _loadTabResults(statics.PDF_RESULTS_ID, q);
        break;
    }
  } else {
    //if another site has send a get request with a search param run the basic search
    if(dijit.byId("q").getValue().length > 0) {
      search();
    }
  }
};

//lets you run a search, initiated by button click
search = function() {
  //remove any previous start data new search is done
  memStore.setValue(currStart, "value", "0");

  var query = _getQuery();
  for( i = 0; i < controlIds.TAB_IDS.length; i++) {
    _loadTabResults(controlIds.TAB_IDS[i], query);
  }

  _addHistoryHash();
};

//used when user is browsing through pages of results
browse = function(start) {
  memStore.setValue(currStart, "value", start);
  _loadTabResults(memStore.getValue(currTab,"value"), _getQuery());
  _addHistoryHash();
};

/**
 * Switches the form being displayed for the user to enter search criteria,
 * only if that form is not already selected.
 * @param searchForm The name of the search form you wish to display.
 */
switchSearchForms = function(searchForm) {
  dijit.byId(controlIds.SEARCH_STACK_CONTAINER_ID).selectChild(searchForm);

  if(searchForm == "advanced") {
    dijit.byId(controlIds.SEARCH_STACK_CONTAINER_ID).domNode.style.height = '280px';
    dijit.byId(controlIds.SEARCH_STACK_CONTAINER_ID).resize();
  } else if ( searchForm == "basic") {
    dijit.byId(controlIds.SEARCH_STACK_CONTAINER_ID).domNode.style.height = '163px';
    dijit.byId(controlIds.SEARCH_STACK_CONTAINER_ID).resize();
  }
};

/**
 * Clears any field content and sets drop-downs to their defaults
 * @param searchForm The name of the form you wish to reset
 */
clearForm = function(searchForm) {
  if(searchForm == "advanced") {
    dijit.byId(controlIds.AS_Q).setValue("");
    dijit.byId(controlIds.AS_EPQ).setValue("");
    dijit.byId(controlIds.AS_OQ).setValue("");
    dijit.byId(controlIds.AS_EQ).setValue("");
    dijit.byId(controlIds.NUM).setValue("10");
    dijit.byId(controlIds.SORT).setValue("");
  } else if ( searchForm == "basic" ) {
    dijit.byId(controlIds.Q).setValue("");
  }
};

//utility to build the query
_getQuery = function() {
  var q = "";
  var f = memStore.getValue(currForm, "value");
  var s = memStore.getValue(currStart, "value");
  if(f === "basic") {
    BasicForm.formViewToMemory();
    q = BasicForm.formToQuery();
  } else if (f === "advanced") {
    AdvancedForm.formViewToMemory();
    q = AdvancedForm.formToQuery();
  }
  q += _getLangParam() + _getStartParam();
  //remove the '&': breaks the google search
  if (q.indexOf("&") == 0) {
    q = q.substring(1, q.length);
  }
  return q;
};

_getStartParam = function() {
  return "&start=" + memStore.getValue(currStart, "value");
};

// check whether the hash contains what we need to restore a URL saved search
// @returns The hash if valid and false if not
_isHashValid = function() {
  var hash = window.location.hash;
  hash = hash.substring(1, hash.length); //remove the #

  var params = hash.split("&");
  var nvp = [];
  var i = 0;
  var requiredParamsCntr = 0;

  for( ; i < params.length; i++) {
    //name value pairs split
    nvp = params[i].split("=");
    name = nvp[0];
    value = nvp[1];
    for( y = 0; y < statics.REQUIRED_PARAMS.length; y++) {
      if (name === statics.REQUIRED_PARAMS[y]) {
        requiredParamsCntr++;
        break;
      }
    }
  }
  if(requiredParamsCntr === statics.REQUIRED_PARAMS.length - 1) {
    return hash;
  }
  return false; //not all parameters are available
};

//puts them in "memory"
_saveHashValues = function() {
  var hash = window.location.hash;
  hash = hash.substring(1, hash.length); //remove the #
  var params = hash.split("&");
  var nvp = [];
  var i = 0;

  for( ; i < params.length; i++) {
    //name value pairs split
    nvp = params[i].split("=");
    name = nvp[0];
    value = nvp[1];
    for( y = 0; y < statics.REQUIRED_PARAMS.length; y++) {
      if (name === statics.REQUIRED_PARAMS[y]) {
        switch(name) {
          case "tabId":
            memStore.setValue(currTab, "value", value);
            break;
          case "form":
            memStore.setValue(currForm, "value", value);
            break;
          case "start":
            memStore.setValue(currStart, "value", value);
            break;
        }
        break;
      }
    }
  }
};

//debug only
_storeStatus = function() {
  console.log("+----------------------------------------------------+");
  console.log("| currForm: " + memStore.getValue(currForm, "value"));
  console.log("| currTab: " + memStore.getValue(currTab, "value"));
  console.log("| currStart: " + memStore.getValue(currStart, "value"));
  console.log("+----------------------------------------------------+");
};

_loadTabResults = function(tabId, queryString) {
  //console.log("Running _loadTabResults ... queryString=" + queryString + " lang=" + lang + " tab=" + tabId);

  if(tabId == statics.ALL_RESULTS_ID
      || tabId == statics.PDF_RESULTS_ID
      || tabId == statics.HTML_RESULTS_ID
      || tabId == statics.XLS_RESULTS_ID
      || tabId == statics.CSV_RESULTS_ID) {

    var resultPane = dijit.byId(tabId);

    resultPane.href= _getResultsLocation(tabId) + lang + ".html?" + _encodeQueryParams(queryString);

    resultPane.refresh();  //display the results
  }
};

// FF encodes XHR requests in UTF-8, IE does not, this method does that for both
_encodeQueryParams = function(queryNameValuePairs) {
  var params = queryNameValuePairs.split("&");
  var nvp = [];
  var i = 0;
  var name = "";
  var value = "";
  var encoded = "";

  for( ; i < params.length; i++) {
    //name value pairs split
    nvp = params[i].split("=");
    name = nvp[0] ? nvp[0] : ""; //avoid undefined and nulls
    value = nvp[1] ? nvp[1] : "";
    //console.log("> > > " + i + " : " + name + " -> " + value);
    if (i == 0) {
      encoded += name + "=" + encodeURI(value);
    } else if ( value == "") {
      if(! _isNameOfControlId(name)) {
        //this is a case in which & is part of the value
        encoded += escape("&") + encodeURI(name);
      } else {
        encoded += "&" + name + "=" + encodeURI(value);
      }
    } else {
      encoded += "&" + name + "=" + encodeURI(value);
    }
  }
  //console.log(" encoded: " + encoded);
  return encoded;
};

_isNameOfControlId = function(name) {
  if(name == controlIds.Q) {
    return true;
  } else if (name == controlIds.AS_Q) {
    return true;
  } else if (name == controlIds.AS_EPQ) {
    return true;
  } else if (name == controlIds.AS_OQ) {
    return true;
  } else if (name == controlIds.AS_EQ) {
    return true;
  } else if (name == controlIds.NUM) {
    return true;
  } else if (name == controlIds.SORT) {
    return true;
  }
  return false;
};

//on tab change store the selected tab id in memory
dojo.subscribe(controlIds.RESULT_PANE_ID + "-selectChild", function(child) {
  memStore.setValue(currTab, "value", child.id);
  _addHistoryHash();
});

//on search form change store the form id in memory
dojo.subscribe(controlIds.SEARCH_STACK_CONTAINER_ID + "-selectChild", function(child) {
  memStore.setValue(currForm, "value", child.id);
  _addHistoryHash();
});

//save the query in the hash so Back button can recreate state
_addHistoryHash = function() {
  var f = memStore.getValue(currForm, "value");
  var t = memStore.getValue(currTab, "value");
  //_getQuery() add start skip it here
  window.location.hash = _getQuery()
                        + "&form=" + f
                        + "&tabId=" + t;
};

_getResultsLocation = function(tabId) {
  var loc;
  if(tabId == statics.ALL_RESULTS_ID) {
    loc = statics.ALL_RESULTS;
  } else if (tabId == statics.PDF_RESULTS_ID) {
    loc = statics.PDF_RESULTS;
  } else if (tabId == statics.HTML_RESULTS_ID) {
    loc = statics.HTML_RESULTS;
  } else if (tabId == statics.XLS_RESULTS_ID) {
    loc = statics.XLS_RESULTS;
  } else if (tabId == statics.CSV_RESULTS_ID) {
    loc = statics.CSV_RESULTS;
  }
  return loc;
};

_getLangParam = function() {
  switch(lang) {
    case "de":
      return "&lr=lang_de";
    case "en":
      return "&lr=lang_en";
  }
};

