/*  Suggest JavaScript, version 3.0
 *  2006 Christophe Clermont <cclermont@easyvoyage.fr>
 *
 *  works with Prototype framework
/*--------------------------------------------------------------------------*/

function getRawTexte(texte) {
  texte=texte.replace("&quot;","\"","g")
  texte=texte.replace("&amp;","&","g")
  texte=texte.replace("&lt;","<","g")
  texte=texte.replace("&gt;",">","g")
  texte=texte.replace("&nbsp;"," ","g")
  texte=texte.replace("&iexcl;","¡","g")
  texte=texte.replace("&cent;","¢","g")
  texte=texte.replace("&pound;","£","g")
  texte=texte.replace("&curren;","¤","g")
  texte=texte.replace("&yen;","¥","g")
  texte=texte.replace("&brvbar;","¦","g")
  texte=texte.replace("&sect;","§","g")
  texte=texte.replace("&uml;","¨","g")
  texte=texte.replace("&copy;","©","g")
  texte=texte.replace("&ordf;","ª","g")
  texte=texte.replace("&laquo;","«","g")
  texte=texte.replace("&not;","¬","g")
  texte=texte.replace("&shy;","­","g")
  texte=texte.replace("&reg;","®","g")
  texte=texte.replace("&macr;","¯","g")
  texte=texte.replace("&deg;","°","g")
  texte=texte.replace("&plusmn;","±","g")
  texte=texte.replace("&sup2;","²","g")
  texte=texte.replace("&sup3;","³","g")
  texte=texte.replace("&acute;","´","g")
  texte=texte.replace("&micro;","µ","g")
  texte=texte.replace("&para;","¶","g")
  texte=texte.replace("&middot;","·","g")
  texte=texte.replace("&cedil;","¸","g")
  texte=texte.replace("&sup1;","¹","g")
  texte=texte.replace("&ordm;","º","g")
  texte=texte.replace("&raquo;","»","g")
  texte=texte.replace("&frac14;","¼","g")
  texte=texte.replace("&frac12;","½","g")
  texte=texte.replace("&frac34;","¾","g")
  texte=texte.replace("&iquest;","¿","g")
  texte=texte.replace("&Agrave;","À","g")
  texte=texte.replace("&Aacute;","Á","g")
  texte=texte.replace("&Acirc;","Â","g")
  texte=texte.replace("&Atilde;","Ã","g")
  texte=texte.replace("&Auml;","Ä","g")
  texte=texte.replace("&Aring;","Å","g")
  texte=texte.replace("&AElig;","Æ","g")
  texte=texte.replace("&Ccedil;","Ç","g")
  texte=texte.replace("&Egrave;","È","g")
  texte=texte.replace("&Eacute;","É","g")
  texte=texte.replace("&Ecirc;","Ê","g")
  texte=texte.replace("&Euml;","Ë","g")
  texte=texte.replace("&Igrave;","Ì","g")
  texte=texte.replace("&Iacute;","Í","g")
  texte=texte.replace("&Icirc;","Î","g")
  texte=texte.replace("&Iuml;","Ï","g")
  texte=texte.replace("&ETH;","Ð","g")
  texte=texte.replace("&Ntilde;","Ñ","g")
  texte=texte.replace("&Ograve;","Ò","g")
  texte=texte.replace("&Oacute;","Ó","g")
  texte=texte.replace("&Ocirc;","Ô","g")
  texte=texte.replace("&Otilde;","Õ","g")
  texte=texte.replace("&Ouml;","Ö","g")
  texte=texte.replace("&times;","×","g")
  texte=texte.replace("&Oslash;","Ø","g")
  texte=texte.replace("&Ugrave;","Ù","g")
  texte=texte.replace("&Uacute;","Ú","g")
  texte=texte.replace("&Ucirc;","Û","g")
  texte=texte.replace("&Uuml;","Ü","g")
  texte=texte.replace("&Yacute;","Ý","g")
  texte=texte.replace("&THORN;","Þ","g")
  texte=texte.replace("&szlig;","ß","g")
  texte=texte.replace("&agrave;","à","g")
  texte=texte.replace("&aacute;","á","g")
  texte=texte.replace("&acirc;","â","g")
  texte=texte.replace("&atilde;","ã","g")
  texte=texte.replace("&auml;","ä","g")
  texte=texte.replace("&aring;","å","g")
  texte=texte.replace("&aelig;","æ","g")
  texte=texte.replace("&ccedil;","ç","g")
  texte=texte.replace("&egrave;","è","g")
  texte=texte.replace("&eacute;","é","g")
  texte=texte.replace("&ecirc;","ê","g")
  texte=texte.replace("&euml;","ë","g")
  texte=texte.replace("&igrave;","ì","g")
  texte=texte.replace("&iacute;","í","g")
  texte=texte.replace("&icirc;","î","g")
  texte=texte.replace("&iuml;","ï","g")
  texte=texte.replace("&eth;","ð","g")
  texte=texte.replace("&ntilde;","ñ","g")
  texte=texte.replace("&ograve;","ò","g")
  texte=texte.replace("&oacute;","ó","g")
  texte=texte.replace("&ocirc;","ô","g")
  texte=texte.replace("&otilde;","õ","g")
  texte=texte.replace("&ouml;","ö","g")
  texte=texte.replace("&divide;","÷","g")
  texte=texte.replace("&oslash;","ø","g")
  texte=texte.replace("&ugrave;","ù","g")
  texte=texte.replace("&uacute;","ú","g")
  texte=texte.replace("&ucirc;","û","g")
  texte=texte.replace("&uuml;","ü","g")
  texte=texte.replace("&yacute;","ý","g")
  texte=texte.replace("&thorn;","þ","g")
  texte=texte.replace("&yuml;","ÿ","g")
  return texte;
}


function debug(text) {
  try {
    box = document.getElementById("debug");
    box.value += text+"\n";
  } catch(e) {}
}

Element.collectTextNodesIgnoreClass = function(element, ignoreclass) {
  var children = $(element).childNodes;
  var text     = "";
  var classtest = new RegExp("^([^ ]+ )*" + ignoreclass+ "( [^ ]+)*$","i");
  
  for (var i = 0; i < children.length; i++) {
    if(children[i].nodeType==3) {
      text+=children[i].nodeValue;
    } else {
      if((!children[i].className.match(classtest)) && children[i].hasChildNodes())
        text += Element.collectTextNodesIgnoreClass(children[i], ignoreclass);
    }
  }
  
  return text;
}

Element.stringValue = function(element) {
  if (typeof element == 'string')
    return element;
  else
    if (element.getName())
      return element.getName();
    else if (element.getAlias())
      return element.getAlias();

  return '';
}

/*---------------------------------------------------------------------------*/

Element.notAmbiguousString = function(element) {
  if (typeof element == 'string') {
    var entry = element.toLowerCase();
    entry = entry.replace(/[äâà]/gi,"a");
    entry = entry.replace(/[ëêéè]/gi,"e");
    entry = entry.replace(/[ïîì]/gi,"i");
    entry = entry.replace(/[öôò]/gi,"o");
    entry = entry.replace(/[üûù]/gi,"u");
    entry = entry.replace(/[ñ]/gi,"n");
    entry = entry.replace(/[^a-z0-9 ]/gi,"");
    entry = entry.replace(/saint /gi,"st ");
    entry = entry.replace(/sainte /gi,"ste ");
    //entry = entry.replace(/ch /gi,"charles ");
    //entry = entry.replace(/mt /gi,"mount ");
    return entry;
  }
  return "";
}

/*---------------------------------------------------------------------------*/

var FormSelect = Class.create();
FormSelect.prototype = {
  initialize: function(id) {
    this.id = id;
    this.element = $(id);
    this.visible($(id).length > 0);
  },

  length: function() {
    return this.element.length;
  },

  focus: function() {
    this.element.focus();
  },

  clear: function() {
    while (this.element.length > 0) {
      this.element.remove(this.element.length - 1);
    }
    this.visible(false);
  },

  disable: function() {
    this.element.disabled=true;
  },

  enable: function() {
    this.element.disabled=false;
  },

  visible: function(visible) {
    this.isVisible = visible;
    var visibility = 'hidden';
    if (visible) {
       visibility = 'inherit';
       try {	
         VoitureEventShow();
       } catch(e) {}
    } else {
       try {
         VoitureEventHide();
       } catch(e) {}
    }

    this.element.style.visibility = visibility;
  },

  append: function(text, value) {
    if (!this.isVisible)
      this.visible(true);

    var option = document.createElement('option');
    option.text = text;
    option.value = value;

    try {
      this.element.add(option, null);
    } catch(e) {
      this.element.add(option); // IE
    } 
  },

  remove: function(index) {
    this.element.remove(index);
  },

  getElement: function() {
    return this.element;
  }
}

/*---------------------------------------------------------------------------*/

var Suggest = {}
Suggest.Common = function() {};
Suggest.Common.prototype = {
  common_initialize: function(element, update, error, maxchoices) {
    this.element = $(element);
    this.update = $(update);
    this.error = $(error);
    this.error.style.visibility='hidden';
    this.has_focus   = false;
    this.changed     = false;
    this.active      = false;
    this.index       = 0;
    this.startIndex  = 0; // indice de debut de la fenetre
    this.entry_count = 0;
    this.total_count = 0; // nombre total de suggestions
    this.exchange    = false;

    if (this.setOptions)
      this.setOptions();
    else
      this.options = {}

    this.options.tokens       = this.options.tokens || new Array();
    this.options.min_chars    = this.options.min_chars || 3;

    // Villes options
    this.options.array = new Array();
    this.options.tempArray = new Array();
    this.options.asynchronous = true;
    this.options.onComplete = this.onComplete.bind(this);
    this.options.method = 'GET';
    this.iatasurl = '/base/xml/iatas/';
    this.citiesurl = '/base/xml/cities/';
    this.adrsurl = '/base/xml/adrs/';
    this.filesuffix = '.xml';
    this.entrylength = 3;
    this.oldentry = ''; 

    var agt=navigator.userAgent.toLowerCase();
    var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
    var defMaxchoices = is_ie ? 7 : 15;
    this.options.choices= maxchoices || defMaxchoices;

    this.options.onShow       = this.options.onShow ||
      function(element, update){
/*
        if(!update.style.position || update.style.position=='absolute') {
          update.style.position = 'absolute';
          var offsets = Position.cumulativeOffset(element);
          update.style.left = offsets[0] + 'px';
          update.style.top  = (offsets[1] + element.offsetHeight) + 'px';
          update.style.width = element.offsetWidth + 'px';
        }
*/
        Element.show(update);
      };

    this.options.onHide = this.options.onHide ||
      function(element, update){
        Element.hide(update);
      };


    this.observer = null;
    // stocke le timer de la disparition de la fenetre de suggestions
    // permet d'être interrompu lors du changement de page
    this.clickobserver = null;

    Element.hide(this.update);

    Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
    //Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
    Event.observe(this.element, "keydown", this.onKeyPress.bindAsEventListener(this));
    //Event.observe(this.element, "keyup", this.onKeyPress.bindAsEventListener(this));
  },

  show: function() {
    if(this.update.style.display=='none') this.options.onShow(this.element, this.update);
    var agt=navigator.userAgent.toLowerCase();
    var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
    if(is_ie && !this.iefix) {
      new Insertion.After(this.update,
       '<iframe id="' + this.update.id + '_iefix" '+
       'style="display:none;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
       'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
      this.iefix = $(this.update.id+'_iefix');
    }
    if(this.iefix) {
      Position.cloneHeight(this.update, this.iefix);
      this.iefix.style.zIndex = 60000;
      this.update.style.zIndex = 61000;
      Element.show(this.iefix);
    }
  },

  hide: function() {
    if(this.update.style.display=='') this.options.onHide(this.element, this.update);
    if(this.iefix) Element.hide(this.iefix);
  },

  startIndicator: function() {
    if(this.indicator) Element.show(this.indicator);
  },

  stopIndicator: function() {
    if(this.indicator) Element.hide(this.indicator);
  },

  onKeyPress: function(event) {
    if(this.active)
      switch(event.keyCode) {
       case Event.KEY_TAB:
       case Event.KEY_RETURN:
         this.select_entry();
         Event.stop(event);
       case Event.KEY_ESC:
         this.hide();
         this.active = false;
         return;
       case Event.KEY_LEFT:
       case Event.KEY_RIGHT:
         return;
       case Event.KEY_UP:
         this.mark_previous();
         this.render();
         if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
         return;
       case Event.KEY_DOWN:
         this.mark_next();
         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.has_focus = true;

    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(element.autocompleteIndex >= 0 && this.index != element.autocompleteIndex) {
      this.index = element.autocompleteIndex;
      this.render();
    }

    Event.stop(event);
  },

  onClick: function(event) {
    var element = Event.findElement(event, 'LI');
    this.index = element.autocompleteIndex;
    this.select_entry();
    Event.stop(event);
  },

  onClickPage: function(event) {
    if(this.clickobserver) clearTimeout(this.clickobserver);
    this.element.focus();

    var element = Event.findElement(event, 'SPAN');

    if(element.autocompleteIndex == -1) {
      this.index = 0;
      var start = (element.innerHTML-1) * this.options.choices;
      if (start != this.startIndex) {
        this.startIndex = (element.innerHTML-1) * this.options.choices;
        this.has_focus = true;

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


  onBlur: function(event) {
    // needed to make click events working
    if(this.clickobserver) clearTimeout(this.clickobserver);
    this.clickobserver =
        setTimeout(this.hide.bind(this), 250);
    this.has_focus = false;
    this.active = false;
  },


  render: function() {
    if(this.entry_count > 0) {
      if (this.hideError(this))
        this.hideError(this);

      for (var i = 0; i < this.entry_count; i++)
        this.index==i ?
          Element.addClassName(this.get_entry(i),"selected") :
          Element.removeClassName(this.get_entry(i),"selected");

      if(this.has_focus) {
        //if(this.get_current_entry().scrollIntoView)
        //  this.get_current_entry().scrollIntoView(false);
        this.show();
        this.active = true;
      }
    }else{
      this.hide();
      if(this.showError(this))
        this.showError(this);
    }
  },

  mark_previous: function() {
    if(this.index > 0) this.index--;
    else {
      var pageCount = Math.ceil(this.total_count / this.options.choices)-1;
      if (pageCount > 0) {
        this.startIndex = (this.startIndex >= this.options.choices) ?
        this.startIndex-this.options.choices : (pageCount * this.options.choices);
        this.onObserverEvent();
      } else {
        this.startIndex = 0;
        this.index = this.entry_count-1;
      }
    } 
  },

  mark_next: function() {
    if(this.index < this.entry_count-1) this.index++;
    else { 
      var pageCount = Math.ceil(this.total_count / this.options.choices);
      this.startIndex = (this.startIndex <= this.total_count-this.options.choices) ?
        this.startIndex+this.options.choices : 0;
      this.onObserverEvent();
    }
  },

  get_entryObject: function(index) {
    return this.options.array[index];
  },

  get_current_entryObject: function() {
    return this.get_entryObject(this.index);
  },

  get_entry: function(index) {
    return this.update.firstChild.childNodes[index];
  },

  get_current_entry: function() {
    return this.get_entry(this.index);
  },

  select_entry: function() {
    this.active = false;
    obj = this.get_current_entryObject();
    value = Element.stringValue(obj);
    this.updateElement(value);
    this.element.focus();

    if (this.selectEntry(this)) {
      this.selectEntry(this);
    }
  },

  updateElement: function(value) {
    value=getRawTexte(value);
    var last_token_pos = this.findLastToken();
    if (last_token_pos != -1) {
      var new_value = this.element.value.substr(0, last_token_pos + 1);
      var whitespace = this.element.value.substr(last_token_pos + 1).match(/^\s+/);
      if (whitespace)
        new_value += whitespace[0];
      this.element.value = new_value + value;
    } else {
      this.element.value = value;
    }
  },

  updateChoices: function(choices) {
    if(!this.changed && this.has_focus) {
      this.update.innerHTML = choices;
      Element.cleanWhitespace(this.update);
      Element.cleanWhitespace(this.update.firstChild);

      if(this.update.firstChild && this.update.firstChild.childNodes) {
        this.entry_count=this.update.firstChild.childNodes.length;
        for (var i = 0; i < this.entry_count; i++) {
          entry = this.get_entry(i);
          entry.autocompleteIndex = i;
          this.addObservers(entry);
        }
      } else {
        this.entry_count = 1;
        this.update.innerHTML = '<p class="error">Aucune entr&ecute;e ne correspond.</p>';
      }

      if(this.update.childNodes.length > 1) {
        // footer
        var count=this.update.childNodes[1].childNodes.length;
        for (var j = 1; j < count; j++) {
           var element = this.update.childNodes[1].childNodes[j];
           if(element.innerHTML != null) {
             element.autocompleteIndex = -1;
             Event.observe(element, "click", this.onClickPage.bindAsEventListener(this));
           }
        }
      }

      this.stopIndicator();

      this.index = 0;
      this.render();
    }

  },

  // Fonction de mise a jour des suggestions
  getUpdatedChoices: function() {
    entry = this.getEntry(); 
    var tmpEntry = Element.notAmbiguousString(entry);
    shortEntry = Element.notAmbiguousString(entry).substring(0,this.entrylength).replace(" ","");

    if(this.oldentry != tmpEntry) {
      this.startIndex=0;
      this.total_count=0;
    }

    if(this.oldentry.substring(0,this.entrylength).replace(" ","") != shortEntry) {
      entryUrl = this.citiesurl + shortEntry + this.filesuffix;
      this.options.parameters = '';
      new Ajax.Request(entryUrl, this.options);

    } else {
      this.updateChoices(this.selector(this));
    } 

    this.oldentry = tmpEntry;

    if(this.exchange) {
      var tmpName = this.hidden.name;
      this.hidden.name = this.element.name;
      this.element.name = tmpName;
      this.exchange=false;
    }
    
  },

  // Fonction de mise a jour du xml a importer
  onComplete: function(request) {
    this.parser(request.responseText, this);
    this.updateChoices(this.selector(this));
  },

  // Fonction de parsing de la page de suggestions
  parser: function(content, instance) {
    instance.options.tempArray = new Array();
    suggestsList = content.split("<city>");
    for (s in suggestsList) {
      try {
        iata = this.valueParser(suggestsList[s], "iata");
        name = this.valueParser(suggestsList[s], "name");
        country = this.valueParser(suggestsList[s], "country");
        hasEntry = (this.valueParser(suggestsList[s], "hasaddress") == "true");
        if(iata!=null&&name!=null&&country!=null) {
          // Nouvelle entree pour la saisie
          var agt=navigator.userAgent.toLowerCase();
          var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
          var nameSuggest = name+", "+country;
          if (is_ie && nameSuggest.length > 25) {
              nameSuggest = name+" "+country.substring(country.length-5,country.length);
          }
          var se1=new SuggestElement(iata, nameSuggest, [true,true,hasEntry]);
          se1.addKeyword(iata);
          se1.addKeyword(name);

          // Sous elements de saisie
          cityAirports = suggestsList[s].split("<airport>");

          // Les mots cles juste avant le premier sous element de saisie (mais pas dans les sous elements)
          keywordsList = cityAirports[0].split("<keyword>");
          for(k in keywordsList) {
            var keyword = this.valueParser("<keyword>"+keywordsList[k], "keyword");
            if(keyword != null){
              se1.addKeyword(keyword);
            }
          }

          // temp: retirer ce test -> voir perfs
          if (instance.getEngine() == 'mev') {
            cityAirports.shift();
            for(a in cityAirports) {
              try {

                airIata = this.valueParser(cityAirports[a], "iata");
                airName = this.valueParser(cityAirports[a], "name");

                if(airIata!=null&&airName!=null) {
                  var se2 = new SuggestElement(airIata, airName, [true,false,false]);
                  if (se2.isOnline(instance.getEngine())) {
                    se1.addKeyword(airIata);
                    se1.addKeyword(airName);
                
                    //se2.addKeywork(airIata);
                    se2.addKeyword(airName);
                    se2.addKeyword(name);

                    airportKeywordList = cityAirports[a].split("<keyword>");
                    for(k in airportKeywordList) {
                      var keyword = this.valueParser("<keyword>"+airportKeywordList[k], "keyword");
                      se1.addKeyword(keyword);
                      se2.addKeyword(keyword);
                    }

                    se1.addSubElement(se2);
                  }
                }

              } catch(e) {debug("parsing airport "+e);}
            }
          }

          if (se1.isOnline(instance.getEngine()))
            instance.options.tempArray.push(se1);
        }
      } catch(e) {debug("parsing city "+e);}
    }
  },

  valueParser: function(content, param) {
    var length=param.length+2;
    var reDeb=new RegExp("<"+param+">");
    var reFin=new RegExp("<\/"+param+">");
    var debut=content.search(reDeb)+length;
    var fin=content.search(reFin);
    if(debut>=length&&fin>=0) return content.substring(debut, fin);
    return null;
  },

  // La fonction selector va calculer les champs a afficher
  selector: function(instance) {
    instance.options.array = new Array();
    var ret       = new Array(); // Beginning matches
    var partial   = new Array(); // Inside matches
    var entry     = Element.notAmbiguousString(instance.getEntry());
    var count     = 0;

    //for (var i = 0; i < instance.options.tempArray.length && 
    //    ret.length < instance.options.choices ; i++) {
    for (var i = 0; i < instance.options.tempArray.length ; i++) {
      var elem = instance.options.tempArray[i];

      if (elem.matches(entry,instance)) {
        if(count >= instance.startIndex && ret.length < instance.options.choices) {
          ret.push("<li>" + elem.getName() + "</li>");
          instance.options.array.push(elem);
        }
        count++;
        // ajout des enfants de l'element
        var subs = elem.getSubElements();
        for(s in subs) {

          var sub = subs[s];
          //if(sub.matches(entry, instance)) {
          if(count >= instance.startIndex && ret.length < instance.options.choices) {
            ret.push("<li class='subelement'>"+sub.getName()+"</li>");
            // on cherche sur la ville, donc on stocke la ville pour les sous-elements
            instance.options.array.push(sub);
          }
          count++;
          //}

        }
       
      }

    }
    instance.total_count = count-1;
    var page = Math.floor(instance.startIndex / instance.options.choices)+1;
    var pageNb = Math.ceil(count / instance.options.choices);
    var statusBar = '';
    if (pageNb > 1) {
      statusBar = '<p>Pages : ';
      var start = pageNb > 10 ? Math.max(page-4,1) : 1;
      var stop = pageNb > 10 ? Math.min(page+4,pageNb) : pageNb;
      for(var i=start; i<=stop; i++) {
        statusBar += (i == page) ? '<span class="selected">' : '<span>';
        statusBar += i+'</span>&nbsp;';
      }
      statusBar += '</p>';
    }
    return '<ul class="dropDown">' + ret.join('') + '</ul>' + statusBar;
  },

  addObservers: function(element) {
    Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
    Event.observe(element, "click", this.onClick.bindAsEventListener(this));
  },

  onObserverEvent: function() {
    this.changed = false;
    if(this.getEntry().length>=this.options.min_chars) {
      this.startIndicator();
      this.getUpdatedChoices();
    } else {
      this.active = false;
      this.hide();
    }
  },

  getEntry: function() {
    var token_pos = this.findLastToken();
    if (token_pos != -1)
      var ret = this.element.value.substr(token_pos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
    else
      var ret = this.element.value;

    return /\n/.test(ret) ? '' : ret;
  },

  findLastToken: function() {
    var last_token_pos = -1;

    for (var i=0; i<this.options.tokens.length; i++) {
      var this_token_pos = this.element.value.lastIndexOf(this.options.tokens[i]);
      if (this_token_pos > last_token_pos)
        last_token_pos = this_token_pos;
    }
    return last_token_pos;
  }
}

/*---------------------------------------------------------------------------*/

Suggest.Voiture = Class.create();
Suggest.Voiture.prototype = Object.extend(new Suggest.Common(), Object.extend(new Ajax.Base(), {
  initialize: function(element, update, select, error) {
    this.common_initialize(element, update, error);
    this.select = new FormSelect(select);

    var tmpName = "pickUpSuggest";
    this.select.getElement().name = this.element.name;
    this.element.name = tmpName;
  },

  // Fonction de mise a jour des suggestions
  getUpdatedChoices: function() {
    this.select.clear();
    entry = this.getEntry(); 
    shortEntry = Element.notAmbiguousString(entry).substring(0,this.entrylength).replace(" ",""); 

    if(this.oldentry != shortEntry) {
      entryUrl = this.citiesurl + shortEntry + this.filesuffix;
      this.options.parameters = '';
      new Ajax.Request(entryUrl, this.options);
      this.oldentry = shortEntry; 

    } else {
      this.updateChoices(this.selector(this));
    } 
  },

  // Initialisation des parametres optionnels
  setOptions: function() {
    this.options = Object.extend({
      //choices: 10,
      partial_search: false,
      partial_chars: 2,
      ignore_case: true,
      full_search: false,

      addressParser: function(content, instance) {
        suggestsList = content.split("<suggest>");
        for (s in suggestsList) {
          try {
            id = this.valueParser(suggestsList[s], "id");
            alias = this.valueParser(suggestsList[s], "alias");
            type = this.valueParser(suggestsList[s], "type");

            if (id != null && alias != null && type != null)
              new Address(id, alias, type, instance.select);
          } catch(e) {}
        }
      },

      valueParser: function(content, param) {
        var length = param.length+2;
        var reDeb = new RegExp("<"+param+">");
        var reFin = new RegExp("<\/"+param+">");
        var debut = content.search(reDeb)+length;
        var fin = content.search(reFin);

        if (debut >= length && fin >= 0)
          return content.substring(debut, fin);

        return null;
      }

    }, {});
  },

  selectEntry: function(instance) {
    instance.select.clear();
    instance.select.disable();
    instance.select.append("Recherche des adresses ...", "");

    var obj = instance.get_current_entryObject();
    var iata = obj.getId();

    if(iata) {
      adOptions = {}
      adOptions.onComplete =  instance.onCompleteAddress.bind(instance);
      adOptions.parameters = '';
      adOptions.asynchronous = true;
      adOptions.method = 'GET';

      carUrl = instance.adrsurl + iata.toLowerCase() + instance.filesuffix;
      new Ajax.Request(carUrl, adOptions); 
    }
  }, 

  onCompleteAddress: function(request) {
    var txt = request.responseText;
    this.select.clear();
    if (txt.length > 1) {
      this.select.append("Selectionnez une adresse ...", "");
      this.options.addressParser(getRawTexte(txt), this);

      if (this.select.length() < 3)
        this.select.remove(0);
 
      this.select.enable();     
      this.select.focus();
    }
  },

  hideError: function(instance) {
    instance.error.style.visibility = 'hidden';
  },

  showError: function(instance) {
    instance.error.style.left = instance.select.getElement().style.left;
    instance.error.style.top = instance.select.getElement().style.top;
    instance.error.style.zIndex = 50;
    instance.error.style.visibility = 'inherit';
  },

  getEngine: function() {
    return 'mec';
  }

}));

/*---------------------------------------------------------------------------*/

var Address = Class.create();
Address.prototype = {
  initialize: function(id, alias, type, select) {
    this.id = id;
    this.alias = alias;
    this.type = type;
 
    this.updateSelect(select);
  },

  updateSelect: function(select) {
    select.append(alias, id);
  }
}

/*---------------------------------------------------------------------------*/
/* Element utilise pour stocker une suggestion                               */
/*                                                                           */
/* Le tableau online permet de definir pour chaque moteur si la suggestion   */
/*  doit etre montree (true) ou non (false)                                  */

var SuggestElement = Class.create();
SuggestElement.prototype = {
  initialize: function(id, name, online) {
    this.id = id;
    this.name = name;
    this.online = online || new Array();
    this.keywords = new Array();
    this.subelements = new Array();
  },

  getId: function() {
    return this.id;
  },

  getName: function() {
    return this.name;
  },

  // fonction interne pour detecter le type
  getType: function() {
    return true;
  },

  // for each meta engine we define a marker
  isOnline: function(engine) {
    if (typeof engine == 'string') {
      if (engine == 'mev' && this.online.length > 0)
        return this.online[0];
      if (engine == 'meh' && this.online.length > 1)
        return this.online[1];
      if (engine == 'mec' && this.online.length > 2)
        return this.online[2];
    }
    return false;   
  },
  
  addKeyword: function(keyword) {
    var key = Element.notAmbiguousString(keyword);
    if (key != null && key!='')
      this.keywords.push(key);
  },

  getKeywords: function() {
    return this.keywords;
  },

  addSubElement: function(subelement) {
    if (subelement.getType())
      this.subelements.push(subelement);
  },

  getSubElements: function() {
    return this.subelements;
  },

  matches: function(suggest, instance) {
    /* les elements hors ligne ne sont pas ajoutes au moment
       du parsing -> voir methode Suggest.Common#parser
    if(!this.isOnline(instance.getEngine()))
      return false;
    */

    for(key in this.keywords) {
      var found_pos = this.keywords[key].indexOf(suggest);

      if (found_pos == 0) {
        return true;
      } else if (suggest.length >= instance.options.partial_chars &&
        instance.options.partial_search && found_pos != -1) {
        if (!instance.options.full_search &&
            !/\s/.test(this.keywords[key].substr(found_pos-1,1)))
          continue;
        return true;
      }
    }

    return (Element.notAmbiguousString(this.getName()).indexOf(suggest) >= 0);

  }
}

/*---------------------------------------------------------------------------*/

Suggest.Vol = Class.create();
Suggest.Vol.prototype = Object.extend(new Suggest.Common(), Object.extend(new Ajax.Base(), {
  initialize: function(element, update, hidden, error, nextElement, maxchoices) {
    this.common_initialize(element, update, error, maxchoices);
    this.hidden=$(hidden);
    this.nextElement=nextElement;

    this.exchange=(this.hidden.value.length > 0);
    if(this.exchange) {
      var tmpName = this.hidden.name;
      this.hidden.name = this.element.name;
      this.element.name = tmpName;
    }
  },

  // Initialisation des parametres optionnels
  setOptions: function() {
    this.options = Object.extend({
      //choices: 16,
      partial_search: false,
      partial_chars: 2,
      ignore_case: true,
      full_search: false

    }, {});
  },

  selectEntry: function(instance) {
    var obj = instance.get_current_entryObject();
    var iata = obj.getId();
    if(iata) instance.hidden.value=iata;

    if(!instance.exchange) {
      var tmpName = instance.hidden.name;
      instance.hidden.name = instance.element.name;
      instance.element.name = tmpName;
    }

    if(instance.nextElement){
      var elt=$(instance.nextElement);
      var eltSuggest=$(instance.nextElement+"Suggest");
     	if(elt) elt.focus();
     	if(eltSuggest) eltSuggest.focus();
    }
  },

  hideError: function(instance) {
    instance.error.style.visibility = 'hidden';
  },

  showError: function(instance) {
    instance.error.style.zIndex=50;
    instance.error.style.visibility='inherit';
  },

  getEngine: function() {
    return 'mev';
  }

}));

/*---------------------------------------------------------------------------*/

Suggest.Hotel = Class.create();
Suggest.Hotel.prototype = Object.extend(new Suggest.Common(), Object.extend(new Ajax.Base(), {
  initialize: function(element, update, hidden, error, nextElement, maxchoices) {
    this.common_initialize(element, update, error, maxchoices);
    this.hidden=$(hidden);

    this.exchange=(this.hidden.value.length > 0);
    if(this.exchange) {
      var tmpName = this.hidden.name;
      this.hidden.name = this.element.name;
      this.element.name = tmpName;
    }
  },

  // Initialisation des parametres optionnels
  setOptions: function() {
    this.options = Object.extend({
      //choices: 16,
      partial_search: false,
      partial_chars: 2,
      ignore_case: true,
      full_search: false

    }, {});
  },

  selectEntry: function(instance) {
    var obj = instance.get_current_entryObject();
    var iata = obj.getId();
    if(iata) instance.hidden.value=iata;

    if(!instance.exchange) {
      var tmpName = instance.hidden.name;
      instance.hidden.name = instance.element.name;
      instance.element.name = tmpName;
    }
  },

  hideError: function(instance) {
    instance.error.style.visibility = 'hidden';
  },

  showError: function(instance) {
    instance.error.style.zIndex=50;
    instance.error.style.visibility='inherit';
  },

  getEngine: function() {
    return 'meh';
  }

}));
