

var SelectAutocompleter = {}
SelectAutocompleter.Base = Class.create();
Object.extend(Object.extend(SelectAutocompleter.Base.prototype,
                            Autocompleter.Base.prototype), {
    selectBaseInitialize: function(element, valueElement, update, options) {
      this.baseInitialize(element, update, options);			
      this.select = document.createElement('select');
      this.update.appendChild(this.select);        
      this.select.style.width = '100%';
      Event.observe(this.select, "focus", this.onSelectFocus.bindAsEventListener(this));
      Event.observe(this.select, "keypress", this.onSelectKeyPress.bindAsEventListener(this));
      Event.observe(this.select, "blur", this.onBlur.bindAsEventListener(this));
      Event.observe(this.element, "change", this.onChange.bindAsEventListener(this));
      this.valueElement = $(valueElement);
      Event.observe(this.select, "click", this.onSelectClick.bindAsEventListener(this));
      if (this.options["valueElementValue"])
        this.valueElement.value = this.options["valueElementValue"];
    	this.cache = new Hash();
		
    this.options["rowCount"] = this.options["rowCount"] || 7;
	//this.options["useCache"] = !(this.options["useCache"] == false);
	//this.options["caseSensitive"] = this.options["caseSensitive"] == true;
	this.options["useCache"] = false;
	this.options["caseSensitive"] = false;
    this.options["autoSubmit"] = this.options["autoSubmit"] == true;
    this.options["matchBeginning"] = !(this.options["matchBeginning"] == false);
    },
    
    match: function(el1, el2) {
      if (this.options["matchBeginning"] == true)
          return el1.startsWith(el2);
      else
          return el1.indexOf(el2) >= 0;
    },
      
    onBlur: function(event) {
      // needed to make click events working
      blurTimer = setTimeout(this.hide.bind(this), 250);
      this.hasFocus = false;
      this.active = false;     
    },

    onSelectFocus: function(event) {
	    clearTimeout(blurTimer);
    },

    updateChoices: function(options) {
	    if(!this.changed && this.hasFocus) {
    	  this.select.update();
        options.each(function(option) {
            var opt = document.createElement('option');
            opt.value = option[0];
            opt.text = option;
            this.select.options.add(opt);
        }, this);
    	  this.select.size = this.options["rowCount"];
	      this.entryCount = this.select.length;
	      this.stopIndicator();		  
	      if(this.select.length == 1 && this.options.autoSelect) {
	        this.selectEntry();
	        this.hide();
	      } else {
	        this.render();
	      }
	    }
    }, 
    
	  getToken: function() {
	      return this.options["caseSensitive"] == true ? this.element.value :  this.element.value.toLowerCase();
	  },
	  
    render: function() {
    if(this.select.length > 0) {
      if(this.hasFocus) { 
        this.show();
        this.active = true;
      }
    } else {
      this.active = false;
      this.hide();
    }
    },

    show: function() {
    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
    if (this.select.length > 0)
        this.select.selectedIndex = 0;
    },

    hide: function() {
    this.stopIndicator();
    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
    },
    
    onChange: function(event) {
      if (this.element.value == '')
        this.valueElement.value = '';
    },

    onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
         if (Prototype.Browser.Opera)
             this.element.blur();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.active = false;
         Event.stop(event);
         return;
       case Event.KEY_LEFT:
       case Event.KEY_RIGHT:
         return;
       case Event.KEY_DOWN:   
	         if (this.select.length > 0) {
                 this.select.focus(); 
                 Event.stop(event);
	         if (Prototype.Browser.IE)
			         this.select.selectedIndex = 1;
     	    return;
	      }
      }
     else 
       if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || 
         (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return;

    this.changed = true;
    this.hasFocus = true;
        
    if(this.observer) clearTimeout(this.observer);
      this.observer = 
        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
      },

    getCurrentEntry: function() {
      return this.select.options[this.select.selectedIndex];
    },

    updateElement: function(selectedElement) {
    this.element.value = selectedElement.text;
    if (!this.valueElement)
		  this.valueElement = $(this.options.valueElement);
	  if (this.valueElement)
	    this.valueElement.value = selectedElement.value;
    this.element.focus();
    
    if (this.options.afterUpdateElement)
      this.options.afterUpdateElement(this.element, selectedElement);
      
    if (this.options["autoSubmit"]) {
      var theForm = Element.up(this.element,'form');
      if (theForm) {
        doIt = theForm.onsubmit ? theForm.onsubmit() : true;
        if (doIt)
          theForm.submit();
      }  
    }
    },
	
	onObserverEvent: function() {
	  this.changed = false;
	  var token = this.getToken();
	  
	  if(token.length>=this.options.minChars) {
		    var tokenFromCache = false;
		    if (this.options["useCache"] == true) {
		        if (this.cache.get(token))  //exact match in cache
		            tokenFromCache = this.cache.get(token);
		         else //look deeper
		            this.cache.keys().each(function(key) {
		                if (this.match(token, key)) {
                        tokenFromCache = [];
		                    this.cache.get(key).inject(tokenFromCache,
		                    function(tokenFromCache, el) {
		                        var comp = this.options["caseSensitive"] == true ? el[1] :  el[1].toLowerCase();
		                        if (this.match(comp, token))
		                            tokenFromCache.push(el);
		                        return tokenFromCache;
		                    }, this)
		                }
		            }, this)
		    }
	  	  if (tokenFromCache) {
			      this.updateChoices(tokenFromCache);
				} else {
			    	this.startIndicator();
			    	this.getUpdatedChoices();
				}
	  } else {
	    this.active = false;
	    this.hide();
	  }
	},

    onSelectKeyPress: function(event) {
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.element.focus();
         Event.stop(event);
      }
    },

    onSelectClick: function(event) {
    this.selectEntry();
    this.hide();
    }
    });

    Ajax.SelectAutocompleter = Class.create();
    Object.extend(Object.extend(Ajax.SelectAutocompleter.prototype, SelectAutocompleter.Base.prototype), {
    initialize: function(element, valueElement, update, url, options) {
    this.selectBaseInitialize(element, valueElement, update , options);
    this.options.asynchronous  = true;
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.defaultParams = this.options.parameters || null;
    this.url                   = url;
    },

    getUpdatedChoices: function() {
    entry = encodeURIComponent(this.options.paramName) + '=' + 
      encodeURIComponent(this.getToken());

    this.options.parameters = this.options.callback ?
      this.options.callback(this.element, entry) : entry;

    if(this.options.defaultParams) 
      this.options.parameters += '&' + this.options.defaultParams;

    new Ajax.Request(this.url, this.options);
    },

    onComplete: function(request) {
    var options = request.responseText.evalJSON(true);
    if (this.options["useCache"] == true)
        this.cache.set(this.getToken(), options);
    this.updateChoices(options);
    }

});
