
function getCumulativeOffset(element, defaultCoords, parentNode)
{
    if (!element)
    {
        return {"left": 0, "top": 0};
    }
    
    var defaultCoords = defaultCoords || {};
    
    element.style.zoom = 1;

    var left = element.offsetLeft + (defaultCoords["left"]*1 || 0),
        top = element.offsetTop + (defaultCoords["top"]*1 || 0),
        parent = element.offsetParent;

    while(parent && parent != parentNode)
    {
        left += parent.offsetLeft;
        top += parent.offsetTop;
        parent = parent.offsetParent;
    }

    return {"left": left, "top": top};
};

//
// Placeholder
// Un champ de formulaire est pré-rempli
// avec le type devaleur qui est attendu
//
var placeholderElements = [];
var placeholderIndice = [];
var Placeholder = function(elm, oParams)
{
    if (!elm || !elm.htmlFor || !elm.form)
    {
        return false;
    }
    
    var oThis = this;
    var oParams = oParams || {};
    var tagDefault = "title";
    var classDefaultElm = "placeholder-defaultElm";
    
    var inputElm = document.getElementById(elm.htmlFor);
    if (!inputElm || inputElm.form != elm.form)
    {
        return false;
    }

    /*
     * méthode: Placeholder.isEmpty: 
     * @value: chaine de caratère à tester
     * --
     * Test si la valeur est vide ou pas
     * Retourne la valeur si elle n'est pas vide
     * Sinon retourne: false
     */
    var isEmpty = function(value)
    {
        return !(value || false);
    };

    /*
     * méthode: Placeholder.setValue: 
     * @elm: element du DOM concerné
     * @value: valeur à affecter au 1er argument
     * --
     * Affecte une valeur à un élément de formulaire
     */
    var setValue = function(elm, value)
    {
        if (!elm || elm.value == value)
        {
            return false;
        }

        elm.value = value;
        return true;
    };
    /*
     * méthode: Placeholder.getDefaultValue: 
     * @elm: element du DOM concerné
     * --
     * Récupère la valeur du champ label si précisé
     * Sinon récupère le title du champ de formulaire
     */
    var getDefaultValue = function(elm, labelElm)
    {
        if (!elm)
        {
            return false;
        }
        
        // Assignation de la valeur par défaut
        if (typeof elm.placeholderValue == "undefined")
        {
            var test = (tagDefault == "label" && typeof labelElm != "undefined") ? (labelElm.firstChild.nodeValue || "") : elm["title"];
            elm.placeholderValue = test || "";
        }
        
        return elm.placeholderValue || "";
    };

    // Comportement au focus de l'élément
    // On supprime la valeur par défaut si elle est affichée
    var focusHandler = function()
    {
        var defaultValue = getDefaultValue(this);
        if (this.value == defaultValue || jQuery(this).hasClass("defaultValue"))
        {
            jQuery(this).removeClass("defaultValue");
            setValue(this, "");
        }
    }

    // Comportement au "blur" de l'élément
    // On réecrie la valeur par défaut si aucune valeur n'a été saisie
    var blurHandler = function()
    {
        var defaultValue = getDefaultValue(this);
        if (isEmpty(this.value))
        {
            jQuery(this).addClass("defaultValue");
            setValue(this, defaultValue);
        }
    }

    // Comportement à la validation du formulaire
    // Ne pas soumettre la valeur par défaut si elle est encore présente dans le champ
    var submitHandler = function()
    {

	//alert("submit handler noelie");

        if (!this || !elm)
        {
            return true;
        }

        var isValid = !(elm.value == getDefaultValue(elm));
        if (isValid && typeof this.submitHandler == "function")
        {
            return this.submitHandler();
        }
        return isValid;
    }
    // Initialisation des comportements
    // et propriétés
    var init = function(elm, labelElm, oParams)
    {
        if (typeof elm.id == "undefined" || !elm.id)
        {
            return false;
        }
        
        // récupère la valeur du label par défaut
        if (oParams["defaultValue"] == "label")
        {
            tagDefault = oParams["defaultValue"];
            jQuery(labelElm).addClass(classDefaultElm);
        }
        
        var placeholderValue = getDefaultValue(elm, labelElm);
        if (!elm || isEmpty(placeholderValue))
        {
            return false;
        }
        
        jQuery(elm.form).addClass("placeholder");
        
        /*
        // Assignation de la valeur par défaut
        elm.placeholderValue = placeholderValue;
        */

        // On rempli le champ s'il n'a pas de valeur
        if (isEmpty(elm.value) || elm.value == placeholderValue)
        {
            jQuery(elm).addClass("defaultValue");
            setValue(elm, placeholderValue);
        }

        // Comportements
        jQuery(elm).bind("focus", focusHandler);
        jQuery(elm).bind("blur", blurHandler);
        elm.form.onsubmit = submitHandler;
        
        // enregistrement
        oThis.field = elm;
        oThis.label = labelElm;
        oThis.defaultValue = placeholderValue;
        
        placeholderIndice[elm.id] = placeholderElements.length;
        placeholderElements.push(oThis);
    }

    init(inputElm, elm, oParams);

    return oThis;
    
};

/*
 * Fausses tooltips
 */
var tooltipElements = [];
var tooltipIndice = {};
var tooltip = function(element, oParams)
{
    if (typeof element == "undefined" || !element)
    {
        return false;
    }
    
    //
    // Propriétés par défaut
    //
    
    var oThis = this;
    
    var data = null;
    var container = null;
    var menu = null;
    var oParams = (typeof oParams == "object") ? oParams : {};
    
    var classRef = "infobulle";
    var classContainer = "infobulle-container";
    var classActive = "active";
    var classPosition = "topleft";
    
    //
    // Positionnement de l'infobulle:
    // 'tooltip' ne doit pas être coupé par le bord du bas de la page;
    // Inverser le sens (en y) uniquement si tootltip est entièrement visible en haut
    // +1 => correctif: tooltip se position 1px trop haut (BUG CSS)
    //
    var getCoords = function(linkElm, tooltipElm)
    {
        if (!linkElm || !tooltipElm)
        {
            return false;
        }
        
        var valign = "top", halign = "left";
        var coords = getCumulativeOffset(linkElm);
        var tooltipHeight = jQuery(tooltipElm).height(),          // hauteur de 'tooltip'
            tooltipWidth = jQuery(tooltipElm).width(),            // Largeur de 'tooltip'
            lineHeight = jQuery(linkElm).height(),                     // hauteur du 'label'
            pasVertical = 0,                                        // Espacement entre 'tooltip' et 'label'
            pasHorizontal = 0,                                     // Espacement entre 'tooltip' et le rebord de la page
            minLeft = (coords.left || 0),                            // position MIN en X de 'label'
            minTop = (coords.top || 0) + lineHeight + pasVertical,   // position MIN en Y de 'label'
            maxLeft = minLeft + tooltipWidth + linkElm.offsetWidth,                       // position MAX en X de 'label'
            maxTop = minTop + tooltipHeight;           // position MAX en Y de 'label'
        
        // Alignement "vertical"
        // Positionnemenet par rapport bas du site
        var fullHeight = tooltipHeight + pasVertical + lineHeight;
        var maxHeight = window.innerHeight || document.documentElement.clientHeight;
        if (maxTop > maxHeight)
        {
            minTop = minTop - fullHeight;
            valign = "bottom";
        }
    
        // Alignement "horizontal"
        // Positionnemenet par rapport au bord droit de la page
        var maxWidth = window.innerWidth || document.documentElement.clientWidth;
        if (maxLeft > maxWidth)
        {
            var scrollLeft = window.scrollX || document.documentElement.scrollLeft;
            minLeft = (maxWidth + scrollLeft) - (tooltipWidth + pasHorizontal);
            halign = "right";
        }
        
        return {
            minLeft: minLeft,
            minTop: minTop,
            maxLeft: maxLeft,
            maxTop: maxTop,
            position: valign + halign
        }
    };
    
    var setPosition = function(elm)
    {
        if (!oThis.link || !oThis.tooltip)
        {
            return false;
        }
        
        var coords = getCoords(oThis.link, oThis.tooltip);
        if (!coords || typeof coords != "object")
        {
            return false;
        }
        
        // Positionnement
        /*
        oThis.tooltip.style.top = coords.minTop + "px";
        oThis.tooltip.style.left = coords.minLeft + "px";
        */
        
        var class0 = "align-" + coords['position'];
        
        if (class0 && !jQuery(elm).hasClass(class0))
        {
            
            // Changement de la position de l'image
            var imgElm = jQuery(oThis.tooltip).find("img") || [];
            if (imgElm.length)
            {
                imgElm[0].src = pathImg + "calendar-arrow-" + coords['position'] + "-v3.png";
            }
            
            // Positionnement de l'infobulle
            jQuery(elm).removeClass(classPosition);
            jQuery(elm).addClass(class0);
            classPosition = class0;
        }
    }
    
    //
    // Récupération de l'infobulle:
    // l'infobulle peut etre "en dur" dans la page
    // Ou génération de celle ci à partir de l'attribut "title" du lien
    //
    var getInfobulle = function(elm)
    {
        if (typeof elm == "undefined" || !elm)
        {
            return false;
        }
        
        // récupération de l'inbulle existante
        var tmp = jQuery(container).find("." + classRef) || [];
        if (tmp && tmp.length)
        {
            return tmp[0];
        }
        
        // Récupération du texte
        data = elm["title"] || elm["alt"] || null;
        if (!data || !data.length)
        {
            return false;
        }
        elm.removeAttribute("title");
        
        // Ajout du noeud Texte
        var tmp = document.createElement("dl");
        var plop = data.split("|");
        for (var i=0, len = plop.length; i<len; i++)
        {
            var textElm = document.createElement((i == 0) ? "dt" : "dd");
            textElm.appendChild(document.createTextNode(plop[i]));
            tmp.appendChild(textElm);
        }

        // Ajout de l'image
        var img = document.createElement("img");
        img.src = pathImg + "calendar-arrow-" + classPosition + "-v3.png";
        
        var tmp0 = document.createElement("div");
        tmp0.appendChild(img);
        tmp0.appendChild(tmp);
        
        // Ajout de l'tooltip au document
        container.appendChild(tmp0);
        jQuery(tmp0).addClass(classRef);
        
        return tmp0;
    };
    
    var handleMouseover = function()
    {
        //alert("mouseover!");
        setPosition(this);
        jQuery(this).addClass(classActive);
    }
    var handleMouseout = function()
    {
        jQuery(this).removeClass(classActive);
    }
    
    // Initialisation des comportements
    // et propriétés
    var init = function(element, oParams)
    {
        if (typeof element == "undefined")
        {
	    //alert("1");
            return false;
        }
        if (typeof element["title"] != "string" || !element["title"].length)
        { 
            //alert("2");
            //return false;
        }
        if (typeof element.parentNode == "undefined" || !element.parentNode)
        {
            //alert("3");
            return false;
        }
        
        // Indentification du container
        container = element.parentNode;
        //alert(container);        

        // Création du bloc tooltip
        var tooltip = getInfobulle(element, container);
        if (!tooltip)
        {
            return false;
        }
        
        /*
        var setMenu = oParams["menu"] || false;
        if (setMenu && setMenu == true)
        {
            var menu = new oMenu(element, tooltip, {"activeEvent": "mouseover"});
        }
        oThis.menu = menu || null;
        */
        
        jQuery(container).addClass(classContainer);
        jQuery(container).bind("mouseover", handleMouseover);
        jQuery(container).bind("mouseout", handleMouseout);
        
        // enregistrement
        if (!tooltip.id)
        {
            tooltip.id = "tooltip-" + tooltipElements.length;
        }
        tooltipIndice[tooltip.id] = tooltipElements.length;
        tooltipElements.push(tooltip);
        
        oThis.tooltip = tooltip;
        oThis.link = element;
        oThis.container = container;
    }
    
    init(element, oParams);
    
    return oThis;
}

//
// Composant: Menu
//
var menuElements = [];
var menuIndice = {};
var oMenu = function(linkElm, menuElm, oParams)
{
    if (!linkElm || !linkElm.tagName || !menuElm || !menuElm.tagName || !menuElements)
    {
        return false;
    }
    
    var menu = menuElm, link = linkElm;
    var oParams = oParams || {};    
    var oRef = this;
    
    var classActive = "active";
    var classContainer = "submenu_container";
    
    var container = menu.parentNode || null;
    var repositionnement = null;
    
    /*
     * Private method: setElmId
     * Génére un ID en fonction du nombre des "menu" stocké dans la page
     */
    var setElmId = function(elm, defaultId)
    {
        if (!elm || !defaultId || !defaultId.length)
        {
            return false;
        }
        
        if (typeof elm.id == "undefined" || !elm.id)
        {
            return (document.getElementById(defaultId)) ? false : defaultId;
        }
        
        return elm.id;
    }
    
    /*
     * Private method: isMenuActive
     * Vérifie si le menu est affiché / ou pas
     */
    var isMenuActive = function()
    {
        return jQuery(container).hasClass(classActive) || false;
    }
    
    var getContainerElm = function(elm)
    {
        return container;
    }
    
    /*
     * Public method: show
     * Affiche le menu
     */
    oRef.show = function(elm)
    {
        if (repositionnement)
        {
            var pos = getCumulativeOffset(link, {"top": link.offsetHeight}, container);
            
            elm.style.left = pos.left + "px";
            elm.style.top = pos.top + "px";
        }
        
        jQuery(container).addClass(classActive);
    }
    
    /*
     * Public method: hide
     * Masque le menu
     */
    oRef.hide = function(elm)
    {
        jQuery(container).removeClass(classActive);
    }
    
    /*
     * Affichage au focus   
     * Masquage à la perte du focus du lien principal 
     * (si le menu n'est pas en survol)
     */
    var handleActiveOnglet = function(e)
    {
        if (typeof e.type == "string" && e.type == "click")
        {
            e.preventDefault();
        }
        
        // Bug Safari + Opera: pas de focus sur le onclick d'un élément
        if (typeof this.isFocus == "undefined" || !this.isFocus)
        {
            this.focus();
        }
        
        // Afficher le menu s'il n'est pas visible
        if (!isMenuActive())
        {
            oRef.show(menu); 
        }
        
        return false;
    };
    
    /*
     * handleFocusOnglet
     * Activation du lien
     */
    var handleFocusOnglet = function()
    {
        this.isFocus = true;
    };
    
    /*
     * handleBlurOnglet
     * Désactivaton du lien
     */
    var handleBlurOnglet = function()
    {
        this.isFocus = false;
        
        if (isMenuActive())
        {
            if (menu && !menu.active)
            {
                oRef.hide(menu);
            }
        }
    };
    
    /*
     * Sous menu: 
     * menu.active: Peut-on ou pas masquer le sous menu ?
     */
    var handleHoverMenu = function()
    {
        this.active = true;
    };
    var handleOutMenu = function()
    {
        this.active = false;
    };
    
    // Un click sur le menu, et le menu se ferme
    // Si on click sur un lien du menu, le lien s'exécute, puis le menu se ferme
    var handleClickMenu = function(e, oMenu)
    {
        oRef.hide(this);
    };
    
    
    // Génération des id pour les éléments DOM utilisés dans le composant
    var menuId = setElmId(menu, "menu_menu" + menuElements.length);
    var linkId = setElmId(link, "menu_link" + menuElements.length);
    if (!menuId || !linkId)
    {
        return false;
    }
    
    // On déplace le menu vers un container qui permettra au menu 
    // de ne pas être masqué par d'autres éléments
    if (oParams && oParams["container"])
    {
        container = oParams["container"];
        repositionnement = true;
        container.appendChild(menu);
    }
    jQuery(container).addClass(classContainer);
    
    // Assignation des ID
    menu.id = menuId;
    link.id = linkId;
    
    // Comportement du lien
    jQuery(link).bind(oParams["activeEvent"] || "click", handleActiveOnglet);
    jQuery(link).bind("focus", handleFocusOnglet);
    jQuery(link).bind("blur", handleBlurOnglet);
    
    // Comportement du menu
    jQuery(menu).bind("mouseover", handleHoverMenu);
    jQuery(menu).bind("mouseout", handleOutMenu);
    jQuery(menu).bind("mouseup", handleClickMenu);
    
    // Stockage des propriétés de l'élément
    oRef["container"] = container;
    oRef["link"] = link;
    oRef["menu"] = menu;
    oRef["menu"].active = false;
    
    // Stockage global de l'élément
    menuElements.push(oRef);
    
    return oRef;
}


//
// Fenêtre de connexion
// FIXME: changer le mode de ciblage avec jQUery
// FIXME: changer le fctionnement
// FIXME: ajouter la methode: saveWindow
// FIXME: ajouter la methode: createWindow
//

var allWindows = [];
var allWindowsIndex = {};
var windowElm = function(elm, oParams)
{
    if (typeof elm == "undefined")
    {
        return false
    }
    
    //
    // Propriétés
    //
    var oThis = this;
    var oParams = oParams || {};
    
    var classActive = "active";
    var classContainer = "lightbox-container";
    var classBackground = "lightbox-background";
    var classHeader = "lightbox-header";
    var classContent = "lightbox-content";
    var classCloseButton = "button-close";
    var textCloseWindow = "Fermer la fenêtre";
    
    var windowContainer = null;
    var contentElm = null;
    var openLinks = null;
    var closeLinks = null;
    
    //
    // Affichage de la fenêtre
    //
    var openWindow = function(e)
    {
        if (!windowContainer)
        {
            return false;
        }
        
        focusWindow(windowContainer);
        
        windowContainer.style.height = parseInt(document.body.offsetHeight) + "px";
        jQuery(windowContainer).addClass(classActive);
        
        e.stopPropagation();
        e.preventDefault();
    }
    
    //
    // On scroll pour voir la fenêtre en haut de la page
    //
    var focusWindow = function(elm)
    {
        if (!elm || elm.nodeType != 1)
        {
            return false;
        }
        /*
        if (!elm.ownerDocument || !elm.ownerDocument.documentElement)
        {
            return false;
        }
        */
        
        var minTop = 58;
        var elm = jQuery(elm);
        
        elm.focus();
        
        elm.css("height", parseInt(document.documentElement.scrollHeight || 0) + "px");
        jQuery(contentElm).css("top", parseInt((jQuery(document).scrollTop() < minTop) ? minTop : jQuery(document).scrollTop() + minTop) + "px");
    }
    
    //
    // Fermeture de la fenêtre
    // !!! le bouton ne doit pas comporter d'image, sinon il ne fonctionne pas
    //
    var closeWindow = function(e)
    {
        var targetElm = e.target || e.srcElement;
        if (targetElm && targetElm == this)
        {
            if (!windowContainer)
            {
                return false;
            }
            
            jQuery(windowContainer).removeClass(classActive);
            jQuery(windowContainer).blur();
            
            e.stopPropagation();
            e.preventDefault();
        }    
    }
    
    //
    // Instanciation/récupération 
    // des liens d'ouverture/fermeture de la fenêtre
    //
    var setOpenElm = function(elm)
    {
        jQuery(elm).bind("click", openWindow);
    }
    var getOpenElements = function(elm)
    {
        return openLinks || [];
    }
    var setCloseElm = function(elm)
    {
        jQuery(elm).bind("click", closeWindow);
    }
    var getCloseElements = function(elm)
    {
        return closeLinks || [];
    }
    
    //
    // Génère l'ossature de la lightbox
    //
    var createWindow = function(elm, id)
    {
        if (!elm)
        {
            return false;
        }
        
        // Création du parent
        var containerElm = document.createElement("div");
        jQuery(containerElm).addClass(classContainer);
        if (id && id.length && !document.getElementById(id))
        {
            containerElm.id = id;
        }
        
        // Création du fond
        var backgroundElm = document.createElement("span");
        jQuery(backgroundElm).addClass(classBackground);
        containerElm.appendChild(backgroundElm);
        
        // Création du contenu
        var contentElm = document.createElement("div");
        jQuery(contentElm).addClass(classContent);
        containerElm.appendChild(contentElm);
        
        // Création du header
        var headerElm = document.createElement("p");
        jQuery(headerElm).addClass(classHeader);
        
        var linkClose = document.createElement("a");
        linkClose.title = textCloseWindow;
        jQuery(linkClose).addClass(classCloseButton);
        headerElm.appendChild(linkClose);
        contentElm.appendChild(headerElm);
        
        // Ajout d'un contenu particulier
        contentElm.appendChild(elm);
        
        return containerElm;
    }
            
    //
    // Stockage de la fenêtre dans la page
    //
    var saveWindow = function()
    {
        if (!windowContainer)
        {
            return false;
        }
        
        // Déclaration des éléments publics
        oThis.element = windowContainer;
        oThis.getOpenLink = getOpenElements;
        oThis.getCloseLink = getCloseElements;
        
        // Le 2nd paramètre sert à savoir 
        // si le lien est ajouté après l'initialisaton ou aps
        this.setOpenLink = function(elm)
        {
            setOpenElm(elm, true);
        }
        this.setCloseLink = function(elm)
        {
            setCloseElm(elm, true);
        }
        
        // Identification de l'objet
        if (!windowContainer.id)
        {
            windowContainer.id = "windowElm-" + allWindows.length;
        }
        
        // Sauvegarde de l'index
        allWindowsIndex[windowContainer.id] = allWindows.length;
        
        // Sauvegarde de l'objet
        var plop = {};
        plop[windowContainer.id] = oThis;
        allWindows.push(plop);
        
        /*
        console.log(windowContainer.id)
        console.log(allWindowsIndex[windowContainer.id])
        console.log(plop)
        */
    }
    
    //
    // Initialisation de la fenetre
    //
    var init = function(elm, oParams)
    {
        // Création de la fenêtre si elle n'existe pas
        if (!elm)
        {
            var content = oParams["content"] || null;
            if (content && typeof content.nodeType == "undefined")
            {
                content = content[0];
            }
            var elm = createWindow(content, oParams["id"] || null);
        }
        if (!elm)
        {
            return false;
        }
            
        // Récupération du contenu
        contentElm = jQuery(elm).find("." + classContent) || null;
        if (!contentElm)
        {
            return false;
        }
        
        windowContainer = elm;
        contentElm = contentElm[0];
        
        // Récupération des élements
        backgroundElm = jQuery(windowContainer).find("." + classBackground);
        closeLinks = jQuery(windowContainer).find("." + classCloseButton);
        if (typeof oParams["links"] == "object")
        {
            openLinks = oParams["links"];
        }
        
        // La fenêtre doit être à la racine du document
        if (windowContainer.parentNode != document.body)
        {
            document.body.appendChild(windowContainer);
        }
        
        //
        // Evenements
        //
        
        jQuery(windowContainer).bind("focus", focusWindow);
        backgroundElm.bind("click", closeWindow);
        
        // Boutons Ouvrir
        for (var i=0, len=openLinks.length; i<len; i++)
        {
            if (typeof openLinks[i] != "undefined" && openLinks[i])
            {
                jQuery(openLinks[i]).bind("click", openWindow);
            }
        }
        
        // Boutons Fermer
        for (var i=0, len=closeLinks.length; i<len; i++)
        {
            if (typeof closeLinks[i] != "undefined" && closeLinks[i])
            {
                jQuery(closeLinks[i]).bind("click", closeWindow);
            }
        }
                
        // Stockage
        saveWindow();

    }
    
    init(elm, oParams || {});
    
    return oThis;
}



