// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
//           (c) 2005 Jon Tirsen (http://www.tirsen.com)
// Contributors:
//  Richard Livsey
//  Rahul Bhargava
//  Rob Wills
// 
// See scriptaculous.js for full license.

// Caching code by Andrew Tetlaw (http://tetlaw.id.au)
// Modified in 2006 by Tangent Audiovisual (http://www.tangent.es)


var Autocompleter = {}
Autocompleter.Base = function() {};
Autocompleter.Base.prototype = {
  baseInitialize: function(element, update, teCodi, options) {
    this.element         = $(element); 
    this.update          = $(update);  
    this.teCodi          = teCodi;
    this.hasFocus        = false; 
    this.changed         = false; 
    this.active          = false; 
    this.index           = 0;     
    this.entryCount      = 0;
    this.posatCodiPostal = false;

    if (this.setOptions)
      this.setOptions(options);
    else
      this.options = options || {};

    this.update.style.zIndex=1000;

    this.options.paramName    = this.options.paramName || this.element.name;
    this.options.tokens       = this.options.tokens || [];
    this.options.frequency    = this.options.frequency || 0.4;
    this.options.minChars     = this.options.minChars || 1;
    this.options.onShow       = this.options.onShow || 
    function(element, update){ 
      if(!update.style.position || update.style.position=='absolute') {
        update.style.position = 'absolute';
	update.style.zIndex=1000;
        Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
      }
      Effect.Appear(update,{duration:0});
    };
    this.options.onHide = this.options.onHide || 
    function(element, update){ new Effect.Fade(update,{duration:0}) };

    if (typeof(this.options.tokens) == 'string') 
      this.options.tokens = new Array(this.options.tokens);

    this.observer = null;
    
    this.element.setAttribute('autocomplete','off');

    Element.hide(this.update);

    Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
    Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
  },

  show: function() {
    if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
    if(!this.iefix && 
      (navigator.appVersion.indexOf('MSIE')>0) &&
      (navigator.userAgent.indexOf('Opera')<0) &&
      (Element.getStyle(this.update, 'position')=='absolute')) {
      new Insertion.After(this.update, 
       '<iframe id="' + this.update.id + '_iefix" '+
       'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
      this.iefix = $(this.update.id+'_iefix');
      this.update.style.zIndex = 10;
    }
    if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
  },
  
  fixIEOverlapping: function() {
    Position.clone(this.update, this.iefix);
    this.iefix.style.zIndex = 1;
    this.update.style.zIndex = 1000;
    Element.show(this.iefix);
  },

  hide: function() {
    this.stopIndicator();
    if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
    if(this.iefix) Element.hide(this.iefix);
  },

  startIndicator: function() {
    if(this.options.indicator) Element.show(this.options.indicator);
  },

  stopIndicator: function() {
    if(this.options.indicator) Element.hide(this.options.indicator);
  },

  onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.selectEntry();
	 var codiPoblacio=this.update.firstChild.childNodes[this.index].id.substring(this.update.firstChild.childNodes[this.index].id.length-5,this.update.firstChild.childNodes[this.index].id.length);
	 if (this.teCodi) {
		this.buscarCodiPostal(codiPoblacio,this.options.codiPostal);
	    	this.posatCodiPostal=true;
		}
         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_UP:
         this.markPrevious();
         this.render();
         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
         return;
       case Event.KEY_DOWN:
         this.markNext();
         this.render();
         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
         return;
      }
     else 
      if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN) 
        return;

    this.changed = true;
    this.hasFocus = true;
    var t=this.getToken();
    if ((t.length==0 || t.length==1) && this.teCodi){
	this.posarInput("",this.options.codiPostal);
    }
    if(this.observer) clearTimeout(this.observer);
      this.observer = 
        setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
  },

  onHover: function(event) {
    var element = Event.findElement(event, 'LI');
    if(this.index != element.autocompleteIndex) 
    {
        this.index = element.autocompleteIndex;
        this.render();
    }
    Event.stop(event);
  },

	buscarRulesValidator:function (id,objFormValidator){
		for (var i=0;i<objFormValidator.rules.length;i++){
			if (objFormValidator.rules[i].element_id==id){
				return i;
				}
			}
		return false;
		},

  posarLabelIComentari:function (elementCodiPostal){
		var elementDiv=document.getElementById(elementCodiPostal).parentNode;
		elementDiv.innerHTML='';
		var elementText=document.createTextNode('Codi Postal*:');
		var elementLabel=document.createElement('LABEL');
		elementLabel.setAttribute('for','codiPostal');
		elementLabel.appendChild(elementText);
		elementDiv.appendChild(elementLabel);
		var elementRegla=document.createComment("codiPostal ^((08)|(17)|(25)|(43))+[0-9]{3}$ false true");
		elementDiv.appendChild(elementRegla);
		return elementDiv;
 	},

  posarInput:function (codiPostal,elementCodiPostal){
  	var elementDiv=this.posarLabelIComentari(elementCodiPostal);
	var elementHTML='<input name="codiPostal" id="codiPostal" value="'+codiPostal[0]+'" readonly />';
	if (codiPostal=="") elementHTML='<input name="codiPostal" id="codiPostal" value="'+codiPostal+'" readonly />';
	else elementHTML='<input name="codiPostal" id="codiPostal" value="'+codiPostal[0]+'" readonly />';
	elementDiv.innerHTML+=elementHTML;
	var numRules=this.buscarRulesValidator('codiPostal',formValidator.validatorCollection[0]);
	formValidator.validatorCollection[0].rules[numRules].element=document.getElementById("codiPostal");
  },
  ordenacion:function(x,y) {
		return ( x < y ) ? -1 : ( x > y ) ? 1 : 0;
	},
  posarSelect:function (codiPostal,elementCodiPostal){
		var elementDiv=this.posarLabelIComentari(elementCodiPostal);
		var elementHTML='<select name="codiPostal" id="codiPostal">';
		elementHTML+='<option></option>';
		codiPostal.sort(this.ordenacion)
		for (var i=0;i<codiPostal.length;i++){
			elementHTML+='<option value="'+codiPostal[i]+'">'+codiPostal[i]+'</option>';
			}
		elementHTML+='</select>';
		elementDiv.innerHTML+=elementHTML;
		var elementSelect=document.getElementById(elementCodiPostal)
		var numRules=this.buscarRulesValidator('codiPostal',formValidator.validatorCollection[0]);
		formValidator.validatorCollection[0].rules[numRules].element=elementSelect;
  },

  buscarCodiPostal:function (codiPoblacio,elementCodiPostal){
	for (var i=0;i<myCPc.length;i++){
		if (codiPoblacio==myCPc[i].codiMunicipi){
			if (myCPc[i].codiPostal.length==1){
				this.posarInput(myCPc[i].codiPostal,elementCodiPostal);
				break;
				}
			else{
				this.posarSelect(myCPc[i].codiPostal,elementCodiPostal);
				break;
				}
			}
	}
	
  },

  onClick: function(event) {
    var element = Event.findElement(event, 'LI');
    this.index = element.autocompleteIndex;
    this.selectEntry();
    var codiPoblacio=element.id.substring(element.id.length-5,element.id.length);
    if (this.teCodi) {
	this.buscarCodiPostal(codiPoblacio,this.options.codiPostal);
	this.posatCodiPostal=true;
	}
    this.hide();
  },
  
  buscarCodiPoblacio: function (){
  if (this.element.value!=""){
	  if (this.update.childNodes>0){
	  	for (var i=0;i<this.update.childNodes[0].childNodes.length;i++){
			if (this.update.childNodes[0].childNodes[i].className){
					if (this.update.childNodes[0].childNodes[i].className){
							if (this.update.childNodes[0].childNodes[i].className=='selected'){
								return this.update.childNodes[0].childNodes[i].id.substring(this.update.childNodes[0].childNodes[i].id.length-5,this.update.childNodes[0].childNodes[i].id.length);
							}
					}
				}
			}
		}
		var codiPoblacio=buscarCodi(myP,this.element.value,true);
		if (codiPoblacio==myP.length){
			return false;		
			}
		else {
			return myP[codiPoblacio].id;
			}
  	}
  },
  buscarNomPoblacio : function (codiPoblacio){
  	for(var i=0;i<myP.length;i++){
  		if (myP[i].id==codiPoblacio){
  			return myP[i].nom;
  			}
  		}
  },

  onBlur: function(event) {
    // needed to make click events working
	    if (this.teCodi && !this.posatCodiPostal) {
		if (this.update.firstChild){
			var codiPoblacio=this.buscarCodiPoblacio();
			if (codiPoblacio) {
				this.buscarCodiPostal(codiPoblacio,this.options.codiPostal);
				this.element.value=this.buscarNomPoblacio(codiPoblacio);
				}
			}
		}
    setTimeout(this.hide.bind(this), 250);
    this.hasFocus = false;
    this.active = false;     
  }, 
  
  render: function() {
    if(this.entryCount > 0) {
      for (var i = 0; i < this.entryCount; i++)
        this.index==i ? 
          Element.addClassName(this.getEntry(i),"selected") : 
          Element.removeClassName(this.getEntry(i),"selected");
        
      if(this.hasFocus) { 
        this.show();
        this.active = true;
      }
    } else {
      this.active = false;
      this.hide();
    }
  },
  
  markPrevious: function() {
    if(this.index > 0) this.index--
      else this.index = this.entryCount-1;
  },
  
  markNext: function() {
    if(this.index < this.entryCount-1) this.index++
      else this.index = 0;
  },
  
  getEntry: function(index) {
    return this.update.firstChild.childNodes[index];
  },
  
  getCurrentEntry: function() {
    return this.getEntry(this.index);
  },
  
  selectEntry: function() {
    this.active = false;
    this.updateElement(this.getCurrentEntry());
  },

  updateElement: function(selectedElement) {
    if (this.options.updateElement) {
      this.options.updateElement(selectedElement);
      return;
    }
    var value = '';
    if (this.options.select) {
      var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
      if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
    } else
      value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
    var lastTokenPos = this.findLastToken();
    if (lastTokenPos != -1) {
      var newValue = this.element.value.substr(0, lastTokenPos + 1);
      var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
      if (whitespace)
        newValue += whitespace[0];
      this.element.value = newValue + value;
    } else {
      this.element.value = value;
    }
    this.element.focus();
    
    if (this.options.afterUpdateElement)
      this.options.afterUpdateElement(this.element, selectedElement);
  },
  retornaFormulariElement:function(element){
	var ele=element;
	while(ele.tagName!="FORM"){
		ele=ele.parentNode;
		}	
	return ele;
  },
  getXmlToken: function(inXml) {
    return inXml.getElementsByTagName("suggeriments").item(0).getAttribute("texte");
  },

  xmlToList: function(inXml, elemName) {
    var currToken = this.getXmlToken(inXml);
    var arrNodes = inXml.getElementsByTagName("sugg");
    var str = '<ul>';
    for (var i=0; i<arrNodes.length; i++)
      str += '<li id="'+inXml.getElementsByTagName("sugg")[i].getAttribute("codiId")+'">' + this.highlightToken(arrNodes[i].childNodes[0].nodeValue, currToken) + '</li>';
    str += '</ul>';
    return str;
  },

  highlightToken: function(str, tok) {
     var tokRegExp = new RegExp(tok, 'i');
     return str.replace(tokRegExp, '<strong>' + str.match(tokRegExp) + '</strong>');
  },

  updateChoices: function(choices) {
    if(!this.changed && this.hasFocus) {

      this.update.innerHTML = choices;
      Element.cleanWhitespace(this.update);
      Element.cleanWhitespace(this.update.firstChild);

      if(this.update.firstChild && this.update.firstChild.childNodes) {
        this.entryCount = this.update.firstChild.childNodes.length;
        for (var i = 0; i < this.entryCount; i++) {
          var entry = this.getEntry(i);
          entry.autocompleteIndex = i;
          this.addObservers(entry);
        }
      } else { 
        this.entryCount = 0;
      }

      this.stopIndicator();

      this.index = 0;
      this.render();
    }
  },

  addObservers: function(element) {
    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
  },

  onObserverEvent: function() {
    var t = this.getToken();
    this.changed = false;
    if ((t.length==0 || t.length==1)&& this.teCodi){
	this.posarInput("",this.options.codiPostal);
	if (typeof this.options.provincia != "undefined") document.getElementById(this.options.provincia).value="";
    }
   if(t.length>=this.options.minChars) {
      this.startIndicator();
      this.getUpdatedChoices(t);
    } else {
      this.active = false;
      this.hide();
    }
  },

  getToken: function() {
    var tokenPos = this.findLastToken();
    if (tokenPos != -1)
      var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
    else
      var ret = this.element.value;
      
    ret = trim(ret);

    return /\n/.test(ret) ? '' : ret;
  },

  findLastToken: function() {
    var lastTokenPos = -1;
    for (var i=0; i<this.options.tokens.length; i++) {
      var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
      if (thisTokenPos > lastTokenPos)
        lastTokenPos = thisTokenPos;
    }
    return lastTokenPos;
  },
  getURL:function (){
   return this.url;
  }
}

Ajax.Autocompleter = Class.create();
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
  initialize: function(element, update, url, teCodi, options) {
    this.baseInitialize(element, update, teCodi, options);
    this.options.asynchronous  = true;
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.defaultParams = this.options.parameters || null;
    this.options.method        = 'get';
    this.url                   = url;
    this.cache                 = {};
  },

  getUpdatedChoices: function(t) {
    if(this.cache[t]) {
        this.updateChoices(this.cache[t]);
    } else {
        entry = escape(this.options.paramName) + '=' + escape(t);
       	if (this.url==""){
	       	var poblacionsXML=buscarText(t);
		var domXMLPoblacions=poblacionsXML.toDOM();
		var t = this.getXmlToken(domXMLPoblacions);
		this.updateChoices(this.cache[t] = this.xmlToList(domXMLPoblacions));
		}
	else if (this.url=="nomes localitat"){
		this.posatCodiPostal=false;
	       	var poblacionsXML=buscarTextLocalitats(t);
		var domXMLPoblacions=poblacionsXML.toDOM();
		var t = this.getXmlToken(domXMLPoblacions);
		this.updateChoices(this.cache[t] = this.xmlToList(domXMLPoblacions));
		}
	else{
        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 t = this.getXmlToken(request.responseXML);
    this.updateChoices(this.cache[t] = this.xmlToList(request.responseXML));
    }
});

