Ajax.AutocompleterEx = Class.create(Autocompleter.Base, {
  initialize: function(element, update, url, options) {
    this.baseInitialize(element, update, options);
    this.options.asynchronous  = true;
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.defaultParams = this.options.parameters || null;
    this.options.method		   = options.method || "get";  // a yslow tip
    this.options.showentries   = options.showentries || 7;
    this.options.pageshowentries   = options.pageshowentries || 3;
    //this.options.lineheight = 16;
    this.options.checkboxes =  options.checkboxes || new Array( new Array(1,'Edit checkboxes'), new Array(2,' and minfilter'));
    this.options.minfilter =  options.minfilter || 0;
    this.checkboxvalues= new Array();
    for(c=0;c<this.options.checkboxes.length;c++){
		this.checkboxvalues[c]=this.options.checkboxes[c][0];
	}
    
    this.url                   = url;
    
    //this.update.style.position = 'absolute';
    this.options.onShow        = 
      function(element, update){
        if(!update.style.position || update.style.position=='absolute') {
          update.style.position = 'absolute';

          Position.clone(element, update, {
            setHeight: false,
            offsetTop: element.offsetHeight
          });
          update.style.width=null;
        }
        Effect.Appear(update,{duration:0.15});
      };   // width null added  ;)
    this.showindex=0;
    this.page=0;
    this.morepages=true;
    this.completed=true;
    this.updateTemp = document.createElement("div");
    document.body.appendChild(this.updateTemp);
    this.updateTemp.style.display="none";
    this.hasFocus =true;
    
    setTimeout(this.Init.bind(this),1000);
/*    this.update.style.display  = 'block';
    this.update.style.position = 'absolute';
    Position.clone(this.element, this.update, {
            setHeight: false,
            setWidth: false,
            offsetTop: element.offsetHeight
          });
    Effect.Appear(this.update,{duration:0.15});
 */  
  },

  // the ie does somehow need a special invitation
  Init: function(){
  	 	this.onObserverEvent();
  /*	 	try{
  	 		if(Prototype.Browser.IE){
  	 			this.options.onShow(this.element, this.update);
			  	if(this.element.value==''){
	  	 			this.hide();
	  	 		}
  	 		}
 		}catch(e) {}
 	*/
  	 		
  },
  getUpdatedChoicesMore: function() {
  	if(this.morepages && this.completed && ((this.showindex + 3*this.options.showentries) >= this.entryCount)  ){
	    this.startIndicator();
	
	    var entry = encodeURIComponent(this.options.paramName) + '=' +
	      encodeURIComponent(this.getToken()) + '&' + 'Filter=' +this.filter+ '&Page='+ this.page;  //encodeURIComponent(this.getToken())
	
		this.page ++; 
		
	    this.options.parameters = this.options.callback ?
	      this.options.callback(this.element, entry) : entry;
	
	    if(this.options.defaultParams)
	      this.options.parameters += '&' + this.options.defaultParams;
	
		this.completed=false;
	    
	    new Ajax.Request(this.url, this.options);
	 }
  },
  
  
  getToken: function() {
    var bounds = this.getTokenBounds();
    return this.element.value.strip();
  },

  OnCheckBoxClick: function (event){
  	var checkbox;
	for(c=0;c<this.options.checkboxes.length;c++){
		checkbox= $(this.update.id +'_checkBox_'+c);
		this.checkboxvalues[c]=checkbox.checked?this.options.checkboxes[c][0]:0;
	}
	this.DontHide(event);
  	this.getUpdatedChoicesEx();
  },
  
  DontHide: function (event){
  	this.hasFocus = true;
	this.active=true;
  	//this.render();
  },
  getUpdatedChoicesEx: function() {
  	this.filter=0;
  	for(c=0;c<this.options.checkboxes.length;c++){
  		this.filter+=this.checkboxvalues[c];
  	}
  	this.filter|=this.options.minfilter;
	this.page = 0;
	this.index = 0;
	this.entryCount=0;
	this.showindex=0;
	this.morepages=true;
	this.completed=true;
	this.update.childNodes[1].innerHTML="";
	this.getUpdatedChoicesMore();
  },
  
  
  getUpdatedChoices: function() {
  	var tempcheckbox="";
  	for(c=0;c<this.options.checkboxes.length;c++){
  		tempcheckbox+='<div><input type="checkbox" id="'+this.update.id +'_checkBox_'+c+'" name="AutocompleterBoxes"  value="'+this.options.checkboxes[c][0]+'" '+((this.checkboxvalues[c]==0)?'':'checked="checked"')+' />'+this.options.checkboxes[c][1]+'</div>';
  	}
	this.update.innerHTML = '<div id="'+this.update.id +'_up" style="display: none;"></div><ul></ul><div id="'+this.update.id +'_down"  style="display: none;"></div>'+
		'<div id="'+this.update.id +'_checkBox"  style="">'+tempcheckbox+'</div>'; 
	Event.observe(this.update.childNodes[0], 'click', this.PagePrev.bindAsEventListener(this));
	Event.observe(this.update.childNodes[2], 'click', this.PageNext.bindAsEventListener(this));
	var checkbox;
	for(c=0;c<this.options.checkboxes.length;c++){
		checkbox= $(this.update.id +'_checkBox_'+c);
		Event.observe(checkbox.parentNode, 'click', this.DontHide.bindAsEventListener(this));
		Event.observe(checkbox, 'click', this.OnCheckBoxClick.bindAsEventListener(this));
	}
	this.getUpdatedChoicesEx();
	this.getUpdatedChoicesMore();
  },
  PagePrev: function (event){

  	var pageshowentries_div2 = Math.ceil(this.options.pageshowentries/2); //3=ceil(5/2)
	if(this.showindex< pageshowentries_div2)
		this.showindex= this.entryCount-showentries_div2;
	if(this.showindex-this.options.pageshowentries> pageshowentries_div2) 
		this.showindex -=this.options.pageshowentries;
	else
		this.showindex=pageshowentries_div2;
	this.index=this.showindex;
	this.hasFocus = true;
  	this.render();
  },

  PageNext: function (event){
  	this.getUpdatedChoicesMore();
  	var pageshowentries_div2 = Math.ceil(this.options.pageshowentries/2); //3=ceil(5/2)
	if(this.showindex< pageshowentries_div2)
		this.showindex= pageshowentries_div2;
	if(this.showindex+this.options.pageshowentries< this.entryCount) 
		this.showindex +=this.options.pageshowentries;
	else
		this.showindex=this.entryCount;
	this.index=this.showindex;
	this.hasFocus = true;
  	this.render();
  } , 

  onBlur: function(event) {
    // needed to make click events working
    setTimeout(this.onBlurEx.bind(this), 250);
    this.hasFocus = false;
    //this.active = false;
  },
  
  onBlurEx: function(event) {
    // needed to make click events working
    if(!this.hasFocus){
    	setTimeout(this.hide.bind(this), 250);
    }
    
    this.active = false;
  },

  onComplete: function(request) {
   	this.updateChoices(request.responseText); //responseXML 
   	this.completed=true;
   	this.stopIndicator();
  },
  markPrevious: function() {
    if(this.index > 0) this.index--;
    this.showindex=this.index;
      //else this.index = this.entryCount-1; //dont go backwards
    //this.getEntry(this.index).scrollIntoView(true);
  },

  markNext: function() {
    if(this.index < this.entryCount-1) this.index++;
    this.showindex=this.index;
    //if(this.index > this.entryCount-8) 
    this.getUpdatedChoicesMore();
    //this.getEntry(this.index).scrollIntoView(false);
  },
  
  render: function() {
  	//TODO: make it more performant 
  
  	var entry;
  	var showentries_div2 = Math.ceil(this.options.showentries/2); //3=ceil(5/2)
  	var showindexpre = this.showindex<this.entryCount-showentries_div2?
  			showentries_div2:
  			this.options.showentries-(this.entryCount-this.showindex)+1;
  	var showindexpost = this.showindex>showentries_div2-1?
  			showentries_div2:
  			this.options.showentries-this.showindex;
  
  	
  //display up and down arrows only if necessary
  
  	this.update.childNodes[0].style.display ="none";
  	this.update.childNodes[2].style.display ="none";

  	
  	if(this.entryCount > this.options.showentries){
		//the uppe arrows
		// the +2 is due to the area replacement if no arrow is needed ... 
		//... so even when the showentries number is reached some(2) more entries can be displayed ... 
		//... since displaying arrows instead makes no sense at all
  		if(this.showindex-(showindexpre)>0 && this.entryCount > this.options.showentries+2){
  			this.update.childNodes[0].style.display ="block";
  		}else{
  			if(this.showindex<showindexpre)
  				showindexpost++;
  			showindexpre++;
  		}
		// the lower arrows
  		if(this.showindex+(showindexpost+1)>=this.entryCount){
  			if(this.showindex>=this.entryCount-showindexpost)
  				showindexpre++;
  			showindexpost++;
  		}else{
  			this.update.childNodes[2].style.display ="block";
  		}
	}  		
  	
    if(this.entryCount > 0) {
      var entrys_lowerbound=this.showindex-this.options.showentries*2;
      //if(entrys_lowerbound<0)
      		entrys_lowerbound=0;
      var entrys_upperbound=this.showindex+this.options.showentries*2;
      //if(entrys_upperbound>this.entryCount)
      	entrys_upperbound=this.entryCount;
      
      for (var i = entrys_lowerbound; i < entrys_upperbound; i++){
      	entry=this.getEntry(i);
      	//entry.style.height =this.options.lineheight+"px";
      	if(this.index==i)
			Element.addClassName(entry,"selected") ;
     	else
			Element.removeClassName(entry,"selected");
      	if(i> this.showindex-showindexpre && i< this.showindex+showindexpost)
      		entry.style.display ="block"; 
     	else	
     		entry.style.display ="none";
      }
      
      if(this.hasFocus) {
        this.show();
        this.active = true;
      }
    } else {
   	  this.active = false;
   	  this.hide();
    }
  },
  
  getEntry: function(index) {
    return this.update.childNodes[1].childNodes[index];
  },
  
  updateChoices: function(choices) {
  	
 	
  	this.updateTemp.innerHTML = choices;
    Element.cleanWhitespace(this.updateTemp);
    Element.cleanWhitespace(this.updateTemp.down()); 	
  		
  	var childs=this.updateTemp.firstChild.childNodes;  	
  	if (childs.length<3)
  		this.morepages = false;


 	var entryCount_before=0; //TODO: PERFORMANCE this.update.childNodes[1].childNodes.length;
	this.update.childNodes[1].innerHTML+=this.updateTemp.firstChild.innerHTML; 	
    //this.update.innerHTML="<ul><li>test</li></ul>";
  	if(this.update.childNodes[1] && this.update.childNodes[1].childNodes) {
      this.entryCount = this.update.childNodes[1].childNodes.length;
      for (var i = entryCount_before; i < this.entryCount; i++) {
        var entry = this.getEntry(i);
        //entry.style ="visibility: hidden;"; // 	display: none ??!
        entry.autocompleteIndex = i;
        this.addObservers(entry);
      }
    } else {
      this.entryCount = 0;
    }

    this.render();
  
  }

});

