var DOM_VER = "$Revision: 1.26 $";

var ElementUtils = {
  /** retrun true si cet element est toujours dans le flux html */
  isValid: function(element) {
    var oDoc = element.ownerDocument;
    var oParent = element;
    while (oParent.parentNode) oParent = oParent.parentNode;
    return (oParent==oDoc);
  },
  getContainer: function(element){
    return ODYCont.findContainer(element);
  },

  //------------------ findDirectChildById ------------------
  // recherche d'element par id dans les enfants direct de cet element
  findDirectChildById : function(element, p_sId) {
    return findDirectChildByExpr("#"+p_sId);
  },

  //------------------ findDirectChildByExpr ------------------
  // recherche d'element par id dans les enfants direct de cet element
  findDirectChildByExpr : function(element, p_sExpr) {
    return element.childElements().find(function(s) { return s.match(p_sExpr)});
  },

  //------------------ findChildById ------------------
  // recherche d'element par id dans les descendants de cet element
  // ATTENTION : le nom est erroné, en fait c'est une recherche dans tous les DESCENDANTS, pas seulement les enfants directes
  findChildById : function(element, p_sId, p_sTagName, p_bInRecusion) {        
    if (p_sId==element.id) return $(element);
    var oNode = element
    // s'il n'existe pas d'élément avec cet id, exit (RSI : 02/09/08 : optimisation réelle !! ne pas supprimer)
    var oDoc = oNode.ownerDocument;
    var oFirstFound = oDoc.getElementById(p_sId);
    if (!oFirstFound) return;
    // verif si ce premier élément trouvé est le bon        
    var oParent = oFirstFound;
    do {
      oParent = oParent.parentNode;
      // correction suite bug avec Espace salarié : avec $O2() boucle à l'infini
      if (oParent==oNode) return $(oFirstFound); 
    } while (oParent!=oDoc)
    
    // si pas le bon (ie. il y a plusieurs élément avec le même Id) => recherche parmi les noeuds fils de cet élément
    var bRecursive = !p_sTagName;
  
    var nodes = p_sTagName ? oNode.getElementsByTagName(p_sTagName) : oNode.childNodes ;
    var oResult;
    // première itération pour rech parmi les enfants
    for (var i=0, l = nodes.length; i <l; i++) {
      var oDOM = nodes[i];
      if (oDOM.nodeType!=1) continue;
      if (oDOM.id==p_sId) { oResult = oDOM; break; }
    }
    
    // syntax error sous IE7 voir methodized() dans prototype.js ligne 336 : utilisé pour compléter findChildById()
    if (Prototype.Browser.IE) return $O2(oResult);
    
    // si pas trouvé et récursif demandé, rech plus profond
    if (!oResult && bRecursive) {
      for (var i=0, l = nodes.length; i <l; i++) {
        var oDOM = nodes[i];
        if (oDOM.nodeType!=1) continue;
        var oDOMc = oDOM.findChildById(p_sId, p_sTagName, true);
        if (oDOMc) { oResult = oDOMc; break; }
      }
    }
    // if (oResult && !p_bInRecusion && console) console.log("findChildById: " + p_sId + " : " + iFCBY + " calls");
    return $O2(oResult);
  },

  //------------------ findBrotherById ------------------
  // recherche d'element par id contenu dans le meme container
  findBrotherById : function(element, p_sId, p_sTag){
    return element.getContainer().findChildById(p_sId, p_sTag, true);
  },

  //------------------ findParentById ------------------
  findParentById : function(element, p_sId){
    var oDOM = element;
    while (oDOM.parentNode && oDOM.parentNode!=oDOM) {
      oDOM = oDOM.parentNode;
      if (oDOM.id && oDOM.id==p_sId) return oDOM;
    }
    return;
  },

  //------------------ findParentByTagName ------------------
  /**
   * @param p_sTagNamePattern le tag parent cherché
   * @return l'objet DOM ayant le tag
   */
  findParentByTagName : function(element, p_sTagNamePattern){
    var reg=new RegExp(p_sTagNamePattern, "gi");
    var oDOM = element;
    while (oDOM.parentNode && oDOM.parentNode!=oDOM) {
      oDOM = oDOM.parentNode;
      if (oDOM.tagName && oDOM.tagName.match(reg)) return oDOM;
    }
    return;
  },
  findBrotherByDispiId : function(element, p_sId){
    var oNode = element.getContainer();
    return oNode.findChildByDispiId(p_sId);
  },
  findChildByDispiId : function(element, p_sId, p_sTag){
    var nodes = p_sTag ? element.getElementsByTagName(p_sTag) : element.childNodes ;
    var oResult;
    for (var i=0, l = nodes.length; i <l; i++) {
      var oDOM = nodes[i];
      if (oDOM.nodeType!=1) continue;
      if (oDOM.getDisplayItemId()==p_sId) return oDOM;
      var oDOMc = oDOM.findChildByDispiId(p_sId, p_sTag);
      if (oDOMc) return oDOMc;
    }
    return;
  },
  getAttributeId: function(element){ return element.getAttribute("attributeId"); }                  ,
  getAttributeName: function(element){ return element.getAttribute("attributename"); }              ,
  getDataItemId: function(element){ return element.getAttribute("dataItemId"); }                    ,
  getDisplayId: function(element){ return element.getAttribute("dispId"); }                         ,
  getDisplayItemId: function(element){ return element.getAttribute("dispiId"); }                    ,
  getCondition    : function(element){ return element.getAttribute("cond"); }                       ,
  getLinketETId   : function(element){ return element.getAttribute("linkETId"); }                   ,
  getLastSearched : function(element){ return element.getAttribute("lastSearched"); }               ,
  setLastSearched : function(element, p_s){ return element.setAttribute("lastSearched",p_s); }      ,

  //------------------ listenTo ------------------
  /* l'interet de listenTo est de conserver la trace des listener enregistrés => visibles dans showLink() de debug.js */
  listenTo        : function(element, name, observer, useCapture) {
    if (!element.listeners) element.listeners = [];
    element.listeners.push([name, observer, useCapture]);
    Event.observe(element, name, observer);
  },
  //------------------ removeListeners ------------------
  /** enlève tous les listeners pour l'action indiquée par name */
  removeListeners  : function(element, name) {
    if (!element.listeners) return;
    var moList = [];
    for (var i=0, l = element.listeners.length; i <l; i++) {
      var moL = element.listeners[i];
      if (moL[0]!=name) {
        moList.push(moL);
        continue;
      }
      var observer =  moL[1];
      Event.stopObserving(element, name, observer);
    }
    element.listeners = moList.length>0 ? moList : false;
  },
  //------------------ clearListeners ------------------
  clearListeners  : function(element) {
    if (!element.listeners) return;
    for (var i=0, l = element.listeners.length; i <l; i++) {
      var moL = element.listeners[i];
      var  name = moL[0];
      var observer =  moL[1];
      Event.stopObserving(element, name, observer);
    }
    element.listeners = false;
  },
  // surcharge de la méthode définie dans prototype
  show: function(element, p_sStyle, p_iZIndex) {
    var oE = $O2(element);
    var sStyle = p_sStyle ? p_sStyle : 'block';
    
    // maj du style ssi style indiqué explicitement en paramètre ou que style actuel est "none", 
    // sinon laisse en l'état (NB: remettre le style à '' peut cacher l'élément si celui-ci a pour style css par défaut 'none')
    if (p_sStyle || oE.getStyle('display')=='none') oE.style.display = sStyle;

    if (p_iZIndex) element.style.zIndex = p_iZIndex;
    if (element.m_bContainer) {
      element.showContainer(p_sStyle, p_iZIndex);
    }
    return element;
  },

  // l'offset par rapport à l'ancètre indiqué
  offsetFrom: function(element, ancestor) {
    var valueT = 0, valueL = 0;
    var oAncestorOffset = ancestor.cumulativeOffset();
    var oEltOffset = element.viewportOffset();
    return Element._returnOffset(oEltOffset.left-oAncestorOffset.left, oEltOffset.top-oAncestorOffset.top);
  },

  // l'offset par rapport à l'ancètre indiqué en tenant compte d'un éventuel scroll
  offsetFromIncludingScroll: function(element, ancestor) {
    var oEltOffset = element.offsetFrom(ancestor);
    return Element._returnOffset(oEltOffset.left+ancestor.scrollLeft, oEltOffset.top+ancestor.scrollTop);
  },

  // scroll le premier parent scollable trouvé pour que l'élément s'affiche en haut
  scrollToShowOnTop: function(element) {
    var oE = $O2(element);
    // recherche du premier parent scrollable
    var oScrollable = oE.parentNode;
    var sScrolableStyle = oE.ownerDocument.defaultView.getComputedStyle(oScrollable, null)["overflowY"];
    while (oScrollable && oScrollable!=oScrollable.parentNode && sScrolableStyle!="auto" && sScrolableStyle!="scroll") {
      oScrollable = oScrollable.parentNode;
      sScrolableStyle = oE.ownerDocument.defaultView.getComputedStyle(oScrollable, null)["overflowY"];
    }
    // la position voulue pour que l'élément soit en haut
    var iScrollTop = oE.offsetTop - oScrollable.offsetTop;
    // s'il n'y a pas assez de contenu ds le scrollable pour mettre l'élément en haut, on l'allonge artificiellement
    if (iScrollTop > (oScrollable.scrollHeight - oScrollable.clientHeight)) {
      var xLastElt = oScrollable.lastChild;
      while (!xLastElt.tagName || !xLastElt.visible()) xLastElt = xLastElt.previousSibling;
      var iMB = xLastElt.style.marginBottom ? parseInt(xLastElt.style.marginBottom) : 0; // la marge initiale
      xLastElt.style.marginBottom = (iMB + (oScrollable.clientHeight - (oScrollable.scrollHeight - iScrollTop))) + "px";
    }
    // positionne le haut de l'élément en haut de la div scrollable
    oScrollable.scrollTop = (oE.offsetTop - oScrollable.offsetTop);
    return element;
  }
}

Element.addMethods(ElementUtils);


// =========================================================================
// @class
// O2Exception - Erreur prévue
// =========================================================================

// ---------- <constructor> ----------------
/**
 * @param p_sMsg  message d'explication
 */
O2Exception = function(p_sMsg) {
  this.m_sMsg = p_sMsg;
}

//************************* STATIC ********************************
// séparateur pour valeurs multiples dans champ de formulaire
O2Exception.sREDIRECT_MSG = "Vous allez être redirigé vers la page d'accueil.";
O2Exception.iMaxErrorNb = 20;
O2Exception.msErrorStack = new Array();

//------------- recordError ------------------
O2Exception.recordError = function(p_sErrMsg) {
  if (O2Exception.msErrorStack.length>O2Exception.iMaxErrorNb) O2Exception.msErrorStack.shift();
  O2Exception.msErrorStack.push(p_sErrMsg);
}

//------------- errorToStr ------------------
O2Exception.errorToStr = function(p_oErr) {
  if (!p_oErr) return "";
  return "Error : "
    + "\n\t Class = " + (getClassName(p_oErr) || "<not an object>")
    + "\n\t Code  = " + (p_oErr.code || "-")
    + "\n\t Msg    = " + p_oErr
    + "\n\t Stack  = " + (p_oErr.stack || "-")
   ;
}

//------------- showErrorStack ------------------
O2Exception.showErrorStack = function(p_sErrMsg) {
  var s = "Error stack (" + O2Exception.msErrorStack.length + " errors) :\n" ;
  var i = 0;
  O2Exception.msErrorStack.each( function(p_s) {
      s += "\n" + i + "/\t" + p_s; 
      i++ ;
    });
  alert(s);
}

//************************* INSTANCE ********************************
//------------- display ------------------
O2Exception.prototype.display = function() {
  alert(this.m_sMsg + "\n\n" + O2Exception.sREDIRECT_MSG);
  navigate(sAccueil, 0 ,'home');
  return false;
}

//--------------  displayError ----------------
function displayError(p_oElem, p_sMsg) {
  var oCont = p_oElem;
  if (!ODYCont.isContainer(oCont)) oCont = oCont.getContainer();
  var oAlertDiv = oCont.findChildById("alerte");
  // masque titre "enregistrement données" et affiche titre "Erreur"
  oAlertDiv.findChildById("titreErreur","div").style.display = "";
  oAlertDiv.findChildById("titreValidation","div").style.display = "none";
  var oBtnDiv = oAlertDiv.findChildById("btnChoix","div");
  oBtnDiv.style.display = "none";
  var oMsgDiv = oAlertDiv.findChildById("msgContent","div");
  oMsgDiv.style.display = "";
  var sHTML = "";
  var oFondDiv = oCont.findChildById("fondGris","div");
  var sPrevTab = "";

  oAlertDiv.findChildById("titre","div").innerHTML = "Erreur système";
  sHTML += p_sMsg;

  oMsgDiv.innerHTML = sHTML;
  oAlertDiv.show();
  oFondDiv.show();
}
