var O2CONTROLS_VER = "$Revision: 1.42 $";

var O2 = new Object();

O2.Autocompleter = Class.create();
Object.extend(Object.extend(O2.Autocompleter.prototype, Ajax.Autocompleter.prototype), {

  //  ------------------ initialize  ----------------------
  /**
   * @param p_sNameSuffix  nom de base de cet autocomplete
   * @param p_sTS  timestamp pour identifier de façon unique le container
   */
  initialize: function(p_sNameSuffix, p_sTS, url, options) {
    this.nameSuffix    = p_sNameSuffix;
    this.ts            = p_sTS;
    var sFullSuffix = this.nameSuffix + (this.ts ? '.' + this.ts : '');
    this.baseInitialize('autoSearch' + sFullSuffix, 'autoSearchList' + sFullSuffix, options);
    this.mainDiv       = $O2("autocpl" + sFullSuffix);
    this.choice        = this.mainDiv.findChildById('choice' + sFullSuffix,'span');
    this.hdLibValue    = this.mainDiv.findChildById('autolib' + sFullSuffix,'input');
    this.editButton    = this.mainDiv.findChildById('editBut' + sFullSuffix,'input');
    this.oInput        = this.mainDiv.findChildById(this.nameSuffix,"input");
    // la div qui contient le champ d'input de recherche (this.element) et l'indicator
    this.divRech       = this.mainDiv.findChildById('rech'+sFullSuffix,'div');
    this.oInput["autocomplete"] = this;
    this.options.autoSelect    = this.options.autoSelect || true;
    this.options.asynchronous  = true;
    this.options.method        = 'get';
    this.options.onComplete    = this.onComplete.bind(this);
    this.options.onHide        = this.onHide.bind(this);
    this.options.onShow        = this.onShow.bind(this);
    this.options.callback      = this.callback.bind(this);
    this.options.updateElement = this.updateElement.bind(this);
    this.options.afterUpdateElement = this.afterUpdateElement.bind(this);
    this.options.defaultParams = this.options.parameters || "step=52&frm=js";
    this.options.baseTag       = this.options.baseTag || "e";
    this.options.onException   = function(element, e) { alert(e); };
    this.url                   = url;

    // event handler pour la span d'affichage du résultat
    this.choice.listenTo('click', this.showDebug.bindAsEventListener(this) );
    this.choice.listenTo('click', this.showHide.bindAsEventListener(this) );

    // event handler pour l'image "edit"
    if (this.editButton) {
      this.editButton.listenTo('click', function(event) {
          this.switchToEditMode();
          Event.stop(event);
          return false;
       }.bindAsEventListener(this) );
     }

    // event handler pour le champ de saisie
    this.element.listenTo('click', this.showDebug.bindAsEventListener(this)) ;
    this.element.listenTo('click', function(event) {
        if (Element.getStyle(this.update, 'display')=='none'){
          this.show();
          this.active = true;
        } else {
          this.hide();
          this.active = false;
        }
     }.bindAsEventListener(this) ) ;

    this.element.listenTo('focus', function(event) {
        var sBaseVal = this.element.getAttribute('baseValue').replace(/"/g,'');
        if(this.element.value==this.element.getAttribute('voidValue')) this.element.value = sBaseVal;
        // memorise valeur à "l'entrée"
        this.element.enterValue = this.element.value;
        this.setCursor(sBaseVal);
      }.bindAsEventListener(this) );

    //  ---------- elementOnBlur  ----------------------
    this.options.elementOnBlur = function(event) {
      var sBaseVal = this.element.getAttribute('baseValue').replace(/"/g,'');
      if(this.element.value==sBaseVal || this.element.value=='') this.element.value=this.element.getAttribute('voidValue');
      // si la valeur n'a pas été modifiée et qu'il y a une valeur sélectionnée, retourne au staleMode
      else if (this.element.value==this.element.enterValue && ""!=this.oInput.value) this.switchToStaleMode();
    }.bind(this);
    this.element.listenTo('blur', this.options.elementOnBlur.bindAsEventListener(this) ) ;
     
  },
  // surcharge du onHide
  onHide: function(element, update) {
    update.hide();
  },

  // surcharge du onShow
  onShow: function(element, update){
    // si aucun élément dans la liste, ne montre rien
    if (!update.hasChildNodes()) return;
    update.style.position = 'absolute';
    update.show();
    // si la liste dépasse de l'écran, déplacement au dessus du champ
    var oDivH = $O2('home');
    if ((update.offsetFrom(oDivH)[1]) > oDivH.clientHeight) {
      update.style.top = (update.style.top-update.clientHeight) + "px";
    }
    return;
  },

  // pour positionner le curseur à la fin du champs, en sélectionnant tout ce qui est en plus de baseVal
  setCursor: function(p_sBaseVal) {
    window.setTimeout( function() {
        var iStart = p_sBaseVal ? p_sBaseVal.length : 0;
        var iEnd = this.element.value ? this.element.value.length : 0;
        this.element.setSelectionRange(iStart, iEnd);
      }.bind(this),50);
  },

  // affiche les infos sur le champ
  showDebug: function(event) {
    if (event && event.ctrlKey) {
      showInputInfo(this.oInput);
      Event.stop(event);
    }
  },

  // affiche ou cache la liste déroulante des choix 
  showHide: function(event) {
    if (Element.getStyle(this.update, 'display')=='none') this.show();
    else this.hide();
  },

  startIndicator: function() {
    if(this.options.indicator) $O2(this.options.indicator).show('inline');
  },
  stopIndicator: function() {
   if(this.options.indicator && $O2(this.options.indicator)) $O2(this.options.indicator).hide();
  },

  switchToEditMode: function() {
    this.choice.style.display    ='none';
    this.editButton.style.display='none';
    this.divRech.style.display   ='inline';
    this.element.activate();
    this.hasFocus = true;
  },

  switchToStaleMode: function(p_xSelectedNode) {
    // cache l'input de saisie du texte de recherche
    this.divRech.style.display   ='none';
    this.choice.style.display    ='inline';
    this.editButton.style.display=  this.options.readonly ? 'none' : 'inline';
    this.hasFocus = false;
    if (p_xSelectedNode) this.choice.firstChild.textContent = p_xSelectedNode.textContent;
  },

  updateElement: function(p_xSelectedNode) {
    if (p_xSelectedNode) this.switchToStaleMode(p_xSelectedNode);
    if (this.options.afterUpdateElement) this.options.afterUpdateElement(this.element, p_xSelectedNode);
  },

  afterUpdateElement: function (p_oSearchInput, p_xSelectedNode) {
    var hdInput   = this.oInput;
    if (p_xSelectedNode) { 
      hdInput.value = p_xSelectedNode.id;
      hdInput.setAttribute("oDataNode", p_xSelectedNode.getAttribute("oDataNode"));
      if ("t_108"==hdInput.id) { // cas de la sélection d'une agence dans la fiche de saisie client
        ODYForm.doShowMessageAgency({oTargetContainer:$O2('edi').getDivFiche(), xDataNode:loadXML(p_xSelectedNode.getAttribute("oDataNode"))});
      }
      if (this.hdLibValue) this.hdLibValue.value = p_xSelectedNode.innerHTML;

    } else {
      hdInput.value = null;
      hdInput.removeAttribute("oDataNode");
      if (this.hdLibValue) this.hdLibValue.value = null;
    }
    // NB : on passe un objet event (non null donc) afin d'activer les recherches sur les éventuels controles dépendants
    // (cf. inputOnChange() l.512 dans edit.js)
    if (hdInput.onchange) hdInput.onchange(document.createEvent("HTMLEvents"));
    if (hdInput.onblur) hdInput.onblur(p_xSelectedNode);
  },

  // complète l'url avant envoie de la requete htttp
  callback: function(p_oInput, p_sQueryString) {
    var oReg = new RegExp("\{(\\d+)\}");
    var sFilterCriter = this.options.filterCriteria;
    if (sFilterCriter) {
      var oRes = oReg.exec(this.options.filterCriteria);
      if (oRes) {//possibilité de faire appel à une valeur se trouvant dans un autre dispiitem (recherche contrat client)
        var iMasterInputDispiId = oRes[1];
        var oMasterI = p_oInput.form[ODYForm.sET_SN].getInputByDisplayItemId(iMasterInputDispiId);
        var sActiveValue = oMasterI.getAttribute("activeValue");
        var sValue = oMasterI.getAttribute("value");
        sFilterCriter = sFilterCriter.replace(oRes[0], (sActiveValue.length>0?sActiveValue:sValue) );
      }
    }
      return 'q=' 
        + (this.options.etId ? 'etid=' + this.options.etId : 'disp.sn='+  this.options.dispSN )
        + (this.options.etIds ? '|etids=' + this.options.etIds : '')
        + (sFilterCriter ? '|' + sFilterCriter : '' )
        + '|o=js' 
        + (this.options.attrId ? '|'+encodeURIComponent(this.options.attrId) + '`sw`' + p_sQueryString.substring(1) : '');
  },
  
  reset: function(event) {
    this.oInput.value = "";
    this.element.enterValue = null;
    this.element.value = this.element.getAttribute('voidValue');
    this.choice.firstChild.textContent = "";
    this.switchToEditMode();
  },
  /**
   * Appelée sur retour xmlHttpRequest ou directement depuis edit.js::showChoiceList().
   * Transforme le xml en une liste <ul>/<li>
   * @param request   requete Ajax
   * @param p_xList   noeud xml de la liste, fournie directement en alternative à un retour de requete (ex: appel depuis
   *    edit.js::showChoiceList()
   */
  onComplete: function(request, p_xList) {
    var oDoc = request ? getDocElement(request.responseText) : null;
    var oList = oDoc ? oDoc.selectNodeSet("//"+this.options.baseTag+"l/"+this.options.baseTag) : p_xList;

    var sResponse;
    var bAutoSel = this.options.autoSelect; // mémorise la config
    if (!oList || oList.length==0) {
      if (this.oInput.sMsg_noChoice) sResponse = "<ul><li style=\"white-space: nowrap\">" + this.oInput.sMsg_noChoice
        + "</li></ul>"; 
      else sResponse = "<span><span>[pas de résultat]</span></span>"; // "<span />";
      this.options.autoSelect = false; // pour désactiver la sélection auto à coup sûr ; rétabli ci-dessous après updateChoices()

    } else {
      sResponse = "<ul>";
      for (var i=0, iL=oList.length; i<iL; i++) {
        var oTmpNode = oList.item(i);
        sResponse += "<li style=\"white-space: nowrap\" id=\"" + oTmpNode.getAttribute("id") + "\" oDataNode=\""
          + (oTmpNode+"").replace(/'|"/g,"&quot;").replace(/\n/g," ") + "\">"
          + builEntityLibFromNode(oTmpNode) + "</li>";
      }
      sResponse += "</ul>";
    }
    this.updateChoices(sResponse);
    this.options.autoSelect = bAutoSel;
  }
 });
 

// =========================================================================
// @class
// O2.DoubleList - Liste à alimentation par liste secondaire
//
// @param 
// : p_sInputName    id (littéral) de l'élément du formulaire auquel la liste est attachée
// : p_msInitialList  tableau des valeurs initiales, sous la forme [id1,val1,id2,val2,...]
// =========================================================================

// TODO : renommage à généraliser
O2.DoubleList = Class.create();

O2.DoubleList.findByInputName = function(p_sInputName, p_oContainer) {
  var oInput = $O2(p_sInputName, p_oContainer);
  return oInput[sDBL_LIST_PREFIX];
}

O2.DoubleList.prototype = {
  initialize: function(p_sInputName, p_sItemClass, p_msInitialList) {
    this.m_eMainContainer = $O2(sDBL_LIST_PREFIX+"_"+p_sInputName);
    this.m_eInput = $O2(p_sInputName);
    this.m_sItemClass = p_sItemClass;
    this.m_eMainContainer[sDBL_LIST_PREFIX] = this;
    this.m_eInput[sDBL_LIST_PREFIX] = this; // pour récup de cet instance à partir de l'objet DOM
    this.m_eList = this.m_eMainContainer.findChildById(sDBL_LIST_PREFIX+"2_"+p_sInputName, "DIV");
    this.m_eSearchList = this.m_eMainContainer.findChildById(sDBL_LIST_PREFIX+"1_"+p_sInputName, "DIV");
    if (p_msInitialList) {
      for (var i=0, l=p_msInitialList.length; i<l; i+=2) {
        this.createItem(2, p_msInitialList[i],p_msInitialList[i+1]);
      }
    }
    this.createSortable(1);
    this.createSortable(2);
  }

  // ---------- getList ----------------
  ,getList: function(p_iIdx) {
    var oList = p_iIdx==1 ? this.m_eSearchList : this.m_eList;
    return oList;
  }
  
  // ---------- getItemClass ----------------
  ,getItemClass: function() {
    return this.m_sItemClass;
  }
}

ODYDoubleList = function(p_sInputName, p_sItemClass, p_msInitialList) {
  this.m_eMainContainer = $O2(sDBL_LIST_PREFIX+"_"+p_sInputName);
  this.m_eInput = $O2(p_sInputName);
  this.m_sItemClass = p_sItemClass;
  this.m_eMainContainer[sDBL_LIST_PREFIX] = this;
  this.m_eInput[sDBL_LIST_PREFIX] = this; // pour récup de cet instance à partir de l'objet DOM
  this.m_eList = this.m_eMainContainer.findChildById(sDBL_LIST_PREFIX+"2_"+p_sInputName, "DIV");
  this.m_eSearchList = this.m_eMainContainer.findChildById(sDBL_LIST_PREFIX+"1_"+p_sInputName, "DIV");
  if (p_msInitialList) {
    for (var i=0, l=p_msInitialList.length; i<l; i+=2) {
      this.createItem(2, p_msInitialList[i], p_msInitialList[i+1]);
    }
  }
  this.createSortable(1);
  this.createSortable(2);
}

ODYDoubleList.findByInputName = function(p_sInputName, p_oContainer) {
  var oInput = $O2(p_sInputName, p_oContainer);
  return oInput[sDBL_LIST_PREFIX];
}

// ---------- getList ----------------
ODYDoubleList.prototype.getList = function(p_iIdx) {
  var oList = p_iIdx==1 ? this.m_eSearchList : this.m_eList;
  return oList;
}

// ---------- getItemClass ----------------
ODYDoubleList.prototype.getItemClass = function() {
  return this.m_sItemClass;
}

// ---------- getLength ----------------
ODYDoubleList.prototype.getLength = function(p_iIdx) {
  var oList = this.getList(p_iIdx);
  var iL = 0;
  if (oList.childNodes) iL = oList.childNodes.length;
  return iL;
}

// ---------- updateCount ----------------
ODYDoubleList.prototype.updateCount = function() {
  if (!this.m_eCountSpan) this.m_eCountSpan = this.m_eMainContainer.findChildById("count");
  this.m_eCountSpan.innerHTML = this.getLength(2);
}

// ---------- showMsg ----------------
ODYDoubleList.prototype.showMsg = function(p_sMsgId) {
  this.m_eMainContainer.findChildById(p_sMsgId).style.display = "block";
}

// ---------- hideMsg ----------------
ODYDoubleList.prototype.hideMsg = function(p_sMsgId) {
  this.m_eMainContainer.findChildById(p_sMsgId).style.display = "none";
}
// ---------- createItem ----------------
ODYDoubleList.prototype.createItem = function(p_iIdx, p_sValId, p_sValLib) {
  var oList = this.getList(p_iIdx);
  var oDiv = document.createElement("div");
  var sId = sDRAG_PREFIX + p_sValId;
  var sHtml = '<img id="add" onclick="parentNode[sDBL_LIST_PREFIX].transfertItem(parentNode)" src="/portail/img/max.gif">'
    + p_sValLib
    + '<img id="del" onclick="parentNode[sDBL_LIST_PREFIX].removeItem(2,parentNode)" src="/portail/img/min.gif">';
  oDiv.innerHTML = sHtml;
  oDiv.setAttribute("class", this.getItemClass());
  oDiv.setAttribute("id", sId);
  oDiv.listenTo("mousedown", function(event) { this.style.cursor='-moz-grabbing'; }, false); 
  oDiv.listenTo("mouseup"  , function(event) { this.style.cursor='-moz-grab';     }, false);
  this.addItem(p_iIdx, oDiv);
}

// ---------- containItem ----------------
ODYDoubleList.prototype.containItem = function(p_iIdx, p_sValId) {
  var oList = this.getList(p_iIdx);
  var sId = p_sValId.match(sDRAG_PREFIX+".*") ? p_sValId : sDRAG_PREFIX + p_sValId;
  for (var i=0,vChild=oList.childNodes, l=vChild.length; i<l;i++) {
    if (sId==vChild[i].id) return true;
  }
  return false;
}

// ---------- addItem ----------------
ODYDoubleList.prototype.addItem = function(p_iIdx, p_eDraggableDiv) {
  var oList = this.getList(p_iIdx);
  if (oList.childNodes) { // insertion dans l'ordre alphabétique
    var oNext;
    var sTxt = p_eDraggableDiv.textContent;
    for (var i=0,vChild=oList.childNodes, l=vChild.length; i<l;i++) {
      var oDiv = vChild[i];
      if (sTxt>oDiv.textContent) continue;
      oNext = oDiv;
      break;
    }
    oList.insertBefore(p_eDraggableDiv, oNext);

  } else oList.appendChild(p_eDraggableDiv);

  var oDrag = new Draggable(p_eDraggableDiv, {revert:true});
  oDrag[sDBL_LIST_PREFIX] = this;
  p_eDraggableDiv[sDBL_LIST_PREFIX] = this;
  p_eDraggableDiv["drag"] = oDrag;
  if (p_iIdx==2) {
    this.addValue(p_eDraggableDiv);
    // this.updateCount();

  } else {
    if (!oList["isShown"]) this.showHide();
    if (this.getLength(1)==1) this.showMsg("msgWhenSingleChoice");
    else this.hideMsg("msgWhenSingleChoice");
  }
}

// ---------- removeItem ----------------
ODYDoubleList.prototype.removeItem = function(p_iIdx, p_eDraggableDiv) {
  var oList = this.getList(p_iIdx);
  var oDrag = p_eDraggableDiv["drag"];
  delete p_eDraggableDiv;
  oList.removeChild(p_eDraggableDiv);
  oDrag.destroy();
  if (p_iIdx==2) {
    this.removeValue(p_eDraggableDiv);
    if ( !this.containItem(1,p_eDraggableDiv.id) ) this.addItem(1, p_eDraggableDiv);
  }
}

// ---------- transfertItem ----------------
ODYDoubleList.prototype.transfertItem = function(p_eDraggableDiv) {
  if ( !this.containItem(2,p_eDraggableDiv.id) ) {
    this.removeItem(1, p_eDraggableDiv);
    // ajout dans la deuxième si non présent
    this.addItem(2, p_eDraggableDiv);
  }
}

// ---------- transfertFirstItem ----------------
ODYDoubleList.prototype.transfertFirstItem = function() {
  var oList = this.getList(1);
  var oDiv = oList.firstChild;
  if (!oDiv) return;
  this.transfertItem(oDiv);
}

// ---------- clearList ----------------
ODYDoubleList.prototype.clearList = function(p_iIdx) {
  var oList = this.getList(p_iIdx);
  while( oList.firstChild ) {
    var oDiv = oList.firstChild;
    this.removeItem(p_iIdx, oDiv);
  }
}

// ---------- addValue ----------------
ODYDoubleList.prototype.addValue = function(p_eDraggableDiv) {
  var sValId = p_eDraggableDiv.id.substring(sDRAG_PREFIX.length);
  this.m_eInput.value = (this.m_eInput.value||"").addItemToList(ODYForm.sVALUE_SEP, sValId);
  this.updateCount();
}

// ---------- removeValue ----------------
ODYDoubleList.prototype.removeValue = function(p_eDraggableDiv) {
  var sValId = p_eDraggableDiv.id.substring(sDRAG_PREFIX.length);
  this.m_eInput.value = (this.m_eInput.value||"").removeItemFromList(ODYForm.sVALUE_SEP, sValId);
  this.updateCount();
}

// ---------- createSortable ----------------
ODYDoubleList.prototype.createSortable = function(p_iIdx) {
  var sInputName = this.m_eInput.id;
  var msOptions = {
        dropOnEmpty:true
       ,containment:[sDBL_LIST_PREFIX +"1_"+sInputName, sDBL_LIST_PREFIX +"2_"+sInputName]
       ,constraint:true
       ,onDrop: function(p_eDraggableDiv, p_oDroppable) {
         var oDblList = p_eDraggableDiv[sDBL_LIST_PREFIX];
         if (p_iIdx==1) oDblList.removeValue(p_eDraggableDiv);
         else oDblList.addValue(p_eDraggableDiv);
        }
      };
  if (2==p_iIdx) msOptions["handle"]='handle';
  // crée un Sortable qui est stocké dans Sortable.sortables, indexé par l'id de l'élément
  Sortable.create(sDBL_LIST_PREFIX + p_iIdx + "_" + sInputName, msOptions);
}

// ---------- showHide ----------------
ODYDoubleList.prototype.showHide = function() {
  var oList = this.getList(1);
  var oContainer = oList.parentNode;
  var oImg = this.m_eMainContainer.findChildById("onglet_img");
  if(oContainer.style.display=='block') {
    oContainer.style.display='none';
    oImg.src='/com/images/fleche-grise-right.png';
    this.showMsg("msgWhenClosed");
    oList["isShown"]=false;

  } else {
    oContainer.style.display='block';
    oImg.src='/com/images/fleche-grise-left.png';
    this.hideMsg("msgWhenClosed");
    oList["isShown"]=true;
  }
}

// ---------- showHideFromLink ----------------
ODYDoubleList.showHideFromLink = function(p_oElem) {
  var oCont = p_oElem.parentNode;
  while (oCont!=oCont.parentNode && !(oCont.className=="mdblconteneur" || oCont.className=="mdblconteneur_large") ) oCont = oCont.parentNode;
  oCont[sDBL_LIST_PREFIX].showHide();
}
