var AutoComplete = function(field_id, results_id, get_url, results_class) {
  this.init(field_id, results_id, get_url, results_class);
  this.setAutoComplete();
}

AutoComplete.prototype = {
  init: function(field_id, results_id, get_url, results_class) {
    // initialise attributes
    this.field_id      = field_id;
    this.results_id    = results_id;
    this.get_url       = get_url;
    this.results_class = results_class || 'results'
    this.acListTotal   = 0;
    this.acListCurrent = -1;
    this.acDelay		   = 500;
    this.keyFilter     = [
      16, // Shift
      17, // Ctrl
      18, // Alt
      20, // Caps Lock
      35, // End
      36, // Home
      37, // Left arrow
      39, // Right arrow
      45, // Insert
    ];
    
    // system vars
    this.acURL		     = get_url;
    this.acSearchId	   = '#' + field_id;
    this.acResultsId	 = '#' + results_id;
  },
  
  setAutoComplete: function() {
    var THIS = this;

    // create the results div
  	$("body").append('<div id="' + this.results_id + '" class="' + this.results_class + '"></div>');

    this.acSearchField = $(this.acSearchId);
    this.acResultsDiv  = $(this.acResultsId);

  	// reposition div
  	this.repositionResultsDiv();
  	
  	// on blur listener
  	this.acSearchField.blur(function(){ setTimeout(function() {THIS.clearAutoComplete()}, 200) });

  	// on key up listener
  	this.acSearchField.keyup(function (e) {

  		// get keyCode (window.event is for IE)
  		var keyCode = e.keyCode || window.event.keyCode;
  		var lastVal = THIS.acSearchField.val();

  		// check an treat up and down arrows
  		if(THIS.updownArrow(keyCode)){
  			return;
  		}

  		// check for an ENTER or ESC
  		if(keyCode == 13 || keyCode == 27){
  			THIS.clearAutoComplete();
  			return;
  		}

  		// if is text that not in filter list, call with delay
      if(jQuery.inArray(keyCode, THIS.keyFilter) == -1) {
        setTimeout(function() {THIS.autoComplete(lastVal)}, THIS.acDelay);
      }
  	});
  },

  // treat the auto-complete action (delayed function)
  autoComplete: function(lastValue) {
    var THIS = this;
    
  	// get the field value
  	var part = this.acSearchField.val();
  	
    // if it's empty clear the resuts box and return
  	if(part == ''){
  		this.clearAutoComplete();
  		return;
  	}

  	// if it's equal the value from the time of the call, allow
  	if(lastValue != part){
  		return;
  	}

  	// get remote data as JSON

    $.ajax({
      type: "POST",
      url: THIS.acURL,
      data: "part=" + part,
      dataType: "json",
      success: function(json) {

        // get the total of results
        var ansLength = THIS.acListTotal = json.length;
        
        // if there are results populate the results div
        if(ansLength > 0){
          var newData = '';
		
          // create a div for each result
          for(i=0; i < ansLength; i++) {
			var result_data = json[i];
			newData += '<div class="unselected" style="z-index: 99;">' + result_data + '</div>';
			
          }
		

		// update the results div
          THIS.acResultsDiv.html(newData);
          THIS.acResultsDiv.css("display","block");
          
          // for all divs in results
          var divs = $(THIS.acResultsId + " > div");
      
          // on mouse over clean previous selected and set a new one
          divs.mouseover( function() {
            divs.each(function(){ this.className = "unselected"; });
            this.className = "selected";
          })
          
          // on click copy the result text to the search field and hide
          divs.click( function() {
			//auto fill in relevant building names
			THIS.acSearchField.val(this.childNodes[0].nodeValue);
            THIS.clearAutoComplete();
          });

        } else {
          //this.clearAutoComplete();
        }
      }
  	});
  },

  // clear auto complete box
  clearAutoComplete: function() {
  	this.acResultsDiv.html('');
  	this.acResultsDiv.css("display","none");
  },

  // reposition the results div accordingly to the search field
  repositionResultsDiv: function() {
  	// get the field position
  	var sf_pos    = this.acSearchField.offset();
    var sf_top    = sf_pos.top;
  	
	// set broswer different
	jQuery.each(jQuery.browser, function(i) {
	  if($.browser.msie){
		 sf_left  = sf_pos.left;
	  }else if ($.browser.safari){
		 sf_left  = sf_pos.left;
	  }else if ($.browser.mozilla) {
		 sf_left  = sf_pos.left;
	  }else {
		 sf_left  = sf_pos.left + 180;
	  }
	});


  	// get the field size
  	var sf_height = this.acSearchField.height();
  	var sf_width  = this.acSearchField.width();

  	// apply the css styles - optimized for Firefox
  	this.acResultsDiv.css("position","absolute");
  	this.acResultsDiv.css("left", sf_left - 1);
  	this.acResultsDiv.css("top", sf_top + sf_height + 1);
  	this.acResultsDiv.css("width", sf_width + 1);
  },
  
  // treat up and down key strokes defining the next selected element
  updownArrow: function(keyCode) {
    var THIS = this;
  	
    if(keyCode == 40 || keyCode == 38){

  		if(keyCode == 38){ // keyUp
  			if(this.acListCurrent == 0 || this.acListCurrent == -1){
  				this.acListCurrent = this.acListTotal-1;
  			}else{
  				this.acListCurrent--;
  			}
  		} else { // keyDown
  			if(this.acListCurrent == this.acListTotal-1){
  				this.acListCurrent = 0;
  			}else {
  				this.acListCurrent++;
  			}
  		}

  		// loop through each result div applying the correct style
  		this.acResultsDiv.children().each(function(i){
												   
  			if(i == THIS.acListCurrent){
				
				//auto fill in relevant building names
				THIS.acSearchField.val(this.childNodes[0].nodeValue);
  				this.className = "selected";
  			} else {
  				this.className = "unselected";
  			}
  		});

  		return true;
  	} else {
  		// reset
  		this.acListCurrent = -1;
  		return false;
  	}
  }
}
  

