/*
 *
 *  Ajax Autocomplete for Prototype, version 1.0.3
 *  (c) 2008 Tomas Kirda
 *
 *  Ajax Autocomplete for Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the web site: http://www.devbridge.com/projects/autocomplete/
 *
 */
//var start = false;
//var diff = false;//@remove

var Autocomplete = function(el, options){
  this.el = $(el);
  this.id = this.el.identify();
  this.el.setAttribute('autocomplete','off');
  this.suggestions = [];
  this.data = [];
  this.county_id = [];
  this.listingCount = [];
  this.badQueries = [];
  this.selectedIndex = -1;
  this.currentValue = this.el.value;
  this.intervalId = 0;
  this.cachedResponse = [];
  this.instanceId = null;
  this.onChangeInterval = null;
  this.ignoreValueChange = false;
  this.serviceUrl = options.serviceUrl;
  this.stateArr = [];
  this.stateArr[1] = 'Alabama';
  this.stateArr[2] = 'Alaska';
  this.stateArr[4] = 'Arizona';
  this.stateArr[5] = 'Arkansas';
  this.stateArr[6] = 'California';
  this.stateArr[8] = 'Colorado';
  this.stateArr[9] = 'Connecticut';
  this.stateArr[10] = 'Delaware';
  this.stateArr[11] = 'District of Columbia';
  this.stateArr[12] = 'Florida';
  this.stateArr[13] = 'Georgia';
  this.stateArr[15] = 'Hawaii';
  this.stateArr[16] = 'Idaho';
  this.stateArr[17] = 'Illinois';
  this.stateArr[18] = 'Indiana';
  this.stateArr[19] = 'Iowa';
  this.stateArr[20] = 'Kansas';
  this.stateArr[21] = 'Kentucky';
  this.stateArr[22] = 'Louisiana';
  this.stateArr[23] = 'Maine';
  this.stateArr[24] = 'Maryland';
  this.stateArr[25] = 'Massachusetts';
  this.stateArr[26] = 'Michigan';
  this.stateArr[27] = 'Minnesota';
  this.stateArr[28] = 'Mississippi';
  this.stateArr[29] = 'Missouri';
  this.stateArr[30] = 'Montana';
  this.stateArr[31] = 'Nebraska';
  this.stateArr[32] = 'Nevada';
  this.stateArr[33] = 'New Hampshire';
  this.stateArr[34] = 'New Jersey';
  this.stateArr[35] = 'New Mexico';
  this.stateArr[36] = 'New York';
  this.stateArr[37] = 'North Carolina';
  this.stateArr[38] = 'North Dakota';
  this.stateArr[39] = 'Ohio';
  this.stateArr[40] = 'Oklahoma';
  this.stateArr[41] = 'Oregon';
  this.stateArr[42] = 'Pennsylvania';
  this.stateArr[44] = 'Rhode Island';
  this.stateArr[45] = 'South Carolina';
  this.stateArr[46] = 'South Dakota';
  this.stateArr[47] = 'Tennessee';
  this.stateArr[48] = 'Texas';
  this.stateArr[49] = 'Utah';
  this.stateArr[50] = 'Vermont';
  this.stateArr[51] = 'Virginia';
  this.stateArr[53] = 'Washington';
  this.stateArr[54] = 'West Virginia';
  this.stateArr[55] = 'Wisconsin';
  this.stateArr[56] = 'Wyoming';
  this.options = {
    autoSubmit:false,
    minChars:1,
    maxHeight:300,
    deferRequestBy:0,
    width:0,
    container:null
  };
  if(options){ Object.extend(this.options, options); }
  if(Autocomplete.isDomLoaded){
    this.initialize();
  }else{
    Event.observe(document, 'dom:loaded', this.initialize.bind(this), false);
  }
};

Autocomplete.instances = [];
Autocomplete.isDomLoaded = false;

Autocomplete.getInstance = function(id){
  var instances = Autocomplete.instances;
  var i = instances.length;
  while(i--){ if(instances[i].id === id){ return instances[i]; }}
};

Autocomplete.highlight = function(value, re){
  return value.replace(re, function(match){ return '<strong>' + match + '<\/strong>' });
};

Autocomplete.prototype = {

  killerFn: null,

  initialize: function() {
    var me = this;
    this.killerFn = function(e) {
      if (!$(Event.element(e)).up('.autocomplete')) {
        me.killSuggestions();
        me.disableKillerFn();
      }
    } .bindAsEventListener(this);

    if (!this.options.width) { this.options.width = this.el.getWidth(); }

    var div = new Element('div', { style: 'position:absolute;z-index:999;' });
    div.update('<div class="autocomplete-w1"><div class="autocomplete-w2"><div class="autocomplete" id="Autocomplete_' + this.id + '" style="display:none; width:' + this.options.width + 'px;"></div></div></div>');

    this.options.container = $(this.options.container);
    if (this.options.container) {
      this.options.container.appendChild(div);
      this.fixPosition = function() { };
    } else {
      document.body.appendChild(div);
    }

    this.mainContainerId = div.identify();
    this.container = $('Autocomplete_' + this.id);
    this.fixPosition();
    
    Event.observe(this.el, window.opera ? 'keypress':'keydown', this.onKeyPress.bind(this));
    Event.observe(this.el, 'keyup', this.onKeyUp.bind(this));
    Event.observe(this.el, 'blur', this.enableKillerFn.bind(this));
    Event.observe(this.el, 'focus', this.fixPosition.bind(this));
    this.container.setStyle({ maxHeight: this.options.maxHeight + 'px' });
    this.instanceId = Autocomplete.instances.push(this) - 1;
  },

  fixPosition: function() {
    var offset = this.el.cumulativeOffset();
    $(this.mainContainerId).setStyle({ top: (offset.top + this.el.getHeight()) + 'px', left: offset.left + 'px' });
  },

  enableKillerFn: function() {
    Event.observe(document.body, 'click', this.killerFn);
  },

  disableKillerFn: function() {
    Event.stopObserving(document.body, 'click', this.killerFn);
  },

  killSuggestions: function() {
    this.stopKillSuggestions();
    this.intervalId = window.setInterval(function() { this.hide(); this.stopKillSuggestions(); } .bind(this), 300);
  },

  stopKillSuggestions: function() {
    window.clearInterval(this.intervalId);
  },

  onKeyPress: function(e) {
    //we have to reset the quickSearchField in case the user types something new and presses enter real fast...if this happens
    //then the old quickSearchField value will still be stuck in there which is wrong
    if ($('quickSearchField') && e.keyCode != 13) {
        $('quickSearchField').value = '';
    }
    
    if (!this.enabled /*|| e.keyCode == 13*/ || e.keyCode == 27) { return; }
    // return will exit the function
    // and event will not fire
    switch (e.keyCode) {
      case Event.KEY_ESC:
        this.el.value = this.currentValue;
        this.hide();
        break;
      case Event.KEY_TAB:
      case Event.KEY_RETURN:
        if (this.selectedIndex === -1) {
          this.hide();
          return;
        }
        this.select(this.selectedIndex);
        if (e.keyCode === Event.KEY_TAB) { return; }
        break;
      case Event.KEY_UP:
        this.moveUp();
        break;
      case Event.KEY_DOWN:
        this.moveDown();
        break;
      default:
        return;
    }
    this.currentKeyCode = e.keyCode;
    Event.stop(e);
  },

  onKeyUp: function(e) {
    //let the user know we are finding suggestions
	if ((e.keyCode < 36 || e.keyCode > 40) && e.keyCode != 13 && e.keyCode != 27) {
		//arrow keys: if they are moving down or up through the results then don't display this..or if they hit enter or esc
	    this.suggestions = ["Finding Suggestions..."];
	    this.data = [""];
	    this.currentValue = this.el.value;
    }
    
	if (e.keyCode == 27 || e.keyCode == 13) {//escape or enter
		this.hide();
		this.killSuggestions();
		Event.stop(e);
		return;
	}
	
    if (this.currentValue !== '' && this.currentValue.length > this.options.minChars) {
    	this.suggest();
    }
    
    switch (e.keyCode) {
      case Event.KEY_UP:
      case Event.KEY_DOWN:
      case 27:	
        return;
    }
    clearInterval(this.onChangeInterval);
    
    //Jimmy commented the if statement out below in order to get the "Finding Suggestions" stuff to work
    //if (this.currentValue !== this.el.value) {
      if (this.options.deferRequestBy > 0) {
        // Defer lookup in case when value changes very quickly:
        this.onChangeInterval = setInterval((function() {
          this.onValueChange();
        }).bind(this), this.options.deferRequestBy);
      } else {
        this.onValueChange();
      }
    //}
  },

  onValueChange: function() {
    clearInterval(this.onChangeInterval);
    this.currentValue = this.el.value;
    this.selectedIndex = -1;
    if (this.ignoreValueChange) {
      this.ignoreValueChange = false;
      return;
    }
    if (this.currentValue === '' || this.currentValue.length < this.options.minChars) {
      this.hide();
    } else {
      this.getSuggestions();
    }
  },

  getSuggestions: function() {
  	//start = (new Date).getTime();//@remove 
	var cr = this.cachedResponse[this.currentValue];
    if (cr && Object.isArray(cr.suggestions)) {
      this.suggestions = cr.suggestions;
      this.data = cr.data;
      this.state = cr.state;
      this.county_id = cr.county_id;
      this.listingCount = cr.count;
      this.suggest();
    } else if (!this.isBadQuery(this.currentValue)) {
      //abort the previous request since we don't care about it anymore because they continued typing
      if (this.prevAjaxRequest) this.prevAjaxRequest.abort();
      this.prevAjaxRequest = new Ajax.Request(this.serviceUrl, {
        parameters: { qsIntelligent: this.currentValue },
        onComplete: this.processResponse.bind(this),
        method: 'get'
      });
    }
  },

  isBadQuery: function(q) {
    var i = this.badQueries.length;
    while (i--) {
      if (q.indexOf(this.badQueries[i]) === 0) { return true; }
    }
    return false;
  },

  hide: function() {
    this.enabled = false;
    this.selectedIndex = -1;
    this.container.hide();
  },

  suggest: function() {
    if (this.suggestions.length === 0) {
      this.hide();
      return;
    }
    
    var content = [];    
    var re = new RegExp('\\b' + this.currentValue.match(/\w+/g).join('|\\b'), 'gi');
    var prevState = 0;
    var j;
    this.suggestions.each(function(value, i) {
      j = i;
    	
      //determine whether or not we should show (add) a state header	
      if (this.state && this.stateArr[this.state[i]] && this.state[i] != prevState) {
    	  content.push('<div class="autocompleterState">', this.stateArr[this.state[i]], '</div>');
    	  //if they are "keying down" through the list and they get to a state, then we want to 
    	  //automatically send them to the next item in the list
    	  //if (this.selectedIndex == i && this.currentKeyCode == 40) this.selectedIndex++;
    	  
    	  //if they are "keying up" through the list and they get to a state, then we want to 
    	  //automatically send them to the previous item in the list
    	  //if (this.selectedIndex == i && this.currentKeyCode == 38) this.selectedIndex--;
      }
      content.push((this.selectedIndex === i ? '<div id="selection'+i+'" class="selected"' : '<div id="selection'+i+'"'), ((value == 'Finding Suggestions...')?(''):(' style="padding-left: 20px;"'))+' title="', value, '" onclick="Autocomplete.instances[', this.instanceId, '].select(', j, ');" onmouseover="Autocomplete.instances[', this.instanceId, '].activate(', j, ');" onmouseout="this.className=\'\';">', Autocomplete.highlight(value, re), '</div>');
      
      if (this.state) {
      	prevState = (this.state[i]) ? this.state[i] : 0;
      }
    } .bind(this));
    this.enabled = true;
    this.container.update(content.join('')).show();
  },

  processResponse: function(xhr) {
    var response;
    try {
      response = xhr.responseText.evalJSON();
      
      if (!Object.isArray(response.data)) { response.data = []; }
    } catch (err) { return; }
    this.suggestions = response.suggestions;
    this.data = response.data;
    this.state = response.state;
    this.county_id = response.county_id;
    this.listingCount = response.count;
    this.cachedResponse[response.query] = response;
    if (response.suggestions.length === 0) { this.badQueries.push(response.query); }
    if (response.query === this.currentValue) { this.suggest(); }

    //at this point we have the results ordered by listing count...and we want to autofill what they are typing with the first
    //suggestion (which has the highest listing count)
    if (this.data[0].length > 0 && this.data[0].toLowerCase().indexOf(this.el.value.toLowerCase()) != -1) {
        //since we are autofilling their search phrase with the top result lets go ahead and "highlight" the top result
        //which will give the user a better indication of what is going on
        $('selection0').className = 'selected';
        
        var inputLength = this.el.value.length;//length of the string the user is typing in
        var restOfSuggestion = this.data[0].substr(inputLength);
        var restOfSuggestionLen = restOfSuggestion.length;
        
        this.el.setValue(this.el.value.substr(0, inputLength) + restOfSuggestion);
        
        if (this.el.setSelectionRange) {
           this.el.setSelectionRange(inputLength, (restOfSuggestionLen + inputLength));
        } else {  // Internet Explorer before version 9
            var inputRange = this.el.createTextRange();
            inputRange.moveStart("character", inputLength);
            inputRange.collapse();
            inputRange.moveEnd("character", restOfSuggestionLen);
            inputRange.select();
        }
        
        var searchType;
        var commaRegexForAddress = /^(.*)[,](.*)[,](.*)$/;
        
        if (this.suggestions[0].indexOf('mls id') != -1) {
            searchType = 'mlsid';
        } else if (this.suggestions[0].indexOf('area') != -1) {
            searchType = 'area';
        } else if (this.suggestions[0].indexOf('school district') != -1) {
            searchType = 'school_district';
        } else if (this.suggestions[0].indexOf('county') != -1) {
            searchType = 'county';
        } else if (this.suggestions[0].indexOf(qsSubLabel) != -1) {
            searchType = 'subdivision';
        } else if (this.suggestions[0].indexOf('post office') != -1) {
            searchType = 'postoffice';
        } else if (this.suggestions[0].indexOf('zip code') != -1) {
            searchType = 'zip_code';
        } else if (this.suggestions[0].indexOf('state') != -1) {
            searchType = 'state';
        } else if (commaRegexForAddress.test(this.suggestions[0])) {
            //this is an address search, so create a field with the mls id...this will enable quicksearchprocess to do a search
            //by mls id, which is faster than an address search
            var parentForm = this.el.form;
            $(parentForm).insert('<input type="hidden" name="quickSearchMls" id="quickSearchMls" value="'+this.data[0]+'">');
            this.addressSearch = true;//we want to keep the address in the search box instead of showing this.data[i] (the mls id) like we usually do
            searchType = "addressByMlsId";
        } else {
            //must be a city
            searchType = 'city';
        }
        
        if ($('qsstate')) {
            $('qsstate').value = this.state[0];
        } else {//if design forgot to include a qsstate in the form lets add one
            var parentForm = this.el.form;
            $(parentForm).insert('<input type="hidden" name="qsstate" id="qsstate" value="'+this.state[0]+'">');
        }
        
        if (this.data[0].indexOf('street:') != -1) {
            searchType = 'address';
        } 
        
        if ($('quickSearchField')) {
            $('quickSearchField').value = searchType;
        } else {
            var parentForm = this.el.form;
            
            //this.el.form.insert({bottom:'<input type="hidden" name="quickSearchField" id="quickSearchField" value="'+searchType+'">'});
            $(parentForm).insert('<input type="hidden" name="quickSearchField" id="quickSearchField" value="'+searchType+'">');
        }
    }
  },

  activate: function(index) {
	  //please take note of the className != autocompleterState in this function, we do this
	  //because we never want to change the style of the state text
    var divs = this.container.childNodes;
    var activeItem;
    
    // Clear previous selection
    if (this.selectedIndex !== -1 && divs.length > this.selectedIndex && divs[this.selectedIndex].className != 'autocompleterState') {
      divs[this.selectedIndex].className = '';
    }
    this.selectedIndex = index;
    if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
      //activeItem = divs[this.selectedIndex];
    	activeItem = $('selection'+this.selectedIndex);
      if (activeItem.className != 'autocompleterState') {
      	//if it is a state then we don't want to mark it as selected
      	activeItem.className = 'selected';
      } 
    }
    return activeItem;
  },

  deactivate: function(div, index) {
    div.className = '';
    if (this.selectedIndex === index) { this.selectedIndex = -1; }
  },

  select: function(i) {
	//var selectedValue = this.suggestions[i];
    var selectedValue = this.data[i];
    
    //the user is selecting a value here, so lets figure out what that is (city, subdivision, school, etc.)
    //and create an <input> tag for that
    var searchType = '';
    //var commaRegex = new RegExp('/^(.*)[,](.*)[,](.*)$/');
    var commaRegexForAddress = /^(.*)[,](.*)[,](.*)$/;
    
    if (this.suggestions[i].indexOf('mls id') != -1) {
        searchType = 'mlsid';
    } else if (this.suggestions[i].indexOf('area') != -1) {
    	searchType = 'area';
    } else if (this.suggestions[i].indexOf('school district') != -1) {
    	searchType = 'school_district';
    } else if (this.suggestions[i].indexOf('county') != -1) {
    	searchType = 'county';
    } else if (this.suggestions[i].indexOf(qsSubLabel) != -1) {
    	searchType = 'subdivision';
    } else if (this.suggestions[i].indexOf('post office') != -1) {
    	searchType = 'postoffice';
    } /*else if (this.suggestions[i].indexOf('street name') != -1) {
    	searchType = 'address';
    } else if (this.suggestions[i].indexOf('state') != -1) {
    	searchType = 'state';
    } */else if (this.suggestions[i].indexOf('zip code') != -1) {
    	searchType = 'zip_code';
    } else if (this.suggestions[i].indexOf('state') != -1) {
    	searchType = 'state';
    } else if (commaRegexForAddress.test(this.suggestions[i])) {
        //this is an address search, so create a field with the mls id...this will enable quicksearchprocess to do a search
        //by mls id, which is faster than an address search
        var parentForm = this.el.form;
        $(parentForm).insert('<input type="hidden" name="quickSearchMls" id="quickSearchMls" value="'+this.data[i]+'">');
        this.addressSearch = true;//we want to keep the address in the search box instead of showing this.data[i] (the mls id) like we usually do
        searchType = "addressByMlsId";
    } else {
        //must be a city
        searchType = 'city';
    }
    
    if ($('qsstate')) {
    	$('qsstate').value = this.state[i];
    } else {//if design forgot to include a qsstate in the form lets add one
        var parentForm = this.el.form;
        $(parentForm).insert('<input type="hidden" name="qsstate" id="qsstate" value="'+this.state[i]+'">');
    }
    
    if (this.data[i].indexOf('street:') != -1) {
    	if (!$('qsstate')) {
    	    var parentForm = this.el.form;
    		$(parentForm).insert('<input type="hidden" name="qsstate" id="qsstate" value="'+this.state[i]+'">');
    	}
    	searchType = 'address';
    } 
    
    if ($('quickSearchField')) {
    	$('quickSearchField').value = searchType;
    } else {
    	var parentForm = this.el.form;
    	
    	//this.el.form.insert({bottom:'<input type="hidden" name="quickSearchField" id="quickSearchField" value="'+searchType+'">'});
    	$(parentForm).insert('<input type="hidden" name="quickSearchField" id="quickSearchField" value="'+searchType+'">');
    }
    
    if (selectedValue) {
      this.el.value = selectedValue;
      if (this.options.autoSubmit && this.el.form) {
        this.el.form.submit();
      }
      this.ignoreValueChange = true;
      this.hide();
      this.onSelect(i);
    }
  },

  moveUp: function() {
    if (this.selectedIndex === -1) { return; }
    if (this.selectedIndex === 0) {
      this.container.childNodes[0].className = '';
      this.selectedIndex = -1;
      this.el.value = this.currentValue;
      return;
    }
    this.adjustScroll(this.selectedIndex - 1);
  },

  moveDown: function() {
    if (this.selectedIndex === (this.suggestions.length - 1)) { return; }
    this.adjustScroll(this.selectedIndex + 1);
  },

  adjustScroll: function(i) {
    var container = this.container;
    var activeItem = this.activate(i);
    var offsetTop = activeItem.offsetTop;
    var upperBound = container.scrollTop;
    var lowerBound = upperBound + this.options.maxHeight - 25;
    if (offsetTop < upperBound) {
      container.scrollTop = offsetTop;
    } else if (offsetTop > lowerBound) {
      container.scrollTop = offsetTop - this.options.maxHeight + 25;
    }
    
    this.el.value = this.suggestions[i];
    
    //at the point the user is selecting a "Search...." search term, we want to strip out the 
    //extra stuff like Search subdivsion, area, school district, etc.
    this.el.value = this.el.value.replace('Search ', '');
    this.el.value = this.el.value.replace('area ', '');
    this.el.value = this.el.value.replace('school district ', '');
    this.el.value = this.el.value.replace(' county', '');
    this.el.value = this.el.value.replace(qsSubLabel+' ', '');
    this.el.value = this.el.value.replace('postoffice ', '');
    this.el.value = this.el.value.replace('street name ', '');
    this.el.value = this.el.value.replace('state ', '');
    this.el.value = this.el.value.replace('zip code ', '');
    this.el.value = this.el.value.replace('mls id ', '');
    this.el.value = this.el.value.replace(/ \(.*?\)/, "");//replace the listing counts in parentheses
  },

  onSelect: function(i) {
    (this.options.onSelect || Prototype.emptyFunction)(this.suggestions[i], ((this.addressSearch===true)?(this.suggestions[i]):(this.data[i])));
  }

};

Event.observe(document, 'dom:loaded', function(){ Autocomplete.isDomLoaded = true; }, false);

//Copyright 2008 Bontrager Connection, LLC
//http://www.willmaster.com/

//When no form field name is provided, it is assumed 
//to be the default name with the default name 
//increment number appended.

var DefaultName = "gift";
var DefaultNameIncrementNumber = 0;

//No further customizations required.
function AddFormField(id,type,name,value,tag) {
if(! document.getElementById && document.createElement) { return; }
var inhere = document.getElementById(id);
var formfield = document.createElement("input");
if(name.length < 1) {
DefaultNameIncrementNumber++;
name = String(DefaultName + DefaultNameIncrementNumber);
}
formfield.name = name;
formfield.type = type;
formfield.value = value;
if(tag.length > 0) {
var thetag = document.createElement(tag);
thetag.appendChild(formfield);
inhere.appendChild(thetag);
}
else { inhere.appendChild(formfield); }
} // function AddFormField()


