if(typeof console === "undefined") {console = {log:function(val){/*alert(val);*/}};}
var storedResponse = new Array();

// loadSuggest()
//  Params:     strField        -   String ID of the field we're searching on.
//              strSearchURL    -   URL where the autosuggest is going to.
//              aOptions        -   Array of options.
//              strSearchURL    -   Search URL we're making the request to.
//  Returns:    Initializes the autosuggest on this field.
//  Revisions:  Created by Rob Terry, 10th September 2010.
function loadSuggest(strField, strSearchURL, aOptions, aSearchParams) {
  // Create a new instance of the autosuggest class and assign it to a variable.
  new AutoSuggest(strField, strSearchURL, aOptions, aSearchParams);
}


// AutoSuggest
//  Params:     strField - text fields ID.
//              strSearchURL    -   Search URL we're making the request to.
//              strResponseID   -   Response ID where the selected field will return to.
//              aOptions        -   Array of options.
//  Returns:    Creates the autosuggest listener etc:
//  Revisions:  Created by Rob Terry, 10th Sept 2010.
AutoSuggest = function(strField, strSearchURL, aOptions, aSearchParams) {
  this.strField = document.getElementById(strField);
  this.strResponseID = aOptions.strResponseID;
  this.strSearchURL = strSearchURL;
  this.aOptions = aOptions;
  this.requestCount = 0;
  
  // Set the defaults for the response div.
  document.getElementById(this.aOptions.strDivID).setAttribute('class','responseDiv');
  document.getElementById(this.aOptions.strDivID).setAttribute('className','responseDiv');
  document.getElementById(this.aOptions.strDivID).style.position = 'absolute';
  
  
  this.aSearchParams = aSearchParams;
  var p = this;
  this.strField.onkeyup = function(e) { return p.onKeyUp(e); };
  this.strField.onkeypress=function(e) { return p.onKeyPress(e); };
  this.strField.onblur = function(e) { return p.onBlur(e, p); };
  this.strField.onfocus = function(e) { return p.onFocus(e); };
  this.strField.setAttribute("autocomplete","off"); 
}

AutoSuggest.prototype.onKeyPress = function(ev) {
  var key = (window.event) ? window.event.keyCode : ev.keyCode;
  var TAB    = 9;
  var ESC    = 27;
  switch(key) {
//    case RETURN:
//        this.setHighlightedValue();
//        bubble = false;
//        break;
//     case TAB:
//         this.setHighlightedValue();
//         break;
    case ESC:
        this.clearSuggestions();
        break;
  }
}

AutoSuggest.prototype.onKeyUp = function(ev){
    var key      = (window.event) ? window.event.keyCode : ev.keyCode;
    var strSuggestion = this.strField.value;
    //console.log(key);
    var TAB      = 9;
    var SHIFT    = 16;
    var ARRUP    = 38;
    var ARRDN    = 40;
    var ARRLEFT  = 37;
    var ARRRIGHT = 39;
    var DEL      = 46;
    var BACKSPACE= 8;
    var bubble   = 1;
    switch(key) {
        case ARRUP:
        case ARRDN:
        case ARRLEFT:
        case ARRRIGHT:
            this.changeHighlight(key);
            bubble = false;
            break;
        case BACKSPACE:
        case DEL:
            this.clearSetFields();
            bubble = false;
            break;  
        case TAB:
        case SHIFT:
            break;                  
        default:
            this.getSuggestions(strSuggestion);
    }
    return bubble;
};

AutoSuggest.prototype.onBlur = function(e, s) {
  setTimeout(function() {s.hideSuggest(); },200);  
  this.showSuggest = false;
}

AutoSuggest.prototype.onFocus = function(e) {
  if(this.strField.value.length > 0) {
    this.getSuggestions(this.strField.value);
  }
}

// AutoSuggest
//  Params:     strSuggestion - text fields content.
//  Returns:    Sends the suggestion request to the feed munge.
//  Revisions:  Created by Rob Terry, 10th Sept 2010.
AutoSuggest.prototype.getSuggestions = function(strSuggestion) {
  if(strSuggestion == '') return;
  
  if(strSuggestion.length < this.aOptions.minChars) { 
    this.hideSuggest();
    return;
  }
  this.showSuggest = true;
  this.strSuggestionKey = this.formatSuggestionToKey(strSuggestion);
  if(typeof storedResponse[this.strSuggestionKey] == 'undefined') {
    if(typeof request != 'undefined') request.req.abort();
    request = new Ajax(this, strSuggestion, this.strSuggestionKey);
    
    // Build up the string of parameters
    strParams = '?like='+escape(strSuggestion)+"&";
    
    // Loop through the array of search params.
    for(var key in this.aSearchParams) {
      
      // If the search parameter string matches the regular expression, then
      var regExp = new RegExp("^document.(.*)","gi");
      if(this.aSearchParams[key].match(regExp)) {    
        // Evaluate the response before we display it.
        strParams += key+'='+escape(eval(this.aSearchParams[key]))+"&";
      } else if(key == 'limit') {
        strParams += key+'='+(parseInt(this.aSearchParams[key])+1)+"&";
      } else {
        // We've got hard coded values, just tag them onto the end.
        strParams += key+'='+escape(this.aSearchParams[key])+"&";
      }
    }
    // Take off the last character on the string ("&" unless somethings properly broken!).
    strParams = strParams.substr(0,strParams.length-1);
    
    // Actually perform the XML request.
    response = request.makeRequest(this.strSearchURL+strParams,'GET',this.onComplete,this.onError);
  } else {
    this.onComplete(storedResponse[this.strSuggestionKey], this);
  } 
}

AutoSuggest.prototype.changeHighlight = function(key) {
//  console.log('changeHighlight');
}


AutoSuggest.prototype.clearSetFields = function() {
 if(this.strField.value == '' || this.strField.value.length == 0) { this.hideSuggest(); return; }
 this.getSuggestions(this.strField.value);
}

AutoSuggest.prototype.clearSuggestions = function() {
//  console.log('clearSuggestions');
}

AutoSuggest.prototype.setHighlight = function(value, id) {
  div = document.getElementById(id);
  div.setAttribute('class','as_highlight_row');
  div.setAttribute('className','as_highlight_row');
}

AutoSuggest.prototype.clearHighlight = function(value, id) {
  div = document.getElementById(id);
  div.setAttribute('class','as_normal_row');
  div.setAttribute('className','as_normal_row');
}

AutoSuggest.prototype.setHighlightedValue = function(id, type) {
  
  selectedID = document.getElementById(id);
  if(selectedID != null) {
    selectedText = selectedID.getElementsByTagName('div')[0].innerHTML.replace("&amp;", "&");
    selectedValue = selectedID.getElementsByTagName('input')[0].value;
    
    
    if(typeof this.aOptions.returnField == 'object' && (this.aOptions.returnField instanceof Object)) {
      for(var temp in this.aOptions.returnField) {
        document.getElementById(this.aOptions.returnField[temp]).value = '';
      }
      
      returnField = this.aOptions.returnField[type];
    } else {
      returnField = this.aOptions.returnField;
    }
    // Here's where we pass back to the original selection div.
    document.getElementById(returnField).value = selectedValue;
    this.strField.value = selectedText;
  }
  
  this.hideSuggest();
  
  if(typeof this.aOptions.postSelectJS != 'undefined') {
    eval(this.aOptions.postSelectJS);
  }
}

// AutoSuggest.onComplete
//  Params:     strSuggestion - text fields content.
//  Returns:    Sends the suggestion request to the feed munge.
//  Revisions:  Created by Rob Terry, 10th Sept 2010.
AutoSuggest.prototype.onComplete = function(hResponse, AS) {
  if(AS.showSuggest == false) { return; }
  
  /*
        This function is the start of a successful ajax request for the autosuggest.
              */
  
  // make a tmp string of the key that has been created for the suggestion.
  tmp = this.strSuggestionKey;
  
  if(typeof storedResponse != 'undefined') {
    // In short, here I set the response into a javascript array, if it doesn't already exist.
    if(typeof storedResponse[tmp] == 'undefined') { storedResponse[tmp] = hResponse.responseXML; }
    
    // Right now we don't do anything about updating the response. Once it's in the javascript "cache", i don't check to see how correct it is.
    // we may want to consider changing that, here's where we can do this.
  }
  
  // Grab the XML response from the stored variable.
  oDom = storedResponse[tmp];
  
  if(typeof oDom == 'object' && oDom.documentElement.nodeName != 'parsererror' && (this.strSuggestion == AS.strField.value || typeof this.strSuggestion == 'undefined')) {
    // Clear out the last suggest's response (not very tidy right now, we may want to do a 'removeChild' etc (may even call another function here.
    document.getElementById(AS.aOptions.strDivID).innerHTML = "";
    // The first tag we expect is a response tag. So grab that one.
    oDom = oDom.getElementsByTagName('response').item(0);
    // If this is the first time we've seen the query, we may be showing a debug element.
    // Remove that here.
    //oDebug = oDom.getElementsByTagName('debug');
    //if(oDebug.length > 0) { debug = oDom.removeChild(oDebug.item(0)); }
    
    // Loop through the response children and see if we have anything worth playing with.
    if(oDom.hasChildNodes()) {
      // Set the children of the current nodelist.
      children = oDom.childNodes;
      
      // Loop through each one of the children.
      for(i = 0;i < children.length; i++) {
        // If it's nodetype is 1 (an element) and it has children, then...
        if(children[i].nodeType == 1 && children[i].hasChildNodes() && children[i].nodeName != 'debug') { 
          // Here we'll be displaying the 
          parentDiv = AS.createNewResponseColumn(children[i].nodeName);
          /// RIGHT... we're only here if we're looking at the correct node and it has children! (in other words, only if we have search results to display!)
          AS.displaySuggestions(children[i].nodeName,children[i], parentDiv, AS.aSearchParams.limit);
          
        // If we're looking at a nodetype of 1, then we must have other options?
        } else if(children[i].nodeType == 1 && children[i].nodeName != 'debug') {
          parentDiv = AS.createNewResponseColumn(children[i].nodeName);
          AS.displayNoMatches(parentDiv);
        }
      }
    }
    
    AS.sortPositioningForResponse();
  }
}


// AutoSuggest.displaySuggestions
//  Params:     strType     -   String of the type of suggestion to display.
//              oNodes      -   XML nodes of the children of the type we're displaying suggestions for.
//              parentDiv   -   element that the results will be put into.
//  Returns:    Sends the suggestion request to the feed munge.
//  Revisions:  Created by Rob Terry, 10th Sept 2010.
AutoSuggest.prototype.displaySuggestions = function(strType,oNodes, parentDiv, limit) {
  suggestions = oNodes.getElementsByTagName('suggestions').item(0);
  var i = 0;
  if(suggestions.hasChildNodes()) {
    childSuggestions = suggestions.childNodes;
    for(j = 0;j < childSuggestions.length; j++) {
      if(childSuggestions[j].nodeType == 1 && childSuggestions[j].hasChildNodes()) { 
        i++;
        
        if(typeof this.aOptions.selectionValue != 'undefined') { 
          if(typeof this.aOptions.selectionValue == 'object' && (this.aOptions.selectionValue instanceof Object)) {
            childValue = this.aOptions.selectionValue[strType];
          } else {
            childValue = this.aOptions.selectionValue;
          }
        } else {
          childValue = 'id';
        }
        
        iChild = childSuggestions[j].getElementsByTagName(childValue)[0].textContent;
        if(iChild == '' && this.aOptions.skipEmpty == 1) continue;
        if(typeof iChild == 'undefined') { iChild = childSuggestions[j].getElementsByTagName('id')[0].text; }
        
        strName = childSuggestions[j].getElementsByTagName(strType)[0].textContent;
        if(typeof strName == 'undefined') { strName = childSuggestions[j].getElementsByTagName(strType)[0].text; }
        
        strHidden = strName;
        
        
        
        if(typeof this.aOptions.selectionElement != 'undefined') { 
          if(typeof this.aOptions.selectionElement == 'object' && (this.aOptions.selectionElement instanceof Object)) {
            selection = this.aOptions.selectionElement[strType];
          } else {
            selection = this.aOptions.selectionElement;
          }
          
          
          if(childSuggestions[j].getElementsByTagName(selection)[0]) {  
            
            strHidden = childSuggestions[j].getElementsByTagName(selection)[0].textContent;
            if(typeof strHidden == 'undefined') { strHidden = childSuggestions[j].getElementsByTagName(selection)[0].text; }
            
            if(strHidden == '' || typeof strHidden == 'undefined') {
              strHidden = childSuggestions[j].getElementsByTagName(strType)[0].textContent;
              if(typeof strHidden == 'undefined') { strHidden = childSuggestions[j].getElementsByTagName(strType)[0].text; }
            }
          }
        }
        if(i <= limit) {
          this.createNewSuggestion(iChild, strType,strName,strHidden,parentDiv);        
        } else {
          this.showTooManyResults(parentDiv);
        } 
      }
    }
  }
}

// AutoSuggest.displayNoMatches
//  Params:     parentDiv   -   Div container for the parent of the no-matches.
//  Returns:    Sends back a column of 'no matches'.
//  Revisions:  Created by Rob Terry, 21st September 2010.
AutoSuggest.prototype.displayNoMatches = function(parentDiv) {
  childSuggestion = document.createElement('div');
  childSuggestion.setAttribute('class','as_normal_row');
  childSuggestion.setAttribute('className','as_normal_row');
  childText = document.createTextNode('Sorry no matches...');
  childSuggestion.appendChild(childText);
  parentDiv.appendChild(childSuggestion);  
}

// AutoSuggest.showTooManyResults
//  Params:     parentDiv   -   Div container for the parent of the no-matches.
//  Returns:    Sends back a column of 'no matches'.
//  Revisions:  Created by Rob Terry, 21st September 2010.
AutoSuggest.prototype.showTooManyResults = function(parentDiv) {
  childSuggestion = document.createElement('div');
  childSuggestion.setAttribute('class','as_refine_row');
  childSuggestion.setAttribute('className','as_refine_row');
  childText = document.createTextNode('Keep typing to refine results');
  childSuggestion.appendChild(childText);
  parentDiv.appendChild(childSuggestion);  
}


// AutoSuggest.onError
//  Params:     stuff   -   Error handling function.
//  Revisions:  Created by Rob Terry, 10th Sept 2010.
AutoSuggest.prototype.onError = function(stuff) {
//  console.log('onError');
//  console.log(stuff);
}


// AutoSuggest.formatSuggestionToKey
//  Params:     strSuggestion       - text fields content.
//  Returns:    strSuggestionKey    - key for the response array.
//  Revisions:  Created by Rob Terry, 10th Sept 2010.
AutoSuggest.prototype.formatSuggestionToKey = function(strSuggestion) {
  var strSuggestionKey = '';
  
  // Addition for allowing a prefix to be supplied for the given suggest.
  if(typeof this.aOptions.cachePrefix != 'undefined') { 
    var regExp = new RegExp("^document.get(.*)","gi");
    if(this.aOptions.cachePrefix.match(regExp)) {    
      strSuggestionKey = eval(this.aOptions.cachePrefix)+"_";
    } else {
      strSuggestionKey = this.aOptions.cachePrefix+"_";
    }
  }
  
  // Loop through the length of the string we're searching for and add the charcode to the key.
  for(i = 0;i<strSuggestion.length;i++) {
    tmpKey = strSuggestion.charCodeAt(i);
    if(tmpKey < 10) tmpKey = "00"+tmpKey;
    if(tmpKey < 100) tmpKey = "0"+tmpKey;
    strSuggestionKey += tmpKey;
  }
  
  // Pass back the suggestion key.
  return strSuggestionKey;
}


// AutoSuggest.createNewResponseColumn
//  Params:     strColumn  -   String of the title to display to the column.
//  Returns:    parentDiv       -   Element into which the children will be placed.
//  Revisions:  Created by Rob Terry, 14th August 2010.
AutoSuggest.prototype.createNewResponseColumn = function(strColumn) {
  parentDiv = document.createElement('div');
  parentDiv.setAttribute("id",strColumn);
  parentDiv.setAttribute("name",'as_col');
  parentDiv.setAttribute("class",'as_col');
  parentDiv.setAttribute("className",'as_col');
  parentDiv.style.width = "180px";
  
  firstDiv = document.createElement('h4');
  strText = strColumn;
  if(typeof this.aOptions.titles != 'undefined' && typeof this.aOptions.titles[strColumn] != 'undefined' ) {
    strText = this.aOptions.titles[strColumn];
  }
  firstDiv.innerHTML = strText;
  firstDiv.setAttribute("class",'as_col_header');
  firstDiv.setAttribute("className",'as_col_header');
  
  
  parentDiv.appendChild(firstDiv);
  document.getElementById(this.aOptions.strDivID).appendChild(parentDiv);
  return parentDiv;
}

// AutoSuggest.createNewSuggestion 
//  Params:     iChild      -   ID of the child we're possibly going to be addingto.
//              strType     -   This is the type string.
//              strName     -   String to display for the suggestion.
//              parentDiv   -   handle of the div that we're adding content to.
//  Returns:
//  Revisions:  Created by Rob Terry, 14th August 2010.
AutoSuggest.prototype.createNewSuggestion = function(iChild,strType,strName,strHidden,parentDiv) {
  
  childSuggestion = document.createElement('div');
  childSuggestion.setAttribute('class','as_normal_row');
  childSuggestion.setAttribute('className','as_normal_row');
  childSuggestion.setAttribute('id', 'as_'+strType+'_'+iChild);
   
    
  childID = document.createElement('input');
  childID.setAttribute('type','hidden');
  childID.setAttribute('id', 'child_'+iChild);
  childID.setAttribute('value',iChild);
  childSuggestion.appendChild(childID);
  
  childTextHidden = document.createElement('div');
  childTextHidden.style.display = 'none';
  childText = document.createTextNode(strHidden);
  childTextHidden.appendChild(childText);
  childSuggestion.appendChild(childTextHidden);
  
  childSuggestion.innerHTML += this.higlightMatchedString(strName);
  
  var p = this;
  overHandle = function(e) { p.setHighlight(e, this.id); }
  outHandle = function(e) { p.clearHighlight(e, this.id); }
  clickHandle = function(e) { p.setHighlightedValue(this.id, strType); }
  
  childSuggestion.onmouseover = overHandle;
  childSuggestion.onmouseout = outHandle;
  childSuggestion.onclick = clickHandle;
  
  
  parentDiv.appendChild(childSuggestion);
}

AutoSuggest.prototype.higlightMatchedString = function(strName) {
  strSearched = this.strField.value;
  var parts = strSearched.split(' ');
  for (var part in parts) {
      var word = parts[part].charAt(0).toUpperCase() + parts[part].substr(1);
      var regExp = new RegExp("(^|^.+\\s)("+word+")([^>]*)(\\s.+|$)","gi");
      if(word != '') strName = strName.replace(regExp,"$1<em><strong>$2</strong></em>$3$4");
  }
  
  return strName;
}

AutoSuggest.prototype.hideSuggest = function() {
  this.showSuggest = false;
  div = document.getElementById(this.aOptions.strDivID);
  div.style.visibility = 'hidden';
  suggest = document.getElementById(this.aOptions.strDivID);
  if(suggest.hasChildNodes())  { while(suggest.childNodes.length >= 1) { suggest.removeChild( suggest.firstChild ); } }
}


AutoSuggest.prototype.sortPositioningForResponse = function() {  
  div = document.getElementById(this.aOptions.strDivID);
  
  div.style.visibility = 'visible';
  
  input = this.strField;
  
  var pos = this.getPos(input);
  
  arrow = document.createElement('div');
  arrow.setAttribute('class','as_arrow');
  arrow.setAttribute('className','as_arrow');
  arrow.style.left = (div.offsetWidth - 80)+"px";
  div.appendChild(arrow);
  
  //div.style.left    = pos.x + "px";
  div.style.top   = (pos.y + input.offsetHeight) + "px";
  if(navigator.userAgent.match('MSIE 7.0')) {
    div.style.top = (pos.y + input.offsetHeight+8) + "px";
  }
  
//  if(div.offsetWidth < input.offsetWidth) div.style.width = input.offsetWidth + "px";
  
  div.style.left  = (pos.x+input.offsetWidth-div.offsetWidth) + "px";
  
  divHeight = div.offsetHeight;
  
  cols = div.childNodes;
  for(i = 0; i < cols.length; i++) {
    if(cols[i].nodeType == 1 && (cols[i].getAttribute('class') == 'as_col' || cols[i].getAttribute('className') == 'as_col')) {
      cols[i].style.height = divHeight+"px";
    }
  }
  
  var p = this;
  clickHandle = function(e) { p.hideSuggest(); }
  
  anchor = document.createElement('a');
  anchor.innerHTML = 'close';
  anchor.href = '#';
  anchor.onclick = clickHandle;
  anchor.setAttribute('class', 'as_close');
  anchor.setAttribute('className', 'as_close');
  div.appendChild(anchor);
  anchor.style.top = "2px";
  anchor.style.left = ((div.offsetWidth - 40))+"px";
}






/***
DOM stuff
***/
AutoSuggest.prototype.d_gE = function(e){
    var t=typeof(e);
    if /**/ (t=="undefined") return 0;
    else if (t=="string"){
        var re = d_gE( e );
        if(!re)return 0;
        else if(typeof(re.appendChild) != "undefined" ) return re;
        else return 0;
    }
    else if(typeof(e.appendChild) != "undefined") return e;
    else /*------------------------------------*/ return 0;
};
AutoSuggest.prototype.getPos = function(e){
    var e = this.d_gE(e);
    var obj = e;
    var curleft = 0;
    if (obj.offsetParent){
        while (obj.offsetParent){
            curleft += obj.offsetLeft;
            obj = obj.offsetParent;
        }
    }
    else if (obj.x) curleft += obj.x;
    var obj = e;
    var curtop = 0;
    if (obj.offsetParent){
        while (obj.offsetParent){
            curtop += obj.offsetTop;
            obj = obj.offsetParent;
        }
    }
    else if (obj.y) curtop += obj.y;
    return {x:curleft, y:curtop};
};


/***
  Ajax response class.
***/
Ajax = function (AutoSuggest, strSuggestion, strSuggestionKey){
    this.req = {};
    this.isIE = false;
    this.AutoSuggest = AutoSuggest;
    this.strSuggestion = strSuggestion;
    this.strSuggestionKey = strSuggestionKey;
};


Ajax.prototype.makeRequest = function (url, meth, onComp, onErr){
    // url is currently provided as relative to the document root.
    // As ie can only handle two concurrent ajax requests per domain we are going to put differing domains on the front of this url to trick it.
    // Obviously the domains have to map to the right place, and they will have to be subdomains of where we are to avoid XSS security restrictions.
    if (0 && window.location.hostname != 'townsites.localhost') {
        var subdomain = 'http://ajax' + (this.AutoSuggest.requestCount++) % 10 + '.' + window.location.hostname;
        var fullUrl = subdomain + url;
    } else {
        var fullUrl = url;
    }
    if (meth != "POST") meth = "GET";
    this.onComplete = onComp;
    this.onError = onErr;
    var pointer = this;
    if (window.XMLHttpRequest){
        this.req = new XMLHttpRequest();
        this.req.onreadystatechange = function () { pointer.processReqChange() };
        this.req.open(meth, fullUrl, true); //
        this.req.send(null);
    }
    else if (window.ActiveXObject) {
        this.req = new ActiveXObject("Microsoft.XMLHTTP");
        if (this.req){
            this.req.onreadystatechange = function () { pointer.processReqChange() };
            this.req.open(meth, fullUrl, true);
            this.req.send();
        }
    }
};

Ajax.prototype.processReqChange = function(){
  if (this.req.readyState == 4) {
        if (this.req.status == 200) this.onComplete( this.req, this.AutoSuggest );
       else /*------------------*/ this.onError( this.req.status );
    }
};
