/**
 * tlc_calendar.js
 * Version : 1.00.00
 * Derniere modif : 05/12/2007 par D@vy
 *
 * Gestion d'un calendrier en DOM permettant de selectionner une date 
 */

/*extern ajoutOnLoad */

/*
 * Notes pour tous : le format textuel standard sur le site est 'JJ/MM/AAAA'
 */ 







/**
 *  Récupère la version du navigateur Internet Explorer et la retourne.
 */   
function versionIE()
{
     var ua = navigator.userAgent.toLowerCase();
     
     versionMinor = parseFloat(navigator.appVersion); 
     if (Prototype.Browser.IE && versionMinor >= 4)
         versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) );
     versionMajor = parseInt(versionMinor);
     return versionMajor ;
}


/**
 * Crée un calendrier. 
 * 
 * @param doc Document où insérer les élements. Si non fourni, window.document
 *            sera utilisé. 
 * @param updateCallback Fonction à appeler lorsque l'utilisateur choisit sa
 *                       date. Prend en premier paramètre la date javascript
 *                       choisie et en second la date textuelle au format 
 *                       standard.
 * @param minDate Date minimum à ne pas dépasser. Date javascript ou au format
 *                textuel standard. 01/01/1800 si non fourni.
 * @param maxDate Date maximum à ne pas dépasser. Date javascript ou au format
 *                textuel standard. 31/12/2099 si non fourni.
 * @param initDate Date initiale. Date javascript ou au format textuel standard.
 *                 Si non fourni, la date du jour sera utilisée. 
 */ 

    
function TlcCalendar(doc, updateCallBack, minDate, maxDate,DateFutur) {
    
    /*
     * ATTRIBUTS
     */
    var self;
    var theDoc;
    
    var eltMainDiv;
    var eltMoisPrec;
    var eltMoisSuiv;
    var eltSelMois;
    var eltSelAnnee;
    var eltTabCells;
    var eltClose;
    
    var dateMini;
    var dateMaxi;
    var curDate;
    var curBrowseDate;
    var buttLastPosY;
    
    var theCallBack;
    
    /* Constantes de classe privées */
    var picsRootDir;
    var tabMois;
    var nbAnneesAffichables;
    var nbMaxLignesJours;
    var tabJours;
    var typicalMaxHeight;
    
    /*
     * METHODES PRIVEES
     */

    /**
     * Retourne une date javascript à partir d'une date quelconque.
     * 	 
     * @param d Date javascript ou date textuelle au format standard
     * @return Date javascript ou null en cas d'erreur	  	 
     */	 	
    function getJsDateFromAnything(d) {
        var jsDate;
        
        jsDate = null;
        if (typeof d === 'string') {
            if (d.length === 2 + 1 + 2 + 1 + 4 &&
                d.substr(2, 1) === '/' &&
                d.substr(2 + 1 + 2, 1) === '/') {
                
                jsDate = new Date(d.substr(2 + 1 + 2 + 1, 4),
                    d.substr(2 + 1, 2) - 1,
                    d.substr(0, 2)
                );
            }
        } else if (typeof d !== 'undefined' && d &&
            typeof d.getFullYear !== 'undefined') {
            jsDate = d;
        }
        
        return jsDate;
    }
    
   
    
    
    /**
     * Retourne number sous forme de chaine, paddé avec des 0
     * 
     * @param number Nombre quelconque
     * @param nbPos Nombre de caractères que doit prendre le nombre
     * @return une chaine representant le nombre                    
     */         
    function padNumberWithZeros(number, nbPos) {
        var txtNumber;
        txtNumber = number.toString();
        while (txtNumber.length < nbPos) {
            txtNumber = '0' + txtNumber;
        }
        return txtNumber;
    }
    
    /**
     * Retourne une date textuelle au format standard à partir d'une date js
     * 
     * @param d Date javascript
     * @return Date textuelle au format standard               
     */         
    function getTxtDateFromJsDate(d) {
        return padNumberWithZeros(d.getDate(), 2) + '/' +
            padNumberWithZeros(d.getMonth() + 1, 2) + '/' +
            padNumberWithZeros(d.getFullYear(), 4);
    }
    
    /**
     * Compare 2 dates javascript uniquement sur les jours / mois / années.
     * getTime() ne peut pas marcher à cause des dates < 1970     
     * 
     * @param d1 Date1
     * @param d2 Date2
     * @return Nombre inferieur à 0, egal à 0 ou superieur à 0
     *         respectivement si d1 < d2, d1 === d2 ou d1 > d2              
     */         
    function dateCompare(d1, d2) {
        var d1Y;
        var d2Y;
        var d1M;
        var d2M;
        var ret;
        
        ret = 0;
        d1Y = d1.getFullYear();
        d2Y = d2.getFullYear();
        if (d1Y === d2Y) {
            d1M = d1.getMonth();
            d2M = d2.getMonth();
            if (d1M === d2M) {
                ret = d1.getDate() - d2.getDate();
            } else {
                ret = d1M - d2M;
            }
        } else {
            ret = d1Y - d2Y;
        }
        
        return ret; 
    }
    
    /**
     * Retourne le nombre de jours dans le mois donné pour l'année donnée
     * 
     * @param year Année
     * @param month Mois (1-12)
     * @return Nombre de jours               	 
     */     	
    function getMaxDay(year, month) {
        var nb;
    
        nb = tabMois[month - 1].jours;
        if (nb === null) {
            nb = 28;
            if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
                nb = 29;
            }
        }
        return nb;
    }
    
    /**
     * Met à jour les élements du calendrier en fonction de la date courante
     * et la date de parcours courante     
     */         
    function refresh() {
        var k;
        var u;
        var eltOption;
        var curMonth;
        var curYear;
        var anneeMin;
        var anneeMax;
        var firstJourVal;
        var curDay;
        var maxDay;
        var curCell;

        /**
         * Enregistre le click sur une cellule de jour
         */                 
        function registerTdClick(td, jour) {
            td.onclick = function () {
                var newDate;
                var txtDate;
                
                newDate = new Date(curYear, curMonth, jour);

                if (dateCompare(newDate, dateMini) >= 0 &&
                    dateCompare(newDate, dateMaxi) <= 0) {
                    curDate = newDate;
                    if (theCallBack) {
                        theCallBack(curDate, getTxtDateFromJsDate(curDate));
                    }
                    self.close();
                }
            };
        }

        curYear = curBrowseDate.getFullYear();
        curMonth = curBrowseDate.getMonth();

        /* Selectionne le mois en cours */
        eltSelMois.selectedIndex = curMonth;

        /* Met à jour la liste des années */
        while (eltSelAnnee.lastChild) {
            eltSelAnnee.removeChild(eltSelAnnee.lastChild);
        }
        anneeMin = curYear - Math.floor(nbAnneesAffichables / 2);
        anneeMax = curYear + Math.floor(nbAnneesAffichables / 2);
        if (anneeMin < dateMini.getFullYear()) {
            anneeMin = dateMini.getFullYear();
        }
        if (anneeMax > dateMaxi.getFullYear()) {
            anneeMax = dateMaxi.getFullYear();
        }
        for (k = anneeMin; k <= anneeMax; k++) {
            eltOption = theDoc.createElement('option');
            eltOption.value = k;
            if (k === curYear) {
                eltOption.selected = true;
                eltOption.defaultSelected = true;
            }
            eltOption.appendChild(theDoc.createTextNode(k));
            eltSelAnnee.appendChild(eltOption);
        }
        

        /* Met à jour le tableau de cellules des jours */
        firstJourVal = (new Date(curYear, curMonth, 1)).getDay();

        curDay = 0;
        maxDay = getMaxDay(curYear, curMonth + 1);
        
        for (k = 0; k < nbMaxLignesJours; k++) {
            if (curDay <= maxDay) {
                /* Reste des jours à afficher */
                for (u = 0; u < tabJours.length; u++) {
                    curCell = eltTabCells[k][u];
    
                    if (curDay === 0) {
                        if (tabJours[u].val === firstJourVal) {
                            curDay = 1;
                        }
                    }
                    
                    if (curDay >= 1 && curDay <= maxDay) {
                        /* Jour précédemment selectionné ? */
                        if (curDay === curDate.getDate() &&
                            curMonth === curDate.getMonth() &&
                            curYear === curDate.getFullYear()) {
                            curCell.className = 'aujourdhui';
                        } else {
                            curCell.className = null;
                        }
                        curCell.firstChild.nodeValue = curDay;
                        registerTdClick(curCell, curDay);
                        curDay++;
                    } else {
                        curCell.className = 'vide';
                        curCell.firstChild.nodeValue = ' ';
                        curCell.onclick = null;
                    }
                }
                /* On raffiche la ligne si besoin */
                curCell.parentNode.style.display = '';
            } else {
                /* Plus de jours à afficher : rendre les lignes restantes 
                 * invisibles
                 */
                eltTabCells[k][0].parentNode.style.display = 'none';
            }
        }

        /* Yavait besoin de repositionner */
        if (buttLastPosY !== null) {
            eltMainDiv.style.top = 
                (buttLastPosY - eltMainDiv.clientHeight - /* marge */ 3) + 'px';
        }
    }
    
    /**
     * Construction des éléments de base si besoin
     */
    function buildBaseIfNeeded() {
        var eltTable;
        var eltTBody;
        var eltRow;
        var eltCell;
        var eltLink;
        var eltImg;
        var eltSelect;
        var eltOption;
        var k;
        
        if (!eltMainDiv) {
            /* Div conteneur princal */
            eltMainDiv = theDoc.createElement('div');
            eltMainDiv.id = 'calendrier';
            eltMainDiv.style.display = 'none';
            eltMainDiv.style.position = 'absolute';
            
            /* Barre de navigation pour les mois et années */
            eltTable = theDoc.createElement('table');
            eltTable.id = 'nav_cal';
            eltTable.cellSpacing = 0;
            eltTable.cellPadding = 0;
            eltTable.border = 0;
            
            eltTBody = theDoc.createElement('tbody');
            eltRow = theDoc.createElement('tr');
            
            /* Mois précédent */
            eltCell = theDoc.createElement('td');
            eltLink = theDoc.createElement('a');
            eltMoisPrec = eltLink;
            eltLink.href = '#';
            eltLink.onclick = function () {
                var newDate;
                var newMonth;
                var newYear;
                
                newMonth = curBrowseDate.getMonth() - 1;
                newYear = curBrowseDate.getFullYear();
                if (newMonth < 0) {
                    newMonth = 11;
                    newYear--;
                }
                
                newDate = new Date(newYear, newMonth, 1);
                if (dateCompare(newDate, dateMini) >= 0) {
                    curBrowseDate = newDate;
                    refresh();
                }
            
                return false;
            };
            eltImg = theDoc.createElement('img');
            eltImg.src = picsRootDir + 'page_prec.gif';
            eltImg.title = 'Mois précédent';
            eltLink.appendChild(eltImg);
            eltCell.appendChild(eltLink);
            eltRow.appendChild(eltCell);
            
            /* Selects des mois et des années */
            eltCell = theDoc.createElement('td');
            eltCell.className = 't2';
            eltSelect = theDoc.createElement('select');
            eltSelMois = eltSelect;
            eltSelMois.onchange = function () {
                var newDate;
                
                newDate = new Date(
                    curBrowseDate.getFullYear(),
                    eltSelMois.options[eltSelMois.selectedIndex].value,
                    1);
                    
                if (dateCompare(newDate, dateMini) >= 0 &&
                    dateCompare(newDate, dateMaxi) <= 0) {
                    curBrowseDate = newDate;
                    refresh();
                }
            };
            for (k = 0; k < tabMois.length; k++) {
                eltOption = theDoc.createElement('option');
                eltOption.value = k;
                eltOption.appendChild(theDoc.createTextNode(tabMois[k].nom));
                eltSelect.appendChild(eltOption);
            }
            eltCell.appendChild(eltSelect);
            
            eltSelect = theDoc.createElement('select');
            eltSelAnnee = eltSelect;
            eltSelAnnee.onchange = function () {
                var newDate;
                
                newDate = new Date(
                    eltSelAnnee.options[eltSelAnnee.selectedIndex].value,
                    curBrowseDate.getMonth(),
                    1);
                    
                if (dateCompare(newDate, dateMini) >= 0 &&
                    dateCompare(newDate, dateMaxi) <= 0) {
                    curBrowseDate = newDate;
                    refresh();
                }
            };
            eltCell.appendChild(eltSelect);
            eltRow.appendChild(eltCell);
            
            /* Mois suivant */
            eltCell = theDoc.createElement('td');
            eltLink = theDoc.createElement('a');
            eltMoisPrec = eltLink;
            eltLink.href = '#';
            eltLink.onclick = function () {
                var newDate;
                var newMonth;
                var newYear;
                
                newMonth = curBrowseDate.getMonth() + 1;
                newYear = curBrowseDate.getFullYear();
                if (newMonth > 11) {
                    newMonth = 0;
                    newYear++;
                }
                
                newDate = new Date(newYear, newMonth, 1);
                if (dateCompare(newDate, dateMaxi) <= 0) {
                    curBrowseDate = newDate;
                    refresh();
                }
            
                return false;
            };
            eltImg = theDoc.createElement('img');
            eltImg.src = picsRootDir + 'page_suiv.gif';
            eltImg.title = 'Mois suivant';
            eltLink.appendChild(eltImg);
            eltCell.appendChild(eltLink);
            eltRow.appendChild(eltCell);
            
            eltTBody.appendChild(eltRow);
            eltTable.appendChild(eltTBody);
            eltMainDiv.appendChild(eltTable);
            
            /* Création du tableau de cellules représentant les jours */
            eltTable = theDoc.createElement('table');
            eltTable.id = 'tb_cal';
            eltTable.cellSpacing = 0;
            eltTable.cellPadding = 0;
            eltTBody = theDoc.createElement('tbody');
            
            /* Entetes de colonnes des jours de la semaine */
            eltRow = theDoc.createElement('tr');
            for (k = 0; k < tabJours.length; k++) {
                eltCell = theDoc.createElement('th');
                eltCell.appendChild(theDoc.createTextNode(tabJours[k].abbr));
                eltRow.appendChild(eltCell);
            }
            eltTBody.appendChild(eltRow);
            
            /* Tableau de cellules des jours */
            eltTabCells = [ ];
            var u;
            for (k = 0; k < nbMaxLignesJours; k++) {
                eltRow = theDoc.createElement('tr');
                eltTabCells[k] = [ ];
                for (u = 0; u < tabJours.length; u++) {
                    eltCell = theDoc.createElement('td');
                    eltTabCells[k][u] = eltCell;
                    eltCell.className = 'vide';
                    eltCell.appendChild(theDoc.createTextNode('\u00a0'));
                    eltRow.appendChild(eltCell);
                }
                eltTBody.appendChild(eltRow);
            }
            eltTable.appendChild(eltTBody);
            eltMainDiv.appendChild(eltTable);
            
            /* Bouton "fermer" */
            eltLink = theDoc.createElement('a');
            eltClose = eltLink;
            eltLink.id = 'ferme_cal';
            eltLink.href = '#';
            eltLink.onclick = function () {
                self.close();
                return false;
            };
            eltImg = theDoc.createElement('img');
            eltImg.src = picsRootDir + 'calendar/fermer.gif';
            eltImg.title = 'Fermer la fenêtre';
            eltLink.appendChild(eltImg);
            eltMainDiv.appendChild(eltLink);
            
            /* Ajout du conteneur principal dans la page */
            theDoc.body.appendChild(eltMainDiv);
        }
    }
    
    /**
     * Ouvre ou reouvre le calendrier à la position absolue donnée
     */         
    function internalOpen(posX, posY) {
        buildBaseIfNeeded();
        curBrowseDate = curDate;
        eltMainDiv.style.left = posX + 'px';
        eltMainDiv.style.top = posY + 'px';
        if (eltMainDiv.style.display === 'none') {
            eltMainDiv.style.display = '';
            if ((versionIE() == 6) && $('pays'))
                $('pays').style.display = 'none';
        }
        refresh();
    }
    
    /*
     * METHODES PUBLIQUES
     */
    
    /**
     * Ouvre ou reouvre le calendrier à la position absolue donnée
     * 
     * @param posX abscisse du coin superieur gauche
     * @param posY ordonnée du coin superieur gauche
     */         
    this.open = function (posX, posY) {
        
        buttLastPosY = null;
        internalOpen(posX, posY);
    };
    
    /**
     * Ouvre le calendrier autour de l'élément donné. Il existe plusieurs
     * dispositions possibles.
     * 
     * @param elt Element autour duquel positionner le calendrier
     * @param pos Une des valeurs TlcCalendar.Pos* indiquant où positionner
     *            le calendrier autour de l'élement donné.
     *            PosAuto determine automatiquement le meilleur positionnement.
     *            Pour PosOver, la position sera reajustée à chaque
     *            rafraichissement des elements du calendrier (changement de
     *            mois) pour toujours se positionner au dessus de l'élement.
     * @param toggle Si vrai, ouvre ou ferme le calendrier en fonction de
     *               si il est actuellement ouvert ou fermé.     
     */         
    this.openNear = function (elt, pos, toggle) {
        var curElt;
        var xElt;
        var yElt;
        var hauteurVue;
        var debutEcranY;
        var finEcranY;
        var x;
        var y;
        
        if (toggle && eltMainDiv && eltMainDiv.style.display !== 'none') {
            self.close();
        } else {
            /* Postions du bouton */
            xElt = 0;
            yElt = 0;
            curElt = elt;
            while (curElt) {
                xElt += curElt.offsetLeft;
                yElt += curElt.offsetTop;
                curElt = curElt.offsetParent;
            }
            
            x = xElt;
            y = yElt;
            
			 /* Pas d'auto-repositionnement par défaut */
             buttLastPosY = null;
       
            
            /* Auto-détermination de la bonne disposition */
             if (!Prototype.Browser.IE)
            {
                if (pos === TlcCalendar.PosAuto) {
                    pos = TlcCalendar.PosUnder; /* par défaut */
                    
                    
                    if (typeof window.innerHeight !== 'undefined') {
                        hauteurVue = window.innerHeight;
                    } else {
                        hauteurVue = theDoc.documentElement.clientHeight;
                    }
                    
                    debutEcranY = theDoc.documentElement.scrollTop;
                    finEcranY = hauteurVue + debutEcranY;
                    if (yElt + elt.clientHeight + typicalMaxHeight > finEcranY) {
                        pos = TlcCalendar.PosOver;
                    }
                }
                
                switch (pos) {
                case TlcCalendar.PosUnder:
                    y += elt.clientHeight;
                    break;
                    
                case TlcCalendar.PosOver:
                    buttLastPosY = yElt;
                    break;
                }
            }
            
            internalOpen(x, y);
        }
    };
    
    /**
     * Ferme le calendrier si ouvert
     */         
    this.close = function () {
        if (eltMainDiv) {
            eltMainDiv.style.display = 'none';
            if ((versionIE() == 6 )&& $('pays'))
                $('pays').style.display= '' ;        
        }  
    };
    
    /**
     * Préselectionne une date (sera effectif à la prochaine ouverture)
     * 
     * @param d Date javascript ou textuelle au format standard          
     */         
    this.setDate = function (d) {
        var date;
        date = getJsDateFromAnything(d);
        if (date) {
            curDate = date;
        }
    };
    
    /**
     * Retourne la date actuellement selectionnée
     * 
     * @return Date javascript selectionnée          
     */         
    this.getDate = function () {
        return curDate;
    };
    

    /*
     * CONSTRUCTEUR
     */
    
    /* Constantes */
    picsRootDir = 'http://image.toutlecine.com/pics/';
    tabMois = [
        { nom: 'Janvier', jours: 31 },
        { nom: 'Février', jours: null },
        { nom: 'Mars', jours: 31 },
        { nom: 'Avril', jours: 30 },
        { nom: 'Mai', jours: 31 },
        { nom: 'Juin', jours: 30 },
        { nom: 'Juillet', jours: 31 },
        { nom: 'Août', jours: 31 },
        { nom: 'Septembre', jours: 30 },
        { nom: 'Octobre', jours: 31 },
        { nom: 'Novembre', jours: 30 },
        { nom: 'Décembre', jours: 31 }
    ];
    tabJours = [
        { abbr: 'Lun', val: 1 },
        { abbr: 'Mar', val: 2 },
        { abbr: 'Mer', val: 3 },
        { abbr: 'Jeu', val: 4 },
        { abbr: 'Ven', val: 5 },
        { abbr: 'Sam', val: 6 },
        { abbr: 'Dim', val: 0 }
    ];
    nbAnneesAffichables = 150;
    nbMaxLignesJours = 6;
    typicalMaxHeight = /* FF avec 6 lignes */ 178;

    /* Initialisations */
    eltMainDiv = null;
    
    theDoc = (typeof doc !== 'undefined' && doc ? doc : window.document);
    
    theCallBack = null;
    if (typeof updateCallBack !== 'undefined') {
        theCallBack = updateCallBack;
    }
    
    curDate = null; 
    if (typeof initDate !== 'undefined') {
        curDate = getJsDateFromAnything(initDate);
    }
    if (!curDate) {
        curDate = new Date();
    }
    
    dateMini = getJsDateFromAnything(
        typeof minDate !== 'undefined' ? minDate : null);
    if (!dateMini) {
        dateMini = new Date(1800, 1 - 1, 1);
    }
    
    dateMaxi = getJsDateFromAnything(
      typeof maxDate !== 'undefined' ? maxDate : null);
    if (!dateMaxi)
    {
           dateMaxi = new Date(2099, 12 - 1, 31);
    }    
    // limiter la date de naissance maxi à la date d'aujourd'hui
    if (DateFutur == false)
    { 
        var datedujour;
        
        Today = new Date;
        Jour = Today.getDate();
        if(Jour<10)    Jour= "0"+Jour;
        Mois = Today.getMonth();
        if(Mois<10)    Mois= "0"+Mois;
        Annee = Today.getFullYear();
        datedujour =  Jour+"/"+Mois+"/"+Annee;
        dateMaxi = new Date(Annee, Mois , Jour);
        
    }
   self = this;
}


/* Valeurs possibles pour la methode openNear
 * PosUnder : placer en dessous du bouton
 * PosOver : placer au dessus du bouton 
 * PosAuto : determine tout seul où positionner
 */
TlcCalendar.PosAuto = 0;
TlcCalendar.PosUnder = 1;
TlcCalendar.PosOver = 2;

/**
 * Effectuera une mise en place de calendrier typique autour du bouton d'id
 * donné et de l'input d'id donné 
 * 
 * @param idButton Id de l'élement faisant office de bouton pour l'ouverture
 *                 du calendrier
 * @param idInput Id de l'élement input qui sera mis à jour avec la date choisie    
 */ 
TlcCalendar.setupTypicalCalOn = function (idButton, idInput) {

    if (typeof TlcCalendar.tabCals === 'undefined') {
        TlcCalendar.tabCals = [ ];
        ajoutOnLoad(
            function () {
                var but;
                var inp;
                var k;
                
                function setupOneTypicalCalendar(button, input) {
                    var cal;
                    var firstElement;
                    var k;
                    
                    cal = new TlcCalendar(
                        document,
                        function (jsDate, txtDate) {
                            input.value = txtDate;
                        });

                    /* On prend le premier fils car dans la majorité
                     * des cas ce sera un lien avec une image dedans
                     * et le lien n'a pas de hauteur.                     
                     */
                    firstElement = null;
                    for (k = 0; !firstElement &&
                        k < button.childNodes.length; k++) {
                        if (button.childNodes[k].nodeType === 1) {
                            firstElement = button.childNodes[k];
                        }
                    }
                    
                    button.onclick = function () {
                        /* Prend en compte la date saisie avant d'ouvrir */
                        cal.setDate(input.value);
                        
                        cal.openNear(firstElement ? firstElement : button,
                            TlcCalendar.PosAuto, true);


                        return false;
                    };
                }

                for (k = 0; k < TlcCalendar.tabCals.length; k++) {
                    but = document.getElementById(TlcCalendar.tabCals[k].b);
                    inp = document.getElementById(TlcCalendar.tabCals[k].i);
                    if (but && inp) {
                        setupOneTypicalCalendar(but, inp);
                    }
                }
            }
        );
    }
    
    TlcCalendar.tabCals.push({ b: idButton, i: idInput });
};
