//#16.0.1.0 WDPlanning.js
//VersionVI: 30A160057k
// Le seul support technique disponible pour cette librairie est
// accessible a travers le service "Assistance Directe".

// Manipulation d'un champ planning
function WDPlanning (sAliasChamp, sAliasZR, sAliasAttribut)
{
	// Si on est pas dans l'init d'un protoype
	if (sAliasChamp)
	{
		// Appel le constructeur de la classe de base
		WDChampParametres.prototype.constructor.apply(this, arguments);
	}
}

// Declare l'heritage
WDPlanning.prototype = new WDChampParametres();
// Surcharge le constructeur qui a ete efface
WDPlanning.prototype.constructor = WDPlanning;

// Membres statiques
// Zone generale et ses 4 zones filles
WDPlanning.prototype.ms_sNomGeneral = "WDPLN-ZoneGenerale";
WDPlanning.prototype.ms_sNomBoutonsPeriode = "WDPLN-ZoneBoutonsPeriode";
WDPlanning.prototype.ms_sNomTitresHorizontal = "WDPLN-ZoneTitresHorizontal";
WDPlanning.prototype.ms_sNomTitresVertical = "WDPLN-ZoneTitresVertical";
WDPlanning.prototype.ms_sNomCorps = "WDPLN-ZoneCorps";
// Titres
WDPlanning.prototype.ms_sNomTitresRessources = "WDPLN-TitresRessources";
WDPlanning.prototype.ms_sNomTitresHeures = "WDPLN-TitresHeures";
// Ressources
WDPlanning.prototype.ms_sNomRessource = "WDPLN-Ressource";
WDPlanning.prototype.ms_sNomRessourceConteneur = "WDPLN-RessourceConteneur";
WDPlanning.prototype.ms_sNomJour = "WDPLN-Jour";
// Le premier element
WDPlanning.prototype.ms_sNomPremier = "WDPLN-Premier";

// Zone d'affichage des donnees
WDPlanning.prototype.ms_sNomCorpsQuadrillage = "WDPLN-ZoneCorpsQuadrillage";
WDPlanning.prototype.ms_sNomCorpsDimensionTotale = "WDPLN-ZoneCorpsDimensionTotale";
// Rendez-vous
WDPlanning.prototype.ms_sNomRendezVousExterne = "WDPLN-RendezVousExterne";
WDPlanning.prototype.ms_sNomRendezVous = "WDPLN-RendezVous";
WDPlanning.prototype.ms_sNomRendezVousSelect = "WDPLN-RendezVousSelect";
WDPlanning.prototype.ms_sNomRendezVousImage = "WDPLN-RendezVousImage";
WDPlanning.prototype.ms_sNomRendezVousTitre = "WDPLN-RendezVousTitre";
WDPlanning.prototype.ms_sNomRendezVousSupprime = "WDPLN-RendezVousSupprime";
WDPlanning.prototype.ms_sNomRendezVousRepetition = "WDPLN-RendezVousRepetition";
WDPlanning.prototype.ms_sNomRendezVousImportance = "WDPLN-RendezVousImportance";
WDPlanning.prototype.ms_sNomRendezVousBas = "WDPLN-RendezVousBas";
WDPlanning.prototype.ms_sNomRendezVousRedimDebut = "WDPLN-RendezVousRedimDebut";
WDPlanning.prototype.ms_sNomRendezVousRedimFin = "WDPLN-RendezVousRedimFin";
// Les heures
WDPlanning.prototype.ms_sNomFondCouleur = "WDPLN-FondCouleur";
WDPlanning.prototype.ms_sNomFondBordure = "WDPLN-FondBordure";
WDPlanning.prototype.ms_sNomHeure = "WDPLN-Heure";
WDPlanning.prototype.ms_sNomHeureDemi = "WDPLN-HeureDemi";
WDPlanning.prototype.ms_sNomHeureLibelle = "WDPLN-HeureLibelle";
WDPlanning.prototype.ms_tabHeureSuffixe = ["Normal", "HorsBornes", "Aujourdhui", "Samedi", "Dimanche", "Ferie"];
// Commandes
// Commandes pour les champs agenda/planning
//WDPlanning.prototype.ms_sActionAgendaRdvSelection = "AGENDARDVSEL";
WDPlanning.prototype.ms_sActionAgendaRdvDeplacement = "AGENDARDVDEP";
WDPlanning.prototype.ms_sActionAgendaRdvRedim = "AGENDARDVRED";
//WDPlanning.prototype.ms_sActionAgendaPeriodeSelect = "AGENDAPERSEL";
WDPlanning.prototype.ms_sActionAgendaRdvSupprime = "AGENDARDVSUP";
WDPlanning.prototype.ms_sActionAgendaRdvAjoute = "AGENDARDVAJO";
//WDPlanning.prototype.ms_sActionAgendaRdvEdition = "AGENDARDVEDI";
WDPlanning.prototype.ms_sActionAgendaRdvModifTitre = "AGENDARDVEDT";
WDPlanning.prototype.ms_sActionAgendaPeriodeAffiche = "AGENDAPERAFF";
//WDPlanning.prototype.ms_sActionAgendaPlanningDeplacementRessource = "PLANNINGRDVDES";
// Superposition
WDPlanning.prototype.ms_eSuperpositionCoteACote = 0;
WDPlanning.prototype.ms_eSuperpositionDecalage = 1;
// Images par defaut
WDPlanning.prototype.ms_tabImageDefaut = {
	ms_sImageVide : "vide.gif",
	ms_sImageSupprime : "pl_delete.gif",
	ms_sImageRepetition : "pl_rdvrepete.gif",
	ms_sImageImportance : "pl_rdvimportant.png",
	ms_sImagePeriodePrecedente : "MoisP.gif",
	ms_sImagePeriodeSuivante : "MoisS.gif"
};

// Paddings
WDPlanning.prototype.ms_nPaddingTitre = 2;
WDPlanning.prototype.ms_nPaddingTitreCalcul = (bIEQuirks ? 0 : 2 * WDPlanning.prototype.ms_nPaddingTitre);
WDPlanning.prototype.ms_nPaddingRendezVous = 3;
WDPlanning.prototype.ms_nPaddingLateralDebut = 1;
WDPlanning.prototype.ms_nPaddingLateralFin = 5;

// Les z-Index du champ
// 0 : Fond des heures
WDPlanning.prototype.ms_nZIndexFondHeure = 0;
// 1 : Fond de la ligne/colonne des ressources
WDPlanning.prototype.ms_nZIndexFondRessource = 1;
// 2 : Bordure des heures
WDPlanning.prototype.ms_nZIndexFondBordure = 2;
// 3 : Date et heure (libelles)
// 4 : Rendez-vous
WDPlanning.prototype.ms_nZIndexRendezVous = 4;
// 5 : Rendez-vous selectionne
WDPlanning.prototype.ms_nZIndexRendezVousSelection = 5;
// 6 : Rupture sur les jours (si presente (specifique au ressources en colonnes))
WDPlanning.prototype.ms_nZIndexFondRupture = 6;
// 7 : Bouton de suppression
WDPlanning.prototype.ms_nZIndexRendezVousSupprime = 7;
// 8 : Fantome en deplacement
WDPlanning.prototype.ms_nZIndexFantome = 8;

// Declare les fonction une par une

// Initialisation :
WDPlanning.prototype.Init = function Init()
{
	// Appel de la methode de la classe de base
	WDChampParametres.prototype.Init.apply(this, arguments);

	// Les callbacks
	var oThis = this;
	this.m_fOnRendezVousSupprime = function(oEvent) { oEvent = oEvent ? oEvent : event; oThis.__OnRendezVousSupprime(oEvent); };
	this.m_fOnDefilementCorps = function(oEvent) { oEvent = oEvent ? oEvent : event; oThis.OnDefilementCorps(oEvent); };

	// Pour ne pas avoir de problemes en cas d'agrandissement du contenu en AJAX
	this.m_oHote.style.overflow = "hidden";
	this.m_oHote.style.position = "relative";

	// Regarde si on est avec un dimensionnement en %
	this.m_bTailleVariable = (-1 != this.m_oHote.style.width.indexOf("%")) || (-1 != this.m_oHote.style.height.indexOf("%"));

	// Reconstruit le HTML
	this.__Reinit();

	// Pour le mode AWP on refixe dans le champ formulaire la selection
	this.ConstruitParam();
};

// Methode d'initialisation generale de la classe
// Filtre et ne s'execute que lors de l'init du PREMIER champ de ce type
WDPlanning.prototype._vInitInitiale = function _vInitInitiale()
{
	// Appel de la methode de la classe de base
	WDChampParametres.prototype._vInitInitiale.apply(this, arguments);

	// Creation de la feuille de style globale
	WDPlanning.prototype.ms_oFeuilleStyleGlobale = this.__oCreeFeuilleStyle();

	// Regles communes aux deux orientation du champ
	// - General
	this.__StyleCreeGlobal("." + this.ms_sNomBoutonsPeriode, ["overflow:hidden"]);
	this.__StyleCreeGlobal("." + this.ms_sNomTitresHorizontal, ["overflow:hidden"]);
	// Le dessin avec clipping ne marche pas dans IE en mode quirks, on fait l'ancien mode avec overflow-x/overflow-y
	if (bIEQuirks)
	{
		// Pour permettre la surcharge de overflow-x dans certains cas
		this.__StyleCreeGlobal("." + this.ms_sNomTitresVertical, ["overflow-x:hidden", "overflow-y:hidden", "z-index:" + this.ms_nZIndexFondRupture, "position:relative"]);
	}
	else
	{
		this.__StyleCreeGlobal("div." + this.ms_sNomTitresVertical, ["overflow:hidden", "z-index:" + this.ms_nZIndexFondRupture]);
	}
	// - Titre
	var tabStyleTitre = ["padding-left:" + this.ms_nPaddingTitre + "px", "padding-right:" + this.ms_nPaddingTitre + "px", "text-overflow:ellipsis", "white-space:nowrap", "overflow:hidden"];
	this.__StyleCreeGlobal("." + this.ms_sNomTitresHorizontal + " div", tabStyleTitre);
	this.__StyleCreeGlobal("." + this.ms_sNomTitresVertical + " div", tabStyleTitre);
	this.__StyleCreeGlobal("." + this.ms_sNomTitresVertical + " span", ["vertical-align:center"]);
	// - Rendez-vous
	this.__StyleCreeGlobal("." + this.ms_sNomRendezVous, ["cursor:default"]);
	this.__StyleCreeGlobal("." + this.ms_sNomRendezVousExterne, ["overflow-y:hidden"]);
	this.__StyleCreeGlobal("." + this.ms_sNomRendezVousExterne + " div", ["overflow:hidden"]);
	this.__StyleCreeGlobal("." + this.ms_sNomRendezVousImage, ["background-position:bottom left", "background-repeat:no-repeat"]);
	this.__StyleCreeGlobal("." + this.ms_sNomRendezVousTitre + " div", ["text-overflow:ellipsis", "white-space:nowrap", "padding-bottom:2px"]);
	this.__StyleCreeGlobal("." + this.ms_sNomRendezVousSupprime, ["z-index:" + this.ms_nZIndexRendezVousSupprime, "position:absolute"]);

	// Ajout des regles
	this.__StyleCreeGlobal("." + this.ms_sNomCorps + " div." + this.ms_sNomRessource, ["z-index:" + this.ms_nZIndexFondRessource, "position:absolute"]);
	this.__StyleCreeGlobal("." + this.ms_sNomRessourceConteneur, ["z-index:" + this.ms_nZIndexRendezVous, "position:relative"]);
	this.__StyleCreeGlobal("." + this.ms_sNomFondCouleur, ["z-index:" + this.ms_nZIndexFondHeure, "position:absolute"]);
	this.__StyleCreeGlobal("." + this.ms_sNomFondCouleur + " div", ["z-index:0"]);
	this.__StyleCreeGlobal("." + this.ms_sNomFondBordure, ["z-index:" + this.ms_nZIndexFondBordure, "position:absolute"]);
	this.__StyleCreeGlobal("." + this.ms_sNomHeureDemi, ["position:absolute"]);
	// ve

	// Prechargement des images
	var sImage;
	for (sImage in this.ms_tabImageDefaut)
	{
		var sCheminImage = this.sCheminImageRes(this.ms_tabImageDefaut[sImage]);
		WDPlanning.prototype[sImage] = sCheminImage;
		(new Image()).src = sCheminImage;
	}

	// S'auto efface pour ne plus etre appele
	WDPlanning.prototype._vInitInitiale = WDChamp.prototype.m_pfVide;
};

// Construit tous le HTML si besoin
WDPlanning.prototype.__Reinit = function __Reinit(bAvecCSS, bRAZDejaFait)
{
	// On effectue la laison avec la selection
	this.__TrouveSelection();

	// Si l'element n'est pas visible : fini
	if (!clWDUtil.bEstDisplay(this.m_oHote, document))
	{
		return;
	}

	// Si c'est le premier affichage
	if (!this.m_bPremierAffichageFait)
	{
		// Initialise les differents evenements
		this.__InitEvents();

		// Initialise les styles
		this.__InitCSS();

		// Construit le HTML
		this.__HTMLAfficheBase();

		// Synchronise le scroll des differentes parties
		HookOnXXX(this.m_oHoteCorps, 'onscroll', 'scroll', this.m_fOnDefilementCorps);

		// Affiche le contenu
		this.__HTMLAfficheContenu(false, true, false);

		this.m_bPremierAffichageFait = true;
	}
	else
	{
//		if (bAvecCSS)
//		{
//			this.__InitCSS();
//			// Il faut refaire cette init car __InitCSS a supprimer la feuille de style
//			this._vInitCSS_LibJour();
//		}

		// Reaffiche le contenu du champ
		this.__HTMLAfficheContenu(true, bAvecCSS, bRAZDejaFait);
	}
};

// Construit le HTML de base
WDPlanning.prototype.__HTMLAfficheBase = function __HTMLAfficheBase()
{
	var sIDZoneBoutonsPeriode = this.sGetSuffixeIDElement(this.ms_sNomBoutonsPeriode);
	var sIDZoneTitresHorizontal = this.sGetSuffixeIDElement(this.ms_sNomTitresHorizontal);
	var sIDZoneTitresVertical = this.sGetSuffixeIDElement(this.ms_sNomTitresVertical);
	var sIDZoneCorps = this.sGetSuffixeIDElement(this.ms_sNomCorps);
	// Genere la table externe
	var tabHTML = [];
	tabHTML.push("<table class=\"");
	tabHTML.push(this.ms_sNomGeneral);
	tabHTML.push(" ");
	tabHTML.push(this.ms_sNomGeneralSpecifique);
	tabHTML.push("\">");
	tabHTML.push("<tr><td>");
	this.__HTMLAfficheDiv(tabHTML, this.ms_sNomBoutonsPeriode, this.sGetNomElement(sIDZoneBoutonsPeriode));
	tabHTML.push("</td><td>");
	this.__HTMLAfficheDiv(tabHTML, this.ms_sNomTitresHorizontal, this.sGetNomElement(sIDZoneTitresHorizontal));
	tabHTML.push("</td></tr><tr><td>");
	this.__HTMLAfficheDiv(tabHTML, this.ms_sNomTitresVertical, this.sGetNomElement(sIDZoneTitresVertical));
	tabHTML.push("</td><td>");
	this.__HTMLAfficheDiv(tabHTML, this.ms_sNomCorps, this.sGetNomElement(sIDZoneCorps));
	tabHTML.push("</td></tr></table>");
	this.m_oHote.innerHTML = tabHTML.join("");

	// Recupere les conteneurs
	this.m_oHoteBoutonsPeriode = this.oGetElementById(document, sIDZoneBoutonsPeriode);
	this.m_oHoteTitresHorizontal = this.oGetElementById(document, sIDZoneTitresHorizontal);
	this.m_oHoteTitresVertical = this.oGetElementById(document, sIDZoneTitresVertical);
	this.m_oHoteCorps = this.oGetElementById(document, sIDZoneCorps);

	// Initialisation du style des libelle des jours (qui a besoin de la dimension des elements)
	this._vInitCSS_LibJour();
};

// Initialise les styles
WDPlanning.prototype.__InitCSS = function __InitCSS()
{
	// Supprime la feuile de style existante
	if (this.m_oFeuilleStyle)
	{
		var oBaliseStyle = bIE ? this.m_oFeuilleStyle.owningElement : this.m_oFeuilleStyle.ownerNode;
		this.m_oFeuilleStyleRules = null;
		this.m_oFeuilleStyle = null;
		oBaliseStyle.parentNode.removeChild(oBaliseStyle);
		oBaliseStyle = null;
	}

	// Creation de la feuille de style locale
	this.m_oFeuilleStyle = this.__oCreeFeuilleStyle();
	this.m_oFeuilleStyleRules = bIE ? this.m_oFeuilleStyle.rules : this.m_oFeuilleStyle.cssRules;

	// Et initialise les styles du champ
	var nLargeur = this.__nGetLargeur();
	var nHauteur = this.__nGetHauteur();
	this.m_nLargeurCorps = nLargeur - this.m_oParametres.m_nLargeurTitresVertical;
	this.m_nHauteurCorps = nHauteur - this.m_oParametres.m_nHauteurTitresHorizontal;

	// Zone generale : taille
	this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomGeneral), ["width:" + nLargeur + "px", "height:" + nHauteur + "px"]);
	// Zone des boutons en haut
	this.__StyleCree(this.__sGetSelecteur(undefined, "div", this.ms_sNomBoutonsPeriode), ["width:" + this.m_oParametres.m_nLargeurTitresVertical + "px", "height:" + this.m_oParametres.m_nHauteurTitresHorizontal + "px"]);
	var tabStyleBoutonsPeriode = this.__tabInitCSS_BorduresMoitie([], this.m_oParametres.m_oStyleNormal, "left", this.m_oParametres.m_oStyleNormal, "top", false);
	if (tabStyleBoutonsPeriode.length)
	{
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomBoutonsPeriode, "td", undefined), tabStyleBoutonsPeriode);
	}
	// Zone de titres : taille
	// - Largeur des titres horizontal = largeur du corps
	this.__StyleCree(this.__sGetSelecteur(undefined, "div", this.ms_sNomTitresHorizontal), ["width:" + this.m_nLargeurCorps + "px", "height:" + this.m_oParametres.m_nHauteurTitresHorizontal + "px"]);
	this.__StyleCree(this.__sGetSelecteur(undefined, "table", this.ms_sNomTitresHorizontal), ["height:" + this.m_oParametres.m_nHauteurTitresHorizontal + "px"]);
	// - Hauteur des titres vertical = hauteur du corps
	this.__StyleCree(this.__sGetSelecteur(undefined, "div", this.ms_sNomTitresVertical), ["width:" + this.m_oParametres.m_nLargeurTitresVertical + "px", "height:" + this.m_nHauteurCorps + "px"]);
	// Le dessin avec clipping ne marche pas dans IE en mode quirks, on fait l'ancien mode avec overflow-x/overflow-y
	var tabStyle = ["width:" + this.m_oParametres.m_nLargeurTitresVertical + "px"]
	if (!bIEQuirks)
	{
		tabStyle.push("position:absolute");
	}
	this.__StyleCree(this.__sGetSelecteur(undefined, "table", this.ms_sNomTitresVertical), tabStyle);
	// Hauteur du bloc de corps
	this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomCorps), ["width:" + this.m_nLargeurCorps + "px", "height:" + this.m_nHauteurCorps + "px"]);

	// Style des titres horizontaux et verticaux
	this.__InitCSS_TitresHorizontal();
	this.__InitCSS_TitresVertical();

	// Style specifique des titres
	this.__InitCSS_TitresRessources();
	this.__InitCSS_TitresHeures();

	// Colonne(s) de ressource(s)
	this.__InitCSS_Ressources();
	// L'init du style des heures est decale pour avoir this.m_nDimensionPxZoneHeures

	// Styles des rendez-vous
	this.__InitCSS_RendezVous();
};

// Initialisation du style de titre
// Param					Ressources									Heures
// sClasseTitre			=>	this.ms_sNomTitresRessources						this.ms_sNomTitresHeures
// sClasseZoneTitre		=>	selon le sens
// tabBordure			=>	Bordures laterales									Bordure principales
// tabBordurePremier	=>	Bordures laterales									Bordure principales
// tabBordureCote		=>	Bordure principales									Bordures laterales
// oStyleTitre			=>	this.m_oParametres.m_oStyleNormal					this.m_oParametres.m_oStyleLibHeure
// oStyleLibelle		=>	this.m_oParametres.m_oStyleLibRessource				this.m_oParametres.m_oStyleLibHeure
// nDimensionPxPrincipale => selon le sens
// nDimensionPxLaterale	=>	this.m_oParametres.m_nDimensionLateralePxRessource	this.m_oParametres.m_nDimensionPxGraduation (+ sans les bordures)
WDPlanning.prototype.__InitCSS_Titres = function __InitCSS_Titres(sClasseTitre, sClasseZoneTitre, tabBordure, tabBordurePremier, tabBordureCote, oStyleTitre, oStyleLibelle, nDimensionPxPrincipale, nDimensionPxLaterale)
{
	// Fixe la bordure des div (div de fond des ressources et div de titre des ressources)
	this.__StyleCree(this.__sGetSelecteur(sClasseTitre, "div", undefined), tabBordure);
	this.__StyleCree(this.__sGetSelecteur(sClasseTitre + " ." + this.ms_sNomPremier, "div", undefined), tabBordurePremier);

	// Bordure du haut de la colonne de ressources
	this.__StyleCree(this.__sGetSelecteur(sClasseTitre, "td", undefined), tabBordureCote);

	// Autres style pour les titres
	// - Dimension (dans les deux sens)
	// - Couleur de fond
	if (oStyleLibelle.m_cFond)
	{
		tabBordure.push("background-color:" + oStyleLibelle.m_cFond);
	}
	// Le reste (les dimensions) est specifique en particulier, il faut supprimer (ou pas) le padding selon le sens
	tabBordure = this._vtabInitCSS_DimensionPxLaterale(tabBordure, nDimensionPxLaterale, this.ms_nPaddingTitreCalcul, 0, true);
	tabBordure = this._vtabInitCSS_DimensionPxPrincipale(tabBordure, nDimensionPxPrincipale, this.ms_nPaddingTitreCalcul, 0, false);
	// La hauteur est fixe dans le style des titres horizontal/vertical
	this.__StyleComplete(this.__sGetSelecteur(sClasseTitre, "div", undefined), tabBordure);

	// Couleur de fond generale (sur toute la zone de titre)
	if (oStyleTitre && oStyleTitre.m_cFond)
	{
		this.__StyleCree(this.__sGetSelecteur(undefined, "", sClasseZoneTitre), ["background-color:" + oStyleTitre.m_cFond]);
	}
};

// Style specifique des titres
WDPlanning.prototype.__InitCSS_TitresRessources = function __InitCSS_TitresRessources()
{
	var tabBordure = this._vtabInitCSS_BorduresLaterales([], null, this.m_oParametres.m_oStyleNormal);
	var tabBordurePremier = this._vtabInitCSS_BorduresLaterales([], this.m_oParametres.m_oStyleLibHeure, this.m_oParametres.m_oStyleNormal);
	var tabBordureCote = this._vtabInitCSS_BorduresPerpendiculaires([], this.m_oParametres.m_oStyleLibRessource, null);
	var nDimensionPxLaterale = this.__nGetDimensionPxSansBordure(this.m_oParametres.m_nDimensionLateralePxRessource, this.m_oParametres.m_oStyleLibRessource);
	this.__InitCSS_Titres(this.ms_sNomTitresRessources, this.ms_sTitresRessourcesPosition, tabBordure, tabBordurePremier, tabBordureCote, this.m_oParametres.m_oStyleNormal, this.m_oParametres.m_oStyleLibRessource, this._vnDimensionPxPrincipaleTitresRessources(), nDimensionPxLaterale);
};
WDPlanning.prototype.__InitCSS_TitresHeures = function __InitCSS_TitresHeures()
{
	var tabBordure = this._vtabInitCSS_BorduresPerpendiculaires([], this.m_oParametres.m_oStyleLibHeure, null);
	// Note : pour les heures ont a un bordure sur le dernier (meme si on garde le meme style)
	var tabBordurePremier = this._vtabInitCSS_BorduresPerpendiculaires([], this.m_oParametres.m_oStyleLibHeure, this.m_oParametres.m_oStyleLibHeure);
	var tabBordureCote = this._vtabInitCSS_BorduresLaterales([], this.m_oParametres.m_oStyleLibHeure, null);
	var nDimensionPxPrincipale = this.__nGetDimensionPxSansBordure(this.m_oParametres.m_nDimensionPxGraduation, this.m_oParametres.m_oStyleLibHeure);
	this.__InitCSS_Titres(this.ms_sNomTitresHeures, this.ms_sTitresHeuresPosition, tabBordure, tabBordurePremier, tabBordureCote, this.m_oParametres.m_oStyleLibHeure, this.m_oParametres.m_oStyleLibHeure, nDimensionPxPrincipale, this._vnDimensionPxPrincipaleTitresLibelles());
};

// Initialisation du style des ressources
WDPlanning.prototype.__InitCSS_Ressources = function __InitCSS_Ressources()
{
	// Style du div (tient compte de la bordure)
	var nLargeurDivPremier = this.__nGetDimensionPxSansBordureRessources(true);
	var nLargeurDiv = this.__nGetDimensionPxSansBordureRessources(false);
	var nOffsetPremier = Math.max(0, nLargeurDiv - nLargeurDivPremier);

	var tabStyle;
	// Style general
	tabStyle = this._vtabInitCSS_DimensionPxLaterale([], this.m_oParametres.m_nDimensionLateralePxRessource, 0, 0, true);
	tabStyle = this._vtabInitCSS_BorduresLaterales(tabStyle, null, this.m_oParametres.m_oStyleNormal);
	this.__StyleCree(this.__sGetSelecteur(undefined, "div", this.ms_sNomRessource), tabStyle);
	// Style du premier
	tabStyle = this._vtabInitCSS_DimensionPxLaterale([], this.m_oParametres.m_nDimensionLateralePxRessource - nOffsetPremier, 0, 0, true);
	tabStyle = this._vtabInitCSS_BorduresLaterales(tabStyle, this.m_oParametres.m_oStyleLibHeure, this.m_oParametres.m_oStyleNormal);
	this.__StyleCree(this.__sGetSelecteur(this.ms_sNomPremier, "div", this.ms_sNomRessource), tabStyle);

	this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomRessourceConteneur), [this.ms_sStyleDimensionLaterale + ":" + nLargeurDiv + "px"]);
	// Si il y a une bordure sur le premier, il faut decaler le premier conteneur pour ne pas avoir le contenu coller a la bordure supplementaire
	// Sauf que sous IE en mode compat les bordures ne sont pas dans le calcul donc nOffsetPremier est toujours a 0
	if (bIEQuirks && this.m_oParametres.m_oStyleLibHeure.m_nBordureV)
	{
		nOffsetPremier = this.m_oParametres.m_oStyleLibHeure.m_nBordureV;
		nLargeurDivPremier = nLargeurDiv - nOffsetPremier;
	}
	if (nOffsetPremier)
	{
		tabStyle = [];
		tabStyle.push(this.ms_sStyleDebutLateral + ":" + nOffsetPremier + "px");
		tabStyle.push(this.ms_sStyleDimensionLaterale + ":" + nLargeurDivPremier + "px");
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomPremier, "", this.ms_sNomRessourceConteneur), tabStyle);
	}

	// Style general sur la largeur sur le td
	this.__StyleCree(this.__sGetSelecteur(undefined, "td", this.ms_sNomRessource), this._vtabInitCSS_DimensionPxLaterale([], this.m_oParametres.m_nDimensionLateralePxRessource, 0, 0, true));
};

// Initialisation du style des heures
WDPlanning.prototype.__InitCSS_Heures = function __InitCSS_Heures()
{
	// Style (largeur) des zones
	// Le positionnement est dans des styles generaux
	var nDimensionPxTotale = this.m_oDonnees.m_tabRessources.length * this.m_oParametres.m_nDimensionLateralePxRessource;
	var tabStyleLateral = this._vtabInitCSS_DimensionPxLaterale([], nDimensionPxTotale, 0, 0, false);

	var tabStyleLateral2 = tabStyleLateral.concat(this.ms_sStyleDimension + ":" + this.m_nDimensionPxZoneHeures + "px");
	this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomFondCouleur), tabStyleLateral2);
	this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomFondBordure), tabStyleLateral2);

	// Style general : hauteur d'une heure
	var tabStylePrincipal = this._vtabInitCSS_DimensionPxPrincipale([], this.m_oParametres.m_nDimensionPxGraduation, 0, 0, false);
	this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomHeure), tabStylePrincipal.concat(this.ms_sStyleDimensionLaterale + ":" + nDimensionPxTotale + "px"));
	this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomHeureLibelle), tabStyleLateral.concat(tabStylePrincipal));

	// Couleur des heures
	var i;
	var nLimiteI = this.ms_tabHeureSuffixe.length;
	for (i = 0; i < nLimiteI; i++)
	{
		this.__InitCSS_UneHeure(this.ms_tabHeureSuffixe[i], tabStyleLateral);
	}
};

// Initialisation du style des heures (on est forcement en affichage par heure)
WDPlanning.prototype.__InitCSS_UneHeure = function __InitCSS_UneHeure(sSuffixe, tabStyleLateral)
{
	var sClasse = "WDPLN-" + sSuffixe;
	// Recupere le style demande
	var oStyle = this.m_oParametres["m_oStyle" + sSuffixe];

	// Si on a une couleur de fond
	if (oStyle.m_cFond)
	{
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomFondCouleur, "", sClasse), ["background-color:" + oStyle.m_cFond]);
	}

	// Style des bordures (demi-heures)
	var tabStyle = [];
	var nDimensionPxDemiHeure = parseInt(this.m_oParametres.m_nDimensionPxGraduation / 2, 10);
	if (0 < oStyle.m_nBordureV)
	{
		var nBordure = oStyle.m_nBordureV;
		// On veux que le trait soit au debut de la demi heure donc il faut l'epaisseur en pixel supplementaire
		// Donc au lieu de faire :
		//	- compat : + 0 * bordure
		//	- strict : - 2 * bordure
		// On fait decale de 1 :
		//	- compat : + 1 * bordure
		//	- strict : - 1 * bordure
		if (bIEQuirks)
		{
			nDimensionPxDemiHeure += nBordure; // - * 1 et pas - * 2
		}
		else
		{
			nDimensionPxDemiHeure -= nBordure; // - * 1 et pas - * 2
		}
		tabStyle = this._vtabInitCSS_BorduresPerpendiculaires(tabStyle, oStyle, oStyle, true);
		// Normalement la couleur de fond dans la premiere colonne est dessous donc cela ne pose pas de probleme
		var tabStyleLibelle = this._vtabInitCSS_BorduresPerpendiculaires(["background-color:transparent"], oStyle, undefined);
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomFondBordure + " ." + sClasse, "", this.ms_sNomHeureLibelle), tabStyleLibelle);

		// Si on est en affichage a la journee, affiche le separateur
		if (this.m_oParametres.m_nResolutionGrille >= 86400000)
		{
			var tabStyleHeure = this._vtabInitCSS_BorduresPerpendiculaires([], oStyle, null, false);
			// Il faut tenir compte du separateur
			if (!bIEQuirks && (0 < oStyle.m_nBordureV))
			{
				tabStyleHeure = this._vtabInitCSS_DimensionPxPrincipale(tabStyleHeure, (this.m_oParametres.m_nDimensionPxGraduation - oStyle.m_nBordureV), 0, 0, false);
			}
			this.__StyleCree(this.__sGetSelecteur(this.ms_sNomFondBordure + " ." + sClasse + "." + this.ms_sNomHeure, "", undefined), tabStyleHeure);
		}
	}
	// Fixe la taille
	tabStyle = this._vtabInitCSS_DimensionPxPrincipale(tabStyle, nDimensionPxDemiHeure, 0, 0, false);
//	tabStyle.push(this.ms_sStyleDebut + ":" + (this.m_oParametres.m_nDimensionPxGraduation - nDimensionPxDemiHeure) + "px");
	tabStyle = tabStyle.concat(tabStyleLateral);
	this.__StyleCree(this.__sGetSelecteur(this.ms_sNomFondBordure + " ." + sClasse, "", this.ms_sNomHeureDemi), tabStyle);
};

//////////////////////////////////////////////////////////////////////////
// Methodes de dessin compatibles avec les deux sens

// - Initialisation

// Initialise les differents evenements
WDPlanning.prototype.__InitEvents = function __InitEvents()
{
	// Evenements :
	//	- Generiques :
	//		- Redimensionnement : fait pas le champ (appel de OnResize)
	//		- Defilement : rien a faire
	// => Vide
	//	- Specifiques :
	//		- Drag drop des rendez-vous
	this.m_oDragRendezVous = new WDDragRendezVous(this);
	this.m_oDragRendezVous.Init();
	//		- Drag-drop dans le fond d'une ressource (selection d'une periode pour creation d'un rendez-vous)
	this.m_oDragPeriodeSelect = new WDDragPeriodeSelect(this);
	this.m_oDragPeriodeSelect.Init();
	//		- Entree en saisie dans un champ
	this.m_oPopupSaisie = new WDPopupSaisiePlanning(this);
	this.m_oPopupSaisie.Init();
};

// Liaison entre les parametres et la selection
WDPlanning.prototype.__TrouveSelection = function __TrouveSelection()
{
	// Supprime le rendez-vous selectionne actuel (s'il n'est pas affiche il n'existe pas)
	this.m_oRendezVousSelection = null;
	delete this.m_oRendezVousSelection;

	// Trouve le rendez-vous selectionne
	if (this.m_oParametres.m_sIDSelection !== undefined)
	{
		var tabRendezVous = this.m_oDonnees.m_tabRendezVous;
		var i;
		var nLimiteI = tabRendezVous.length;
		for (i = 0; i < nLimiteI; i++)
		{
			if (tabRendezVous[i].m_sID == this.m_oParametres.m_sIDSelection)
			{
				this.m_oRendezVousSelection = tabRendezVous[i];
				break;
			}
		}
	}
};

// - Methodes surchargees des classes de bases

// - Tous les champs : Notifie le champ le conteneur xxx est affiche via un .display = "block"
WDPlanning.prototype.OnDisplay = function OnDisplay(oElementRacine)
{
	// Appel de la methode de la classe de base
	WDChampParametres.prototype.OnDisplay.apply(this, arguments);

	if (this.m_oHote && bEstFils(this.m_oHote, oElementRacine, document))
	{
		// Reaffiche le contenu du champ
		this.__Reinit(true);
	}
};

// - Tous les champs : Notifie le champ que la fenetre est redimentionnee
WDPlanning.prototype.OnResize = function OnResize(oEvent)
{
	// Appel de la methode de la classe de base
	WDChampParametres.prototype.OnResize.apply(this, arguments);

	if (this.m_oHote && this.m_bTailleVariable)
	{
		// Si on n'a déjà un __Reinit en attente, on ne vide pas une seconde fois
		if (!this.bGetTimeXXXExiste("__Reinit"))
		{
			this.__HTMLVideContenu();
			// Modifie temporairement la taille du corps
			this.__StyleComplete(this.__sGetSelecteur(undefined, "", this.ms_sNomGeneral), ["width:1px", "height:1px"]);
			this.__StyleComplete(this.__sGetSelecteur(undefined, "", this.ms_sNomCorps), ["width:1px", "height:1px"]);
			this.m_oHoteTitresHorizontal.style.width = "1px";
			this.m_oHoteTitresVertical.style.height = "1px";
		}
		this.nSetTimeoutUnique("__Reinit", 200, true, true);
	}
};

// Pour implementer ConstruitParam (accepte des parametres variables)
WDPlanning.prototype._vsConstruitParam = function _vsConstruitParam()
{
	var tabParam = [];
	// Appel de la methode de la classe de base
	var sParam = WDChampParametres.prototype._vsConstruitParam.apply(this, arguments);
	if (sParam.length > 0)
	{
		tabParam.push(sParam);
	}

	// Ajoute la position du debut du champ
	tabParam.push(this.m_oParametres.m_oDateDebut.getTime() + "");
	// Ajoute la position de scrolling dans le sens du temps (donc parallele au sens des ressources)
	if (this.m_nDefilementPrincipal)
	{
		var oGraduation = this.__oGetGraduation(this.m_nDefilementPrincipal, true);
		var oDateDebutDefilementJour = new Date(oGraduation.m_nDateDebut);
		oDateDebutDefilementJour.setUTCHours(0, 0, 0, 0);
		tabParam.push(oDateDebutDefilementJour.getTime() + "");
	}
	else
	{
		tabParam.push(this.m_oParametres.m_oDateDebut.getTime() + "");
	}

	// Si on a recu un argument : c'est le rendez-vous
	var oRendezVous = (arguments.length >= 1) ? arguments[0] : this.m_oRendezVousSelection;

	// Les details du rendez-vous (au format urlencode)
	if (oRendezVous)
	{
		tabParam.push(this._sConstruitParamObjet(oRendezVous));
	}
	else
	{
		tabParam.push("");
	}

	return tabParam.join(',');
};

// Trouve les divers elements : liaison avec le HTML
WDPlanning.prototype._vLiaisonHTML = function _vLiaisonHTML()
{
	// Appel de la methode de la classe de base
	WDChampParametres.prototype._vLiaisonHTML.apply(this, arguments);

	// La zone de dessin
	this.m_oHote = this.oGetElementById(document, this.ms_sSuffixeHote);
};

// Applique les parametres
WDPlanning.prototype._vAppliqueParametres = function vAppliqueParametres()
{
	WDChampParametres.prototype._vAppliqueParametres.apply(this, arguments);

	// Recharge le champ (en particulier le calcul tailles etc)
	this.__Reinit(true);

	// Pour le mode AWP on refixe dans le champ formulaire la selection
	this.ConstruitParam();
};

// - Traitement des evenements utilisateurs

// Defilement de la zone d'affichage
WDPlanning.prototype.OnDefilementCorps = function OnDefilementCorps(oEvent)
{
	// La consultation des scrollXxx declenche un appel de onscroll
	if (this.m_bDansGetDefilement)
	{
		return;
	}

	var nLargeurCorps = this.m_oHoteCorps.clientWidth;
	var nHauteurCorps = this.m_oHoteCorps.clientHeight;
//	var nLargeurCorps = this.m_nLargeurCorps;
//	var nHauteurCorps = this.m_nHauteurCorps;
	var nDefilementHorizontal = this.m_oHoteCorps.scrollLeft;
	var nDefilementVertical = this.m_oHoteCorps.scrollTop;

	// Inutile : on change le style sur le resize
	// Ajoute la largeur de la zone des titres
	if (nLargeurCorps != this.m_oHoteTitresHorizontal.clientWidth)
	{
		this.m_oHoteTitresHorizontal.style.width = nLargeurCorps + "px";
	}

	// Synchronise les scrolls
	if (nDefilementHorizontal != this.m_oHoteTitresHorizontal.scrollLeft)
	{
		this.m_oHoteTitresHorizontal.scrollLeft = nDefilementHorizontal;
	}

	// Inutile : on change le style sur le resize
	// Ajoute la largeur de la zone des titres
	if (nHauteurCorps != this.m_oHoteTitresVertical.clientHeight)
	{
		this.m_oHoteTitresVertical.style.height = nHauteurCorps + "px";
	}

	// Synchronise les scrolls
	// Le dessin avec clipping ne marche pas dans IE en mode quirks, on fait l'ancien mode avec overflow-x/overflow-y
	if (bIEQuirks)
	{
		if (nDefilementVertical != this.m_oHoteTitresVertical.scrollTop)
		{
			this.m_oHoteTitresVertical.scrollTop = nDefilementVertical;
		}
	}
	else
	{
		if (nDefilementVertical != -parseInt(_JGCS(this.m_oHoteTitresVertical.firstChild).top, 10))
		{
			this.m_oHoteTitresVertical.firstChild.style.top = (-nDefilementVertical + this.m_oParametres.m_nHauteurTitresHorizontal) + "px";
			this.m_oHoteTitresVertical.firstChild.style.clip = "rect(" + nDefilementVertical + "px, auto, " + (nDefilementVertical + nHauteurCorps) + "px, auto)";
		}
	}

	// Memorise la position pour le cas d'un reaffichage
	var nDefilementPrincipalOld = this.m_nDefilementPrincipal;
	this.m_nDefilementPrincipal = this._vnGetDefilementPrincipal();
	// Memorise la position pour le serveur dans le champ formulaire la selection
	if (nDefilementPrincipalOld != this.m_nDefilementPrincipal)
	{
		this.ConstruitParam();
	}
	// Memorise la position pour le cas d'un reaffichage (mais on ne l'envoi pas au serveur)
	this.m_nDefilementLateral = this._vnGetDefilementLateral();

	// Deplace le bouton de suppression (parente au parent du corps pour ne pas etre coupe par l'overflow
	this.__HTMLPlaceRendezVousSuppressionAutonome();

	// Sur le defilement du corps
	this._vOnDefilementCorps(nLargeurCorps, nHauteurCorps, nDefilementHorizontal, nDefilementVertical);
};

// Selectionne une rendez-vous
WDPlanning.prototype.bOnRendezVousSelection = function bOnRendezVousSelection(oEvent, oRendezVous)
{
	// Si deja selectionne
	if (this.__bMemeRendezVous(this.m_oRendezVousSelection, oRendezVous))
	{
		// Reforce la selection (pour le cas ou les pointeurs sont differents)
		this.m_oRendezVousSelection = oRendezVous;
		return true;
	}

	// Valide avec le PCode (+ construit les parametres)
	if (!this.__bAppelPCodeConstruitParam(this.ms_nEventNavAgendaRdvSelection, undefined, oEvent, oRendezVous))
	{
		return false;
	}

	// Le rendez-vous selectionne ne l'est plus
	this.__HTMLVideRendezVousSelection();

	// Memorise la selection
	this.m_oRendezVousSelection = oRendezVous;

	// Affiche le nouveau rendez-vous selectionne
	this.__HTMLAfficheRendezVousSelection();

	return true;
};

// Indique si si deux rendez-vous sont identiques
WDPlanning.prototype.__bMemeRendezVous = function __bMemeRendezVous(oRendezVous1, oRendezVous2)
{
	// Compare :
	// - Les pointeurs (rapide)
	// - Les IDs (lent) pour le cas ou c'est le meme rendez-vous mais retourne par le serveur
	return ((oRendezVous1 == oRendezVous2) || (oRendezVous1 && oRendezVous2 && (oRendezVous1.m_sID == oRendezVous2.m_sID)));
};

// Clic sur un rendez-vous
WDPlanning.prototype.__OnRendezVousClic = function __OnRendezVousClic(oEvent, oRendezVous)
{
	// Selectionne le rendez-vous
	this.bOnRendezVousSelection(oEvent, oRendezVous);
};

// Double clic sur un rendez-vous
WDPlanning.prototype.__OnRendezVousDoubleClic = function __OnRendezVousDoubleClic(oEvent, oRendezVous)
{
	// Valide que l'on a le droit d'edition
	if (this.m_oParametres.m_bEditionRendezVous)
	{
		// Valide avec le PCode (le rendez-vous est normalement deja selectionne par le clic)
		if (this.__bAppelPCode(this.ms_nEventNavAgendaRdvEdition, undefined, oEvent, oRendezVous))
		{
			// Entre en saisie
			this.m_oPopupSaisie.Debut(oRendezVous.m_oDiv, 0, oRendezVous);
		}
	}
};

// Fin de la modification d'un rendez-vous (= fin du double clic)
WDPlanning.prototype.OnRendezVousValideSaisie = function OnRendezVousValideSaisie(oEvent, oRendezVous, sValeur)
{
	var sOldTitre = oRendezVous.m_sTitre;
	// Uniquement si la valeur change (pas d'appel serveur inutile)
	if (sValeur != sOldTitre)
	{
		oRendezVous.m_sTitre = sValeur;

		// Valide avec le PCode (le rendez-vous est normalement deja selectionne par le clic)
		if (!this.__bAppelPCodeConstruitParam(this.ms_nEventNavAgendaRdvModifTitre, this.ms_sActionAgendaRdvModifTitre, oEvent, oRendezVous))
		{
			// Refus de la modification
			oRendezVous.m_sTitre = sOldTitre;
		}
	}
};

// Notifie du redimensionnement de la selection
WDPlanning.prototype.OnRendezVousRedimensionne = function OnRendezVousRedimensionne(oEvent, nDebut, nLongueur)
{
	this.__bOnRendezVousDeplacement(oEvent, nDebut, nLongueur);
};

// Notifie du deplacement (et/ou du changement de ressources)
WDPlanning.prototype.OnRendezVousDeplacement = function OnRendezVousDeplacement(oEvent, nDebut, nLongueur, nRessource)
{
	this.__bOnRendezVousDeplacement(oEvent, nDebut, nLongueur, nRessource);
};

// Notifie du deplacement/redimensionnement (et/ou du changement de ressources)
// nRessource != undefined => Deplacement (meme si la ressource ne change pas
WDPlanning.prototype.__bOnRendezVousDeplacement = function __bOnRendezVousDeplacement(oEvent, nDebut, nLongueur, nRessource)
{
	var oRendezVous = this.oGetRendezVousSelection();

	// Calcule la nouvelle position du rendez-vous
	var oOldDateDebut = oRendezVous.m_oDateDebut;
	var oOldDateFin = oRendezVous.m_oDateFin;
	var nOldRessource = oRendezVous.m_nRessource;
	oRendezVous.m_oDateDebut = this.__oGetDateFromPosAlignResolution(nDebut, true);
	oRendezVous.m_oDateFin = this.__oGetDateFromPosAlignResolution(nDebut + nLongueur, false);

	var nPCode;
	var sAction;
	if (nRessource !== undefined)
	{
		// Deplacement
		nPCode = this.ms_nEventNavAgendaRdvDeplacement;
		sAction = this.ms_sActionAgendaRdvDeplacement;

		// Si il y a changement de ressource
		if (nRessource != oRendezVous.m_nRessource)
		{
			oRendezVous.m_nRessource = nRessource;
			if (!this.__bAppelPCode(this.ms_nEventNavPlanningRdvDeplacementRessource, undefined, oEvent, oRendezVous))
			{
				oRendezVous.m_oDateDebut = oOldDateDebut;
				oRendezVous.m_oDateFin = oOldDateFin;
				oRendezVous.m_nRessource = nOldRessource;
				return false;
			}
		}
	}
	else
	{
		// Redimensionnement
		nPCode = this.ms_nEventNavAgendaRdvRedim;
		sAction = this.ms_sActionAgendaRdvRedim;
	}

	// Valide avec le PCode
	if (!this.__bAppelPCodeConstruitParam(nPCode, sAction, oEvent, oRendezVous))
	{
		oRendezVous.m_oDateDebut = oOldDateDebut;
		oRendezVous.m_oDateFin = oOldDateFin;
		if (nRessource !== undefined)
		{
			oRendezVous.m_nRessource = nOldRessource;
		}
		return false;
	}
	return true;
};

// Ajoute un rendez-vous a la position de la selection
WDPlanning.prototype.OnRendezVousAjoute = function OnRendezVousAjoute(oEvent, nDebut, nLongueur, nRessource)
{
	// Creation du rendez-vous
	var oRendezVous = {
		m_nRessource: nRessource,
		m_oDateDebut: this.__oGetDateFromPosAlignResolution(nDebut, true),
		m_oDateFin: this.__oGetDateFromPosAlignResolution(nDebut + nLongueur, false),
		m_sTitre: "",
		m_sContenu: ""
	};

	// Appel le code navigateur
	this.__bAppelPCodeConstruitParam(this.ms_nEventNavAgendaRdvAjoute, this.ms_sActionAgendaRdvAjoute, oEvent, oRendezVous);
};

// Supprime le rendez-vous selectionn
WDPlanning.prototype.__OnRendezVousSupprime = function __OnRendezVousSupprime(oEvent)
{
	// Appel le code navigateur
	var oRendezVous = this.oGetRendezVousSelection();
	this.__bAppelPCodeConstruitParam(this.ms_nEventNavAgendaRdvSupprime, this.ms_sActionAgendaRdvSupprime, oEvent, oRendezVous);
};

// Notifie de la selection
WDPlanning.prototype.bOnPeriodeSelect = function bOnPeriodeSelect(oEvent, nDebut, nLongueur, nRessource)
{
	// @@@ Place les valeurs pour le code navigateur
	//	...

	// Appel le code navigateur
	if (!this.__bAppelPCode(this.ms_nEventNavAgendaPeriodeSelect, undefined, oEvent))
	{
		// @@@ Retablie les valeurs originales
		//		...
		return false;
	}

	return true;
};

// Changement de periode
// - Precedente
WDPlanning.prototype.__OnAffichePeriodePrecedente = function __OnAffichePeriodePrecedente(oEvent)
{
	// Affiche la periode precedente (normalement elle est disponible sinon le bouton n'est pas affiche)
	if (this.m_oParametres.m_oDateDebutPrecedente)
	{
		this.__OnAffichePeriode(oEvent, this.m_oParametres.m_oDateDebutPrecedente);
	}
};
// - Suivante
WDPlanning.prototype.__OnAffichePeriodeSuivante = function __OnAffichePeriodeSuivante(oEvent)
{
	// Affiche la periode suivante (normalement elle est disponible sinon le bouton n'est pas affiche)
	if (this.m_oParametres.m_oDateDebutSuivante)
	{
		this.__OnAffichePeriode(oEvent, this.m_oParametres.m_oDateDebutSuivante);
	}
};
// - Methode commune
WDPlanning.prototype.__OnAffichePeriode = function __OnAffichePeriode(oEvent, oDateDebutPeriode)
{
	// Force la date de debut (pour la construction des parametres)
	var oOldDateDebut = this.m_oParametres.m_oDateDebut;
	this.m_oParametres.m_oDateDebut = oDateDebutPeriode;

	this.__bAppelPCodeConstruitParam(this.ms_nEventNavAgendaPeriodeAffiche, this.ms_sActionAgendaPeriodeAffiche, oEvent);

	// Restaure la date de debut (pour garder la coherence le temps du retour serveur)
	this.m_oParametres.m_oDateDebut = oOldDateDebut;
};

// - Appel des PCodes

// Appel d'un PCode navigateur avec transmission d'un rendezvous + creation des parametres serveurs
WDPlanning.prototype.__bAppelPCodeConstruitParam = function __bAppelPCodeConstruitParam(ePCodeNav, sActionServeur, oEvent, oRendezVous)
{
	// Construit les parametres pour le serveur
	if (oRendezVous)
	{
		this.ConstruitParam(oRendezVous);
	}
	else
	{
		this.ConstruitParam();
	}

	return this.__bAppelPCode(ePCodeNav, sActionServeur, oEvent, oRendezVous);
};

// Appel d'un PCode navigateur avec transmission (optionnelle) d'un rendezvous
WDPlanning.prototype.__bAppelPCode = function __bAppelPCode(ePCodeNav, sActionServeur, oEvent, oRendezVous)
{
	// Si on a un rendezvous, construit le type avance correspondant et le transmet au PCode
	var oRes = this.RecuperePCode(ePCodeNav)(oEvent, sActionServeur, oRendezVous ? new WDRendezVous(this, oRendezVous) : undefined);
	// Aucun retour ou Retour = (exactement) true
	if ((oRes === undefined) || (oRes === true))
	{
		return true;
	}
	// Retour = (exactement) false
	if (oRes === false)
	{
		return true;
	}
	// Sinon comparaison souple
	return (oRes != false);
};

// - Manipulation des feuilles de style

// Creation d'une feuille de style
WDPlanning.prototype.__oCreeFeuilleStyle = function __oCreeFeuilleStyle()
{
	// Creation de la feuille de style
	var oStyle = document.getElementsByTagName("head")[0].appendChild(document.createElement("style"));
	if (bWK)
	{
		oStyle.appendChild(document.createTextNode(""));
	}
	return oStyle.styleSheet ? oStyle.styleSheet : oStyle.sheet;
};

// Cree le selecteur pour une classe
WDPlanning.prototype.__sGetSelecteur = function __sGetSelecteur(sClasse1, sTag, sClasse2)
{
	var tabSelecteur = [];
	tabSelecteur.push('#' + this.m_sAliasChamp + this.ms_sSuffixeHote);
	if (sClasse1 !== undefined)
	{
		tabSelecteur.push('.' + sClasse1);
	}
	if (sClasse2 !== undefined)
	{
		tabSelecteur.push(sTag + '.' + sClasse2);
	}
	else
	{
		tabSelecteur.push(sTag);
	}
	return tabSelecteur.join(' ');
};

// Creation d'un style pour tout les champs planning
WDPlanning.prototype.__StyleCreeGlobal = function __StyleCreeGlobal(sNomStyle, tabStyle)
{
	CreeStyle(this.ms_oFeuilleStyleGlobale, sNomStyle, tabStyle.join(';'));
};

// Creation ou modification d'un style pour le champ courant
WDPlanning.prototype.__StyleCree = function __StyleCree(sNomStyle, tabStyle)
{
	// Supprime le style
	this.__StyleSupprime(sNomStyle);
	// Et le recree
	CreeStyle(this.m_oFeuilleStyle, sNomStyle, tabStyle.join(';'));
};

// Supprime un style
WDPlanning.prototype.__StyleSupprime = function __StyleSupprime(sNomStyle)
{
	var nStyle = this.__nStyleTrouve(sNomStyle);
	if (-1 != nStyle)
	{
		if (bIE)
		{
			this.m_oFeuilleStyle.removeRule(nStyle);
		}
		else
		{
			this.m_oFeuilleStyle.deleteRule(nStyle);
		}
	}
};

// Complete un style
WDPlanning.prototype.__StyleComplete = function __StyleComplete(sNomStyle, tabStyle)
{
	// Trouve le style
	var nStyle = this.__nStyleTrouve(sNomStyle);
	if (-1 != nStyle)
	{
		// Le modifie
		var i;
		var nLimiteI = tabStyle.length;
		for (i = 0; i < nLimiteI; i++)
		{
			var tabTemp = tabStyle[i].split(":");
			this.m_oFeuilleStyleRules[nStyle].style[tabTemp[0]] = tabTemp[1];
		}
	}
	else
	{
		// Non trouve : le cree
		CreeStyle(this.m_oFeuilleStyle, sNomStyle, tabStyle.join(';'));
	}
};

// Trouve un style
WDPlanning.prototype.__nStyleTrouve = function __nStyleTrouve(sNomStyle)
{
	// Recherche le style dans la feuille de style locale
	var tabRules = this.m_oFeuilleStyleRules;
	var i;
	var nLimiteI = tabRules.length;
	for (i = 0; i < nLimiteI; i++)
	{
		if (tabRules[i].selectorText == sNomStyle)
		{
			return i;
		}
	}

	// Non trouve
	return -1;
};

// - Affichage general

WDPlanning.prototype.__nGetClientWidth = function __nGetClientWidth(oElement)
{
	// La consultation des clientXxx declenche un appel de onscroll
	this.m_bDansGetDefilement = true;
	var nRes = oElement.clientWidth;
	this.m_bDansGetDefilement = false;
	return nRes;
};
WDPlanning.prototype.__nGetClientHeight = function __nGetClientHeight(oElement)
{
	// La consultation des clientXxx declenche un appel de onscroll
	this.m_bDansGetDefilement = true;
	var nRes = oElement.clientHeight;
	this.m_bDansGetDefilement = false;
	return nRes;
};

// Recupere la largeur totale de la zone cible
WDPlanning.prototype.__nGetLargeur = function __nGetLargeur()
{
	return this.__nGetClientWidth(this.m_oHote);
//	return this._nGetOffsetWidth(this.m_oHote);
};

// Recupere la hauteur totale de la zone cible
WDPlanning.prototype.__nGetHauteur = function __nGetHauteur()
{
	// La consultation des clientXxx declenche un appel de onscroll
	this.m_bDansGetDefilement = true;
	var nRes = this._nGetOffsetHeight(this.m_oHote);
	this.m_bDansGetDefilement = false;
	return nRes;
};

// Recupere le defilement
WDPlanning.prototype._nGetDefilementVertical = function _nGetDefilementVertical()
{
	// La consultation des scrollXxx declenche un appel de onscroll
	this.m_bDansGetDefilement = true;
	var nRes = this.m_oHoteCorps.scrollTop;
	this.m_bDansGetDefilement = false;
	return nRes;
};
WDPlanning.prototype._nGetDefilementHorizontal = function _nGetDefilementHorizontal()
{
	// La consultation des scrollXxx declenche un appel de onscroll
	this.m_bDansGetDefilement = true;
	var nRes = this.m_oHoteCorps.scrollLeft;
	this.m_bDansGetDefilement = false;
	return nRes;
};
// Fixe le defilement
WDPlanning.prototype._SetDefilementVertical = function _SetDefilementVertical(nDefilement)
{
	this.m_oHoteCorps.scrollTop = nDefilement;
};
WDPlanning.prototype._SetDefilementHorizontal = function _SetDefilementHorizontal(nDefilement)
{
	this.m_oHoteCorps.scrollLeft = nDefilement;
};

// Construit le style pour une dimension (stricte si demande) dans le sens largueur/hauteur
WDPlanning.prototype.__tabInitCSS_Dimension = function __tabInitCSS_Dimension(tabStyle, nDimensionPx, sDimension, bStrict)
{
	var sTemp = sDimension + ":" + nDimensionPx + "px";
	tabStyle.push(sTemp);
	if (bStrict)
	{
		tabStyle.push("min-" + sTemp);
		tabStyle.push("max-" + sTemp);
	}
	return tabStyle;
};
WDPlanning.prototype._tabInitCSS_DimensionLargeur = function _tabInitCSS_DimensionLargeur(tabStyle, nDimensionPx, nPaddingLargeur, nPaddingHauteur, bStrict)
{
	return this.__tabInitCSS_Dimension(tabStyle, nDimensionPx - nPaddingLargeur, "width", bStrict);
};
WDPlanning.prototype._tabInitCSS_DimensionHauteur = function _tabInitCSS_DimensionHauteur(tabStyle, nDimensionPx, nPaddingLargeur, nPaddingHauteur, bStrict)
{
	if (bStrict)
	{
		tabStyle.push("line-height:" + (nDimensionPx - nPaddingHauteur) + "px");
	}
	return this.__tabInitCSS_Dimension(tabStyle, nDimensionPx - nPaddingHauteur, "height", bStrict);
};

// Construit le style pour les bordures dans le sens haut/bas ou droite/gauche
WDPlanning.prototype.__tabInitCSS_BorduresMoitie = function __tabInitCSS_BorduresMoitie(tabStyle, oStyleDebut, sDebut, oStyleFin, sFin, bFinPointille)
{
	// Bordure du debut (ici haut)
	if (oStyleDebut && (0 < oStyleDebut.m_nBordureV))
	{
		tabStyle.push("border-" + sDebut + ":solid " + oStyleDebut.m_nBordureV + "px " + oStyleDebut.m_cBordureV);
	}
	// Bordure de la fin (ici bas)
	if (oStyleFin && (0 < oStyleFin.m_nBordureV))
	{
		tabStyle.push("border-" + sFin + ":" + (bFinPointille ? "dotted" : "solid") + " " + oStyleFin.m_nBordureV + "px " + oStyleFin.m_cBordureV);
	}
	return tabStyle;
};
WDPlanning.prototype._tabInitCSS_BorduresHautBas = function _tabInitCSS_BorduresHautBas(tabStyle, oStyleDebut, oStyleFin, bFinPointille)
{
	return this.__tabInitCSS_BorduresMoitie(tabStyle, oStyleDebut, "top", oStyleFin, "bottom", bFinPointille);
};
WDPlanning.prototype._tabInitCSS_BorduresGaucheDroite = function _tabInitCSS_BorduresGaucheDroite(tabStyle, oStyleDebut, oStyleFin, bFinPointille)
{
	return this.__tabInitCSS_BorduresMoitie(tabStyle, oStyleDebut, "left", oStyleFin, "right", bFinPointille);
};

// Style des titres horizontaux et verticaux
WDPlanning.prototype.__InitCSS_TitresHorizontal = function __InitCSS_TitresHorizontal()
{
	// Dimension des div avec le contenu
	this.__StyleCree(this.__sGetSelecteur(this.ms_sNomTitresHorizontal, "div", undefined), ["height:" + this.m_oParametres.m_nHauteurTitresHorizontal + "px"]);
};
WDPlanning.prototype.__InitCSS_TitresVertical = function __InitCSS_TitresVertical()
{
	// Dimension des div avec le contenu
	this.__StyleCree(this.__sGetSelecteur(this.ms_sNomTitresVertical, " div", undefined), ["width:" + (this.m_oParametres.m_nHauteurTitresVertical - this.ms_nPaddingTitreCalcul) + "px"]);
};

// Styles des rendez-vous
WDPlanning.prototype.__InitCSS_RendezVous = function __InitCSS_RendezVous()
{
	// Le style des rendez-vous
	this.__InitCSS_RendezVous_UnStyle("m_oStyleRendezVous", this.ms_sNomRendezVous);
	// Le style du rendez-vous selectionne
	this.__InitCSS_RendezVous_UnStyle("m_oStyleRendezVousSelect", this.ms_sNomRendezVousSelect);
};

// Un des tyles des rendez-vous
WDPlanning.prototype.__InitCSS_RendezVous_UnStyle = function __InitCSS_RendezVous_UnStyle(sStyle, sClass)
{
	// Recupere le style pour le rendez-vous selectionne
	oStyle = this.m_oParametres[sStyle];

	// Style des bordures (demi-heures)
	var tabStyle;
	if (0 < oStyle.m_nBordureV)
	{
		tabStyle = [ "border:solid " + oStyle.m_nBordureV + "px " + oStyle.m_cBordureV ];

		// En mode quirks, IE9 n'affiche pas les bord arrondi
		if (!bIE || ((8 > nIE) && !bIEQuirks))
		{
			tabStyle.push("border-collapse:separate");
			this.__BorderRadius(tabStyle, 5);

			var nRadiusInterne = Math.max(0, 5 - oStyle.m_nBordureV);
			if (0 < nRadiusInterne)
			{
				var tabStyleHaut = [];
				this.__BorderRadius(tabStyleHaut, nRadiusInterne, true);
				this.__StyleCree(this.__sGetSelecteur(sClass, "", this.ms_sNomRendezVousTitre), tabStyleHaut);
				var tabStyleBas = [];
				this.__BorderRadius(tabStyleBas, nRadiusInterne, false);
				this.__StyleCree(this.__sGetSelecteur(sClass, "", this.ms_sNomRendezVousBas), tabStyleBas);
			}
		}
		if (this.m_oParametres.m_bRedimensionnementRendezVous)
		{
			this.__StyleCree(this.__sGetSelecteur(sClass, "", this.ms_sNomRendezVousRedimDebut), ["cursor:" + this.ms_sCurseurRedim]);
			this.__StyleCree(this.__sGetSelecteur(sClass, "", this.ms_sNomRendezVousRedimFin), ["cursor:" + this.ms_sCurseurRedim]);
		}
		this.__StyleCree(this.__sGetSelecteur(undefined, "", sClass), tabStyle);
	}

	var nPadding = this.__nGetRendezVousEpaisseurBordure(oStyle);
	if (nPadding)
	{
		tabStyle = ["padding-left:" + nPadding + "px", "padding-right:" + nPadding + "px"];
		// Si besoin ajoute un deplacement de l'image
		if (bIEQuirks && (8 > nIE))
		{
			tabStyle.push("-ms-background-position-x:" + nPadding + "px");
		}
		else
		{
			tabStyle.push("background-position-x:" + nPadding + "px");
		}
		this.__StyleCree(this.__sGetSelecteur(undefined, "", sClass + " td"), tabStyle);
	}
};

WDPlanning.prototype.__BorderRadius = function __BorderRadius(tabStyle, nRadius, bTop)
{
	var tabBorderRadius = [];
	if (bFF)
	{
		tabBorderRadius.push("-moz");
	}
	else if (bWK)
	{
		tabBorderRadius.push("-webkit");
	}
	tabBorderRadius.push("border");
	tabBorderRadius.push("radius");
	tabBorderRadius = [tabBorderRadius.join('-')];
	tabBorderRadius.push(':');
	var nRadiusTop = ((bTop === undefined) || bTop) ? nRadius : 0;
	var nRadiusBottom = ((bTop === undefined) || !bTop) ? nRadius : 0;
	tabBorderRadius.push(nRadiusTop);
	tabBorderRadius.push("px ");
	tabBorderRadius.push(nRadiusTop);
	tabBorderRadius.push("px ");
	tabBorderRadius.push(nRadiusBottom);
	tabBorderRadius.push("px ");
	tabBorderRadius.push(nRadiusBottom);
	tabBorderRadius.push("px");
	tabStyle.push(tabBorderRadius.join(""));
};

// Construit un div simple (avec une class et un contenu optionnel)
// tabHTML est mdofie en sortie
WDPlanning.prototype.__HTMLAfficheDiv = function __HTMLAfficheDiv(tabHTML, sClass, sId, sContenu, sCouleurFond)
{
	tabHTML.push("<div");
	if (sClass)
	{
		tabHTML.push(" class=\"");
		tabHTML.push(sClass);
		tabHTML.push("\"");
	}
	if (sId)
	{
		tabHTML.push(" id=\"");
		tabHTML.push(sId);
		tabHTML.push("\"");
	}
	if (sCouleurFond)
	{
		tabHTML.push(" style=\"background-color:");
		tabHTML.push(sCouleurFond);
		tabHTML.push("\"");
	}
	tabHTML.push(">");
	if (sContenu && sContenu.length)
	{
		tabHTML.push(sContenu);
	}
	else if (bIEQuirks)
	{
		tabHTML.push("<!-- -->");
	}
	tabHTML.push("</div>");
};

// Affiche le contenu
// bRAZ : indique s'il faut supprimer le precedent contenu
WDPlanning.prototype.__HTMLAfficheContenu = function __HTMLAfficheContenu(bRAZ, bAvecCSS, bRAZDejaFait)
{
	if (bRAZ && !bRAZDejaFait)
	{
		this.__HTMLVideContenu();
	}

	// Initialise le tableau des positions des heures
	this.__InitPositionsHeures();

	// Decale pour avoir this.m_nDimensionPxZoneHeures (intialise par __InitPositionsHeures)
	// Styles des heures
	if (bAvecCSS)
	{
		if (bRAZ)
		{
			this.__InitCSS();
			// Il faut refaire cette init car __InitCSS a supprimer la feuille de style
			this._vInitCSS_LibJour();
		}
		// On ne peut calculer ce style que maintenant (que l'on a this.m_nDimensionPxZoneHeures)
		this.__StyleComplete(this.__sGetSelecteur(undefined, "", this.ms_sNomCorpsDimensionTotale), [this.ms_sStyleDimension + ":" + this.m_nDimensionPxZoneHeures + "px"]);
		this.__InitCSS_Heures();
	}

	// Construit la zone de bouton de changement de periode
	this.__HTMLAfficheBoutonsPeriode();
	// Construit les zones des titres
	this.__HTMLAfficheTitresHorizontal();
	this.__HTMLAfficheTitresVertical();
	// Construit la zone des rendez vous
	this.__HTMLAfficheCorps();
	// Construit les rendez-vous
	this.__HTMLAfficheRendezVous();
	// Et affiche le rendez-vous selectionne
	this.__HTMLAfficheRendezVousSelection();

	// Declenche la synchronisation des scrolling (et des largeurs)
	this.nSetTimeoutUnique("OnDefilementCorps", 1);

	// Sauve les parametres (pour avoir le tableau des anciens rendez-vous lors du reaffichage)
	this.m_oOldDonnees = this.m_oDonnees;
};

// Supprime le contenu
WDPlanning.prototype.__HTMLVideContenu = function __HTMLVideContenu()
{
	this.__HTMLVideRendezVousSelection();
	this.__HTMLVideRendezVous();
	this.__HTMLVideCorps();
	this.__HTMLVideTitresVertical();
	this.__HTMLVideTitresHorizontal();
	this.__HTMLVideBoutonsPeriode();
};

WDPlanning.prototype.__InitPositionsHeures = function __InitPositionsHeures()
{
	// - Initialise les variables resultat

	// Si on trouve une heure dans aujourd'hui on l'affichera
	this.m_nPositionAujourdhui = -1;
	// Pour facilite la conversion position => Date, on stocke l'heure de debut chaque graduation (bloc html) dans un tableau
	// Si on n'est pas en mode par heure : contient le debut par
	this.m_tabGraduations = [];
	// Dimension totale de la zone des heures
	this.m_nDimensionPxZoneHeures = 0;

	// - Precalculs

	if (this.m_oParametres.m_nResolutionGrille >= 86400000)
	{
		// Si on est en affichage par jour (ou plus)
		// => this.m_oParametres.m_nDimensionPxGraduation contient en fait la hauteur d'un jour
		// 86400000 = 24 * 3600 * 1000 = 1 jour en ms
		this.m_oParametres.m_nGraduationDureeMs = 86400000;
		// Jamais de rupture dans ce mode
		this.m_oParametres.m_nHauteurLibJour = 0;
	}
	else if (this.m_oParametres.m_nResolutionGrille == 43200000)
	{
		// Si on est en affichage par demi-journee (exactement)
		// => this.m_oParametres.m_nDimensionPxGraduation contient en fait la hauteur d'un jour
		// On affiche une seule zone pour la journee
		// 86400000 = 24 * 3600 * 1000 = 1 jour en ms
		this.m_oParametres.m_nGraduationDureeMs = 86400000;
	}
	else
	{
		// Si on est en affichage par heure
		// 3600000 = 3600 * 1000 = 1 heure en ms
		this.m_oParametres.m_nGraduationDureeMs = 3600000;
	}

	// Calcule les heures ouvrables (arrondi a l'heure pres)
	// => On corrige la valeur des parametres pour ne pas refaire le calcul partout
	// Ces 4 valeurs sont en heures (et pas en ms commes les valeurs de this.m_oParametres)
	var nHeureOuvrableMin, nHeureOuvrableMax, nHeureAfficheMin, nHeureAfficheMax;

	// Si on est en affichage par heure prend les valeurs transmisses
	if (this.m_oParametres.m_nGraduationDureeMs == 3600000)
	{
		nHeureOuvrableMin = this.__nGetHeureArrondiDefaut(this.m_oParametres.m_nHeureOuvrableMin);
		nHeureOuvrableMax = this.__nGetHeureArrondiExces(this.m_oParametres.m_nHeureOuvrableMax);
		nHeureAfficheMin = this.__nGetHeureArrondiDefaut(this.m_oParametres.m_nHeureAfficheMin);
		nHeureAfficheMax = this.__nGetHeureArrondiExces(this.m_oParametres.m_nHeureAfficheMax);
	}
	else
	{
		// En affichage par demi-journee ou par journee
		nHeureOuvrableMin = 0;
		nHeureOuvrableMax = 24;
		nHeureAfficheMin = 0;
		nHeureAfficheMax = 24;
	}

	// Reforce les valeurs corrigees
	this.m_oParametres.m_nHeureOuvrableMin = nHeureOuvrableMin * 3600000;
	this.m_oParametres.m_nHeureOuvrableMax = nHeureOuvrableMax * 3600000;
	this.m_oParametres.m_nHeureAfficheMin = nHeureAfficheMin * 3600000;
	this.m_oParametres.m_nHeureAfficheMax = nHeureAfficheMax * 3600000;

	// Calcule aujourdhui
	var oAujourdhui = new Date();
	oAujourdhui.setUTCHours(0, 0, 0, 0);
	var nAjourdhui = oAujourdhui.getTime();
	// 86400000 = 24 * 3600 * 1000 = 1 jour en ms
	var nDemain = nAjourdhui + 86400000;

	var oHeure = new Date(this.m_oParametres.m_oDateDebut);
	oHeure.setUTCMinutes(0, 0, 0);

	// Commence a -1 car des le debut on va passer au jour suivant
	var nJour = -1;
	var oJour;
	var nPosition = 0;
	var bRupture = false;

	// - Boucle de calcul
	for (; oHeure < this.m_oParametres.m_oDateFin; oHeure.setTime(oHeure.getTime() + this.m_oParametres.m_nGraduationDureeMs))
	{
		var nHeure = oHeure.getUTCHours();

		// Teste si on change de jour et que l'on doit alors affiche une rupture de jour
		// Ou si on est sur la premiere ligne
		if ((0 == nHeure) || (nJour == -1))
		{
			nJour++;
			// Trouve la description du jour
			oJour = this.m_oParametres.m_tabJours[nJour];

			if (oJour.m_bAujourdhui)
			{
				this.m_nPositionAujourdhui = nPosition;
			}

			// Affiche les ruptures de jour (si besoin)
			// Si on n'a pas de ruptures, this.m_oParametres.m_nHauteurLibJour n'est pas defini ou est a 0
			bRupture = true;
			if (this.m_oParametres.m_nHauteurLibJour)
			{
				nPosition += this.m_oParametres.m_nHauteurLibJour;
			}
		}

		// Si l'heure n'est pas affichee
		if ((nHeure < nHeureAfficheMin) || (nHeure >= nHeureAfficheMax))
		{
			// N'ecrase pas bRupture cra on veux la premiere heure du jour courant)
			continue;
		}

		// Objet resultat
		var oGraduation = {
			m_nDateDebut : oHeure.getTime(),
			m_nMois : oHeure.getMonth(),
			m_nPosition : nPosition,
			m_nHeureStyle: this.__nGetHeureStyle(oHeure.getDay(), oJour.m_bFerie, nHeure, nHeureOuvrableMin, nHeureOuvrableMax)
		};
		oGraduation.m_sHeureClasses = this.__sGetHeureClasses(oGraduation.m_nHeureStyle, oGraduation.m_nDateDebut, nAjourdhui, nDemain);

		if (bRupture)
		{
			oGraduation.m_bRupture = bRupture;
			oGraduation.m_sRuptureLibelle = oJour.m_sLibelle;
			bRupture = false;
		}
		if (oGraduation.m_nHeureStyle > 0)
		{
			// Si on a un style d'heure non standard on reforce la couleur de fond
			oGraduation.m_sCouleurFond = this.m_oParametres["m_oStyle" + this.ms_tabHeureSuffixe[oGraduation.m_nHeureStyle]].m_cFond;
		}
		// Affiche le libelle des heures/jours selon le mode
		if ((this.m_oParametres.m_nResolutionGrille >= 86400000) || ((this.m_oParametres.m_nResolutionGrille == 43200000) && !this.m_oParametres.m_nHauteurLibJour))
		{
			// Libelle du jour avec le style de la rupture :
			// - Si on est en affichage par jour (ou plus)
			// - Si on est en affichage par demi-journee (exactement) + sans ruptures
			oGraduation.m_sLibelle = oJour.m_sLibelle;
			oGraduation.m_sLibelleClasse = this.m_oParametres.m_oStyleLibJourSemaine.m_sClasses;
			oGraduation.m_sLibelleCouleurFond = this.m_oParametres.m_oStyleLibJourSemaine.m_cFond;
		}
		else
		{
			// Si on est en affichage par demi-journee (exactement) + avec ruptures
			// Si on est en affichage par heure : libelle des heures avec la classe par defaut, sinon rien
			oGraduation.m_sLibelle = (this.m_oParametres.m_nResolution != 43200000) ? this.__sHTMLAfficheFormateHeure(nHeure) : "";
			oGraduation.m_sLibelleClasse = this.m_oParametres.m_oStyleLibHeure.m_sClasses;
			// Pas de couleur de fond
		}

		this.m_tabGraduations.push(oGraduation);

		nPosition += this.m_oParametres.m_nDimensionPxGraduation;
	}

	this.m_nDimensionPxZoneHeures = nPosition;
};

// Calcule le style d'une heure
WDPlanning.prototype.__nGetHeureStyle = function __nGetHeureStyle(nJourSemaine, bFerie, nHeure, nHeureOuvrableMin, nHeureOuvrableMax)
{
	// Par ordre de priorite :

	if (bFerie)
	{
		// - Si c'est un jour ferie
		return 5;
	}
	else if ((nHeure < nHeureOuvrableMin) || (nHeure >= nHeureOuvrableMax))
	{
		// - Si l'heure est non ouvrable
		return 1;
	}
	else
	{
		// - L'heure est ouvrable : prend le style du jour
		switch (nJourSemaine)
		{
		case 6:
			// Samedi
			return 3;
		case 0:
			// Dimanche
			return 4;
		default:
			// Par defaut le style est celui d'une heure ouvrable
			return 0;
		}
	}
};

// Calcule la/les classe(s) a utiliser pour une heure
WDPlanning.prototype.__sGetHeureClasses = function __sGetHeureClasses(nHeureStyle, nDateDebutHeure, nAjourdhui, nDemain)
{
	var tabClasseTypeHeure = [this.ms_sNomHeure];
	tabClasseTypeHeure.push("WDPLN-" + this.ms_tabHeureSuffixe[nHeureStyle]);

	// Si on est dans aujourdhui
	if ((nDateDebutHeure >= nAjourdhui) && (nDateDebutHeure < nDemain))
	{
		tabClasseTypeHeure.push("WDPLN-" + this.ms_tabHeureSuffixe[2]);
	}
	return tabClasseTypeHeure.join(" ");
};

// Formatage d'une heure pour affichage
WDPlanning.prototype.__sHTMLAfficheFormateHeure = function __sHTMLAfficheFormateHeure(nHeure)
{
	// Trouve l'heure qui correspond
	return this.m_oParametres.m_tabFormatHeure[nHeure];
};

// Construit la zone des rendez vous
WDPlanning.prototype.__HTMLAfficheCorps = function __HTMLAfficheCorps()
{
	var tabHTML = [];
	tabHTML.push("<table><tr><td ");
	tabHTML.push(this.ms_bTableTrParRessource ? "rowspan" : "colspan");
	tabHTML.push("=\"");
	tabHTML.push(this.m_oDonnees.m_tabRessources.length);
	tabHTML.push("\" class=\"");
	tabHTML.push(this.ms_sNomCorpsQuadrillage);
	tabHTML.push("\"><div>");

	// On construit en parallele les DIVs pour la couleur de fond et pour la couleur
	var tabHTMLFondCouleur = this.__tabHTMLAfficheCorpsHeureDebut(this.ms_sNomFondCouleur);
	var tabHTMLFondBordure = this.__tabHTMLAfficheCorpsHeureDebut(this.ms_sNomFondBordure);

	// Selon la position des heures initialise
	var tabGraduations = this.m_tabGraduations;
	var i;
	var nLimiteI = tabGraduations.length;
	for (i = 0; i < nLimiteI; i++)
	{
		var oGraduation = tabGraduations[i];

		// Si on a une rupture : ajoute l'espace
		if (oGraduation.m_bRupture && this.m_oParametres.m_nHauteurLibJour)
		{
			// La partie avec la couleur : dessous : div vide
			this.__HTMLAfficheDiv(tabHTMLFondCouleur, this.ms_sNomJour);
			// La partie avec les bordures : dessous : div vide
			this.__HTMLAfficheDiv(tabHTMLFondBordure, this.ms_sNomJour);
		}

		// La partie avec la couleur : dessous
		this.__HTMLAfficheDiv(tabHTMLFondCouleur, oGraduation.m_sHeureClasses, undefined, undefined, oGraduation.m_sCouleurFond);

		// La partie avec la bordure : dessus
		tabHTMLFondBordure.push("<div class=\"");
		tabHTMLFondBordure.push(oGraduation.m_sHeureClasses);
		tabHTMLFondBordure.push("\">");
		// Si on n'est pas en affichage a la journee (mais la demi-journee est acceptee)
		if (this.m_oParametres.m_nResolutionGrille < 86400000)
		{
			this.__HTMLAfficheDiv(tabHTMLFondBordure, this.ms_sNomHeureDemi);
		}
		else
		{
			if (bIEQuirks)
			{
				tabHTMLFondBordure.push("<!-- -->");
			}
		}
		tabHTMLFondBordure.push("</div>");
	}

	// Ferme les tableaux
	tabHTMLFondCouleur.push("</div>");
	tabHTMLFondBordure.push("</div>");
	// Et les fusionne avec le tableau global
	tabHTML = tabHTML.concat(tabHTMLFondCouleur);
	tabHTML = tabHTML.concat(tabHTMLFondBordure);

	tabHTML.push("</div></td>");
	if (!this.ms_bTableTrParRessource)
	{
		tabHTML.push("</tr><tr class=\"");
		tabHTML.push(this.ms_sNomCorpsDimensionTotale);
		tabHTML.push("\">");
	}

	nLimiteI = this.m_oDonnees.m_tabRessources.length;
	for (i = 0; i < nLimiteI; i++)
	{
		// Sauf si c'est la premiere (ouverte au dessus)
		if ((this.ms_bTableTrParRessource) && (i != 0))
		{
			tabHTML.push("<tr class=\"");
			tabHTML.push(this.ms_sNomCorpsDimensionTotale);
			tabHTML.push("\">");
		}
		tabHTML.push("<td class=\"");
		tabHTML.push(this.ms_sNomRessource);
		if (i == 0)
		{
			tabHTML.push(" " + this.ms_sNomPremier);
		}
		tabHTML.push("\">");
		this.__HTMLAfficheDiv(tabHTML, this.ms_sNomRessource + " " + this.ms_sNomCorpsDimensionTotale);
		this.__HTMLAfficheDiv(tabHTML, this.ms_sNomRessourceConteneur + " " + this.ms_sNomCorpsDimensionTotale, this.sGetNomElement(this.sGetSuffixeIDElement(this.ms_sNomRessource, i)));
		tabHTML.push("</td>");
		if (this.ms_bTableTrParRessource)
		{
			tabHTML.push("</tr>");
		}
	}

	// Si on n'a pas une ligne par ressource, il faut au minimum un td pour avoir la taille
	if (0 == nLimiteI)
	{
		if (!this.ms_bTableTrParRessource)
		{
			tabHTML.push("<td/>");
		}
		else
		{
			tabHTML.push("<td>");
			this.__HTMLAfficheDiv(tabHTML, this.ms_sNomCorpsDimensionTotale);
			tabHTML.push("</td>");
		}
	}

	// Si on a ouvert un tr spécifiquement, ou si on n'a jamais fermer le premier (cas this.ms_bTableTrParRessource + 0 == nLimiteI)
	if (!this.ms_bTableTrParRessource || (0 == nLimiteI))
	{
		tabHTML.push("</tr>");
	}
	tabHTML.push("</table>");

	this.m_oHoteCorps.innerHTML = tabHTML.join("");

	// Gestion du clic sur les ressources
	var tabRessources = this.m_oDonnees.m_tabRessources;
	for (i = 0; i < nLimiteI; i++)
	{
		tabRessources[i].m_oDiv = this.oGetElementById(document, this.sGetSuffixeIDElement(this.ms_sNomRessource, i));
		this.m_oDragPeriodeSelect.InitElement(tabRessources[i], tabRessources[i].m_oDiv);
	}

	// Si on a une position existante pour la meme zone
	if ((this.m_nDefilementPrincipal !== undefined) && (this.m_oDefilementPrincipalDate.getTime() == this.m_oParametres.m_oDateDebut.getTime()))
	{
		this._vSetDefilementPrincipal(this.m_nDefilementPrincipal);
	}
	else
	{
		// Si possible se place sur aujourdhui
		this._vSetDefilementPrincipal((-1 != this.m_nPositionAujourdhui) ? this.m_nPositionAujourdhui : 0);
		this.m_oDefilementPrincipalDate = this.m_oParametres.m_oDateDebut;
	}
	// Reforce la position (si on va trop loin)
	this.m_nDefilementPrincipal = this._vnGetDefilementPrincipal();

	// Si on a une position existante pour la meme zone
	if ((this.m_nDefilementLateral !== undefined) && (this.m_nDefilementLateralNbRessources == this.m_oDonnees.m_tabRessources.length))
	{
		this._vSetDefilementLateral(this.m_nDefilementLateral);
	}
	else
	{
		// Si possible se place en haut
		this._vSetDefilementLateral(0);
		this.m_nDefilementLateralNbRessources = this.m_oDonnees.m_tabRessources.length;
	}
	// Reforce la position (si on va trop loin)
	this.m_nDefilementLateral = this._vnGetDefilementLateral();

};

// Construit le debut du HTML des zone de couleur
WDPlanning.prototype.__tabHTMLAfficheCorpsHeureDebut = function __tabHTMLAfficheCorpsHeureDebut(sClasse)
{
	// On construit en parallele les DIVs pour la couleur de fond et pour la couleur
	var tabHTML = [];

	tabHTML.push("<div class=\"");
	tabHTML.push(sClasse);
	tabHTML.push("\">");

	return tabHTML;
};

// Supprime le HTML du conteneur
WDPlanning.prototype.__HTMLVideCorps = function __HTMLVideCorps()
{
	// Libere le hook sur les ressources
	var tabRessources = this.m_oOldDonnees.m_tabRessources;
	var i;
	var nLimiteI = tabRessources.length;
	for (i = 0; i < nLimiteI; i++)
	{
		this.m_oDragPeriodeSelect.LibereElement(tabRessources[i], tabRessources[i].m_oDiv);
		tabRessources[i].m_oDiv = null;
		delete tabRessources[i].m_oDiv;
	}

	SupprimeFils(this.m_oHoteCorps);
};

// Construit la zone de bouton de changement de periode
WDPlanning.prototype.__HTMLAfficheBoutonsPeriode = function __HTMLAfficheBoutonsPeriode()
{
	var nNbBoutons = (this.m_oParametres.m_oDateDebutPrecedente ? 1 : 0) + (this.m_oParametres.m_oDateDebutSuivante ? 1 : 0);

	// Ajoute un div vide ou une table si on a les bouton de changement de periode
	if (0 < nNbBoutons)
	{
		var tabHTML = [];
		var nDimension = Math.min(this.m_oParametres.m_nHauteurTitresHorizontal, parseInt(this.m_oParametres.m_nLargeurTitresVertical / nNbBoutons, 10));

		// Si on a au moins un des boutons : ajoute une table (on a deja le DIV avec la taille)
		tabHTML.push("<table width=\"100%\" height=\"100%\"><tr>");
		// Premier bouton
		if (this.m_oParametres.m_oDateDebutPrecedente)
		{
			this.__HTMLAfficheUnBoutonPeriode(tabHTML, "__OnAffichePeriodePrecedente", nDimension, this.m_oParametres.m_sImageBtnPeriodePrecedente, this.ms_sImagePeriodePrecedente);
		}
		// Second bouton
		if (this.m_oParametres.m_oDateDebutPrecedente)
		{
			this.__HTMLAfficheUnBoutonPeriode(tabHTML, "__OnAffichePeriodeSuivante", nDimension, this.m_oParametres.m_sImageBtnPeriodeSuivante, this.ms_sImagePeriodeSuivante);
		}
		// TD intermediaire
		if (nDimension == this.m_oParametres.m_nHauteurTitresHorizontal)
		{
			tabHTML.push("<td width=\"100%\"/>");
		}
		tabHTML.push("</tr></table>");
		this.m_oHoteBoutonsPeriode.innerHTML = tabHTML.join("");
	}
};

// Construit le HTML d'un des boutons de changement de periode
WDPlanning.prototype.__HTMLAfficheUnBoutonPeriode = function __HTMLAfficheUnBoutonPeriode(tabHTML, sCallback, nDimension, sImage, sImageDefaut)
{
	tabHTML.push("<td vAlign=\"center\" style=\"background-repeat: no-repeat; background-position: center center; background-image:url(");
	// Si on n'a pas d'image, prend l'image par defaut
	tabHTML.push((!sImage || !sImage.length) ? sImageDefaut : _WD_ + sImage);
	tabHTML.push(")\"");
	if (this.m_oParametres.m_oStyleBtnSuivPrec && this.m_oParametres.m_oStyleBtnSuivPrec.m_sClasses && this.m_oParametres.m_oStyleBtnSuivPrec.m_sClasses.length)
	{
		tabHTML.push(" class=\"");
		tabHTML.push(this.m_oParametres.m_oStyleBtnSuivPrec.m_sClasses);
		tabHTML.push("\"");
	}
	tabHTML.push("><a href=\"javascript:{cl");
	tabHTML.push(this.m_sAliasChamp);
	tabHTML.push(".");
	tabHTML.push(sCallback);
	tabHTML.push("();}\"><img border=\"0\" src=\"");
	tabHTML.push(this.ms_sImageVide);
	tabHTML.push("\" width=\"");
	tabHTML.push(nDimension);
	tabHTML.push("\" height=\"");
	tabHTML.push(nDimension);
	tabHTML.push("\"></a></td>");
};

// Vide la zone des boutons de changement de periode
WDPlanning.prototype.__HTMLVideBoutonsPeriode = function __HTMLVideBoutonsPeriode()
{
	SupprimeFils(this.m_oHoteBoutonsPeriode);
};

// Construit la zone de titres horizontal
WDPlanning.prototype.__HTMLAfficheTitresHorizontal = function __HTMLAfficheTitresHorizontal()
{
	// Genere la table
	var tabHTML = [];
	tabHTML.push("<table class=\"");
	tabHTML.push(this.ms_sNomTitresHorizontal);
	tabHTML.push("\">");
	this._vHTMLAfficheTitresHorizontal(tabHTML);
	tabHTML.push("</table>");
	this.m_oHoteTitresHorizontal.innerHTML = tabHTML.join("");
};

// Supprime le HTML de la zone de titres horizontal
WDPlanning.prototype.__HTMLVideTitresHorizontal = function __HTMLVideTitresHorizontal()
{
	SupprimeFils(this.m_oHoteTitresHorizontal);
};

// Construit la zone de titres vertical
WDPlanning.prototype.__HTMLAfficheTitresVertical = function __HTMLAfficheTitresVertical()
{
	// Genere la table
	var tabHTML = [];
	tabHTML.push("<table class=\"");
	tabHTML.push(this.ms_sNomTitresVertical);
	tabHTML.push("\">");
	this._vHTMLAfficheTitresVertical(tabHTML);
	tabHTML.push("</table>");
	this.m_oHoteTitresVertical.innerHTML = tabHTML.join("");
};

// Supprime le HTML de la zone de titres vertical
WDPlanning.prototype.__HTMLVideTitresVertical = function __HTMLVideTitresVertical()
{
	SupprimeFils(this.m_oHoteTitresVertical);
};

// - Affichage des rendez-vous

// Construit les rendez-vous
WDPlanning.prototype.__HTMLAfficheRendezVous = function __HTMLAfficheRendezVous()
{
	// Le tableau des rendez-vous est trie (calcul sur le serveur)
	// On precalcule la superposition des rendez-vous
	// On recoit un tableau des rendez-vous par ressources
	var tabRessourceRendezVous = this.__tabGetRessourceRendezVous();

	// Affiche les rendez vous par ressources
	var tabRessource = this.m_oDonnees.m_tabRessources;
	var i;
	var nLimiteI = tabRessource.length;
	for (i = 0; i < nLimiteI; i++)
	{
		this.__HTMLAfficheRendezVousRessource(tabRessourceRendezVous, i);
	}
};

// Le tableau des rendez-vous est trie (calcul sur le serveur)
// On precalcule la superposition des rendez-vous
// On recoit un tableau des rendez-vous par ressources
WDPlanning.prototype.__tabGetRessourceRendezVous = function __tabGetRessourceRendezVous()
{
	var tabRessourceRendezVous = [];

	// Creation des tableaux internes
	var tabRessource = this.m_oDonnees.m_tabRessources;
	var i;
	var nLimiteI = tabRessource.length;
	for (i = 0; i < nLimiteI; i++)
	{
		tabRessourceRendezVous.push([]);
	}

	// Et remplissage avec les rendez-vous
	// Normalement tous les indices sont valides (le serveur ne retourne que les rendezvous associees a une ressource)
	// Et comme les rendez-vous sont deja trie, ils seront aussi tri une fois dans les ressources
	var tabRendezVous = this.m_oDonnees.m_tabRendezVous;
	nLimiteI = tabRendezVous.length;
	for (i = 0; i < nLimiteI; i++)
	{
		var oRendezVous = tabRendezVous[i];
		tabRessourceRendezVous[oRendezVous.m_nRessource].push(oRendezVous);
	}

	return tabRessourceRendezVous;
};

// Affiche les rendez vous d'une ressource
WDPlanning.prototype.__HTMLAfficheRendezVousRessource = function __HTMLAfficheRendezVousRessource(tabRessourceRendezVous, nRessource)
{
	// Trouve le conteneur de la ressource
	var oConteneur = this.oGetConteneurRessource(nRessource);
	// Recupere le tableau des rendez-vous pour la ressource
	var tabRendezVous = tabRessourceRendezVous[nRessource];
	var bPremiereRessource = (0 == nRessource);

	// Alloue a chaque rendez-vous une position (avec eventuellement sa superposition)
	// Chaque element du tableau est un objet avec "m_nSuperposition" et "m_nNbSuperpositions"
	var tabRendezVousSuperpositionInfo = this.__tabGetRendezVousSuperpositionInfo(tabRendezVous);

	var i;
	var nLimiteI = tabRendezVous.length;
	for (i = 0; i < nLimiteI; i++)
	{
		// Affiche le rendez-vous
		this.__HTMLAfficheUnRendezVous(tabRendezVous[i], tabRendezVousSuperpositionInfo[i], oConteneur, bPremiereRessource);
	}
};

// Alloue a chaque rendez-vous une position (avec eventuellement sa superposition)
WDPlanning.prototype.__tabGetRendezVousSuperpositionInfo = function __tabGetRendezVousSuperpositionInfo(tabRendezVous)
{
	var nNbRendezVous = tabRendezVous.length;
	// Le tableau avec le resultat
	var tabRendezVousSuperpositionInfo = new Array(nNbRendezVous);

	// Le tableaux de l'etat des superpositions
	var tabSuperpositions = [];

	// Pour la detection du nombre de superpositions :
	// Le nombre de superpositions ne change pas tant qu'il y a un rendez-vous d'affiche pour une meme heure.
	// Donc on detecte le debut d'une zone ou tous est vide.
	var nDebutZone = 0;

	// Alloue a chaque rendez-vous une position
	var i;
	for (i = 0; i < nNbRendezVous; i++)
	{
		var oRendezVous = tabRendezVous[i];

		// Si on n'a aucun aucun rendez-vous (cas apres l'init, on ne passe pas dans la boucle mais la valeur est deja bonne)
		var nPremiereSuperpositionLibre = tabSuperpositions.length;
		var nNbSuperpositionsLibres = 0;

		// Met a jour le contenu des superpositions (et supprime les superpositions inutiles)
		var j;
		for (j = tabSuperpositions.length - 1; j >= 0; j--)
		{
			// Si le rendez-vous existe et est fini
			if (tabSuperpositions[j] && (tabSuperpositions[j].m_oDateFin <= oRendezVous.m_oDateDebut))
			{
				// La superposition n'est plus utilise
				tabSuperpositions[j] = null;
			}
			// Si la superposition est vide
			if (!tabSuperpositions[j])
			{
				// => MAJ de nPremiereSuperpositionLibre (comme on fait un parcours a l'envers la valeur sera bonne a la fin de la boucle)
				nPremiereSuperpositionLibre = j;
				nNbSuperpositionsLibres++;
			}
		}

		// Cree l'objet et note la position
		tabRendezVousSuperpositionInfo[i] = { m_nSuperposition : nPremiereSuperpositionLibre };

		// Si toutes les positions sont vides
		if (tabSuperpositions.length == nNbSuperpositionsLibres)
		{
			// Note le nombre de superpositions dans tous les rendez-vous depuis le dernier RAZ
			// (incremente nDebutZone au passage)
			for (; nDebutZone < i; nDebutZone++)
			{
				tabRendezVousSuperpositionInfo[nDebutZone].m_nNbSuperpositions = tabSuperpositions.length;
			}
			// Puis repart a zero
			tabSuperpositions.length = 0;
//			nDebutZone = i + 1;
		}

		// Place le rendez-vous dans la premiere position de libre
		if (nPremiereSuperpositionLibre == tabSuperpositions.length)
		{
			tabSuperpositions.push(oRendezVous);
		}
		else
		{
			tabSuperpositions[nPremiereSuperpositionLibre] = oRendezVous;
		}
	}

	// Note le nombre de superpositions dans tous les rendez-vous depuis le dernier RAZ
	for (; nDebutZone < i; nDebutZone++)
	{
		tabRendezVousSuperpositionInfo[nDebutZone].m_nNbSuperpositions = tabSuperpositions.length;
	}

	return tabRendezVousSuperpositionInfo;
};

// Affiche un rendez-vous
WDPlanning.prototype.__HTMLAfficheUnRendezVous = function __HTMLAfficheUnRendezVous(oRendezVous, oSuperpositionInfo, oConteneur, bPremiereRessource)
{
	var nDateDebutAff = this.m_oParametres.m_oDateDebut.getTime();
	var nDateFinAff = this.m_oParametres.m_oDateFin.getTime();

	// Duree en ms depuis le debut de l'affichage et le debut du rendez-vous
	// => gere le cas du rendez-vous qui commence avant le debut de l'affichage
	var nDateDebut = Math.max(oRendezVous.m_oDateDebut.getTime(), nDateDebutAff);
	// => gere le cas d'un rendez-vous qui commence dans la zone non affichee
	nDateDebut = this.__nCorrigeDateHeure(nDateDebut, true);

	// Duree en ms entre le debut et la fin du rendez-vous
	// => gere le cas du rendez-vous qui fini apres la fin de l'affichage
	var nDateFin = Math.min(oRendezVous.m_oDateFin.getTime(), nDateFinAff);
	// => gere le cas d'un rendez-vous qui fini dans la zone non affichee
	nDateFin = this.__nCorrigeDateHeure(nDateFin, false);

	// Si le rendez-vous n'est pas visible on ne l'affiche pas
	// WinDev ne fait pas forcement pareil
	if (nDateFin <= nDateDebut)
	{
		return;
	}

	// Creation du div
	var oDiv = document.createElement("div");
	oDiv.style.position = "absolute";
	oDiv.style.zIndex = this.ms_nZIndexRendezVous;
	// Position laterale selon la superposition
	var nDimensionLateralePx = this.nHTMLAfficheUnRendezVousSuperposition(oDiv, oSuperpositionInfo.m_nSuperposition, oSuperpositionInfo.m_nNbSuperpositions, bPremiereRessource);

	var nLongueur = this.__nGetLongueurRendezVous(nDateFin, nDateDebut);

	this.vSetDebut(oDiv, this.__nGetDebutRendezVous(nDateDebut, nDateDebutAff) + "px");
	this.vSetLongueur(oDiv, nLongueur + "px");
	oDiv.id = this.sGetNomElement(this.sGetSuffixeIDElement(this.ms_sNomRendezVous, oRendezVous.m_sID));
	oDiv.className = this.ms_sNomRendezVousExterne;

	// Ajoute dans la ressource
	oDiv = oConteneur.appendChild(oDiv);
	// + son contenu
	oDiv.innerHTML = this._vsGetHTMLRendezVous(oRendezVous, nLongueur, nDimensionLateralePx);
	// + les evenements sur le contenu
	this.__SetRendezVousEvenements(oRendezVous, oDiv);

	// Memorise le DIV dans le rendez-vous
	oRendezVous.m_oDiv = oDiv;
};

// Positionne un rendez-vous en hauteur (ressources en ligne) ou en largeur (ressources en colonne)
// Retourne la dimension laterale (= perpendiculaire ayu passage du temps) du rendez-vous
WDPlanning.prototype.nHTMLAfficheUnRendezVousSuperposition = function nHTMLAfficheUnRendezVousSuperposition(oDiv, nSuperposition, nNbSuperpositions, bPremiereRessource)
{
	// Selon le mode de superposition
	switch (this.m_oParametres.m_eModeSuperposition)
	{
	case this.ms_eSuperpositionDecalage:
		return this.__nHTMLAfficheUnRendezVousSuperpositionDecalage(oDiv, nSuperposition, nNbSuperpositions, bPremiereRessource);
	case this.ms_eSuperpositionCoteACote:
	default:
		return this.__nHTMLAfficheUnRendezVousSuperpositionCoteACote(oDiv, nSuperposition, nNbSuperpositions, bPremiereRessource);
	}
};

// Positionne un rendez-vous en largeur avec un affichage "cote a cote"
// Retourne la dimension laterale (= perpendiculaire ayu passage du temps) du rendez-vous
WDPlanning.prototype.__nHTMLAfficheUnRendezVousSuperpositionCoteACote = function __nHTMLAfficheUnRendezVousSuperpositionCoteACote(oDiv, nSuperposition, nNbSuperpositions, bPremiereRessource)
{
	// Il faut prendre la dimension totale car le conteneur des ressources n'a pas de bordure
	var nDimensionRessources = this.__nGetDimensionPxSansBordureRessources(bPremiereRessource) - this.ms_nPaddingLateralDebut - this.ms_nPaddingLateralFin;
	// La colonne ne gere pas l'espace a gauche/haut et a droite/bas
	var nDimensionLaterale = nDimensionRessources / nNbSuperpositions;

	// Position en colonne
	if (bIEQuirks)
	{
		// La colonne gere deja l'espace a gauche/haut et a droite/bas via un padding
		var nDimensionLateralePourcentage = 100 / nNbSuperpositions;
		this.vSetDebutLateral(oDiv, (nSuperposition * nDimensionLateralePourcentage) + "%");
		this.vSetLongueurLateral(oDiv, nDimensionLateralePourcentage + "%");
	}
	else
	{
		// + this.ms_nPaddingLateralDebut : Padding haut/gauche
		this.vSetDebutLateral(oDiv, (this.ms_nPaddingLateralDebut + nSuperposition * nDimensionLaterale) + "px");
		// + this.ms_nPaddingLateralFin : Padding bas/droit
		this.vSetFinLateral(oDiv, (this.ms_nPaddingLateralFin + (nNbSuperpositions - nSuperposition - 1) * nDimensionLaterale) + "px");
	}
	return nDimensionLaterale;
};

// Positionne un rendez-vous en largeur avec un affichage "decalage"
// Retourne la dimension laterale (= perpendiculaire ayu passage du temps) du rendez-vous
WDPlanning.prototype.__nHTMLAfficheUnRendezVousSuperpositionDecalage = function __nHTMLAfficheUnRendezVousSuperpositionDecalage(oDiv, nSuperposition, nNbSuperpositions, bPremiereRessource)
{
	// Si il n'y a qu'un rendez-vous (pas de superposition) : retrouve le calcul "cote a cote"
	if (1 == nNbSuperpositions)
	{
		return this.__nHTMLAfficheUnRendezVousSuperpositionCoteACote(oDiv, nSuperposition, nNbSuperpositions, bPremiereRessource);
	}

	var nDimensionRessources = this.__nGetDimensionPxSansBordureRessources(bPremiereRessource) - this.ms_nPaddingLateralDebut - this.ms_nPaddingLateralFin;
	// On reserve 30% pour les decalages
	var nPourcentageDecalage = 30;
	var nDimensionZoneVide = Math.floor(nDimensionRessources * nPourcentageDecalage / 100);
	var nDimensionZoneVideColonne = nDimensionZoneVide / (nNbSuperpositions - 1);

	// Position en colonne
	if (bIEQuirks)
	{
		this.vSetDebutLateral(oDiv, (nSuperposition * nDimensionZoneVideColonne) + "px");
		this.vSetLongueurLateral(oDiv, (nDimensionRessources - nDimensionZoneVide + this.ms_nPaddingLateralDebut + this.ms_nPaddingLateralFin) + "px");
	}
	else
	{
		// + this.ms_nPaddingLateralDebut : Padding haut/gauche
		this.vSetDebutLateral(oDiv, (this.ms_nPaddingLateralDebut + nSuperposition * nDimensionZoneVideColonne) + "px");
		// + this.ms_nPaddingLateralFin : Padding bas/droit
		this.vSetFinLateral(oDiv, (this.ms_nPaddingLateralFin + (nNbSuperpositions - nSuperposition - 1) * nDimensionZoneVideColonne) + "px");
	}
	return Math.floor(nDimensionRessources - nDimensionZoneVide);
};

// Recupere le contenu HTML d'un rendez-vous
// Cette fonction concerne le HTML interne du rendez-vous et est donc independant du sens d'affichage
WDPlanning.prototype._sGetHTMLRendezVous = function _sGetHTMLRendezVous(oRendezVous, nLargeur, nHauteur)
{
	var nEpaisseur = this.__nGetRendezVousEpaisseurBordure(this.m_oParametres.m_oStyleRendezVous);

	var tabHTML = [];
	// Creation de la table exterieure
	tabHTML.push("<table class=\"");
	tabHTML.push(this.ms_sNomRendezVous);
	tabHTML.push("\" style=\"width:");
	tabHTML.push(nLargeur);
	tabHTML.push("px;height:");
	tabHTML.push(nHauteur);
	tabHTML.push("px");
	if (oRendezVous.m_cBord)
	{
		tabHTML.push(";border-color:");
		tabHTML.push(oRendezVous.m_cBord);
	}
	if (oRendezVous.m_sBulle)
	{
		tabHTML.push("\" title=\"");
		tabHTML.push(clWDEncode.sEncodeCharset(oRendezVous.m_sBulle));
	}
	tabHTML.push("\"><tr><td");
	if (oRendezVous.m_cFondTitre || nEpaisseur)
	{
		tabHTML.push(" style=\"");
		if (nEpaisseur)
		{
			tabHTML.push("padding-top:");
			tabHTML.push(nEpaisseur);
		}
		if (oRendezVous.m_cFondTitre)
		{
			var bDegrade = false;
			if (oRendezVous.m_cBord || (0 < this.m_oParametres.m_oStyleRendezVous.m_nBordureV))
			{
				// Fond degrade dans tous les navigateurs autres que IE8- et chrome (qui dessine mal le degrade (pas de clipping sur le bord arrondi)
				if ((!bIE || (8 > nIE)) && !bCrm)
				{
					tabHTML.push(";");
					if (bFF)
					{
						tabHTML.push("-moz-box-shadow");
					}
					else if (bWK)
					{
						tabHTML.push("-webkit-box-shadow");
					}
					else
					{
						tabHTML.push("box-shadow");
					}
					tabHTML.push(": 0px 20px 10px -10px ");
					tabHTML.push(oRendezVous.m_cFondTitre);
					tabHTML.push(" inset");
					bDegrade = true;
				}
			}
			tabHTML.push(";background-color:");
			// Avec le degrade on inverse les couleurs (pour avoir un degrade dans le bon sens
			tabHTML.push(bDegrade ? oRendezVous.m_cBord : oRendezVous.m_cFondTitre);
			tabHTML.push(";");
		}

		tabHTML.push("\"");
	}
	tabHTML.push(" class=\"");
	tabHTML.push(this.ms_sNomRendezVousTitre);
	tabHTML.push(" ");
	tabHTML.push(this.m_oParametres.m_oStyleRendezVous.m_sClasses);
	tabHTML.push("\"><div style=\"width:");
	tabHTML.push(nLargeur - this.ms_nPaddingRendezVous * 2);
	tabHTML.push("px\">");
	if (oRendezVous.m_sTitre)
	{
		tabHTML.push(clWDEncode.sEncodeInnerHTML(oRendezVous.m_sTitre, true, false));
	}
	else
	{
		tabHTML.push("&nbsp;");
	}
	tabHTML.push("</div>");
	this._vHTMLRendezVousRedimGauche(tabHTML, nHauteur, nEpaisseur, this.ms_sNomRendezVousRedimDebut);
	this._vHTMLRendezVousRedimDroite(tabHTML, nHauteur, nEpaisseur, this.ms_sNomRendezVousRedimFin);
	tabHTML.push("</td></tr><tr");
	if (oRendezVous.m_cFondContenu)
	{
		tabHTML.push(" style=\"background-color:");
		tabHTML.push(oRendezVous.m_cFondContenu);
		tabHTML.push(";\"");
	}
	tabHTML.push(" height=\"100%\"><td");
	var tabClasses = [];
	if (oRendezVous.m_sImage)
	{
		tabHTML.push(" style=\"background-image:url('");
		tabHTML.push(_WD_);
		tabHTML.push(oRendezVous.m_sImage);
		tabHTML.push("')\"");
		tabClasses.push(this.ms_sNomRendezVousImage);
	}
	if (oRendezVous.m_sContenu && this.m_oParametres.m_oStyleLibContenu.m_sClasses && this.m_oParametres.m_oStyleLibContenu.m_sClasses.length)
	{
		tabClasses.push(this.m_oParametres.m_oStyleLibContenu.m_sClasses);
	}
	if (0 < tabClasses.length)
	{
		tabHTML.push(" class=\"");
		tabHTML.push(tabClasses.join(" "));
		tabHTML.push("\"");
	}
	tabHTML.push(">");
	if (oRendezVous.m_sContenu)
	{
		tabHTML.push("<div style=\"width:");
		tabHTML.push(nLargeur - this.ms_nPaddingRendezVous * 2);
		tabHTML.push("px\">");
		tabHTML.push(clWDEncode.sEncodeInnerHTML(oRendezVous.m_sContenu, true, false));
		tabHTML.push("</div>");
	}
	tabHTML.push("</td></tr><tr");
	if (oRendezVous.m_cFondContenu)
	{
		tabHTML.push(" style=\"background-color:");
		tabHTML.push(oRendezVous.m_cFondContenu);
		tabHTML.push(";\"");
	}
	tabHTML.push("><td height=\"");
	tabHTML.push(nEpaisseur + 2);
	tabHTML.push("\" class=\"");
	tabHTML.push(this.ms_sNomRendezVousBas);
	tabHTML.push("\"/>");
	this._vHTMLRendezVousRedimBas(tabHTML, nLargeur, nEpaisseur, this.ms_sNomRendezVousRedimFin);
	if (oRendezVous.m_bRepetee)
	{
		tabHTML.push("<img class=\"");
		tabHTML.push(this.ms_sNomRendezVousRepetition);
		tabHTML.push("\" src=\"");
		tabHTML.push(this.ms_sImageRepetition);
		tabHTML.push("\" />");
	}

	if (0 < oRendezVous.m_nImportance)
	{
		tabHTML.push("<img class=\"");
		tabHTML.push(this.ms_sNomRendezVousImportance);
		tabHTML.push("\" src=\"");
		tabHTML.push(this.ms_sImageImportance);
		tabHTML.push("\" />");
	}
	tabHTML.push("</tr></table>");
	return tabHTML.join("");
};

// Genere le div de redimensionnement
WDPlanning.prototype.__HTMLRendezVousRedim = function __HTMLRendezVousRedim(tabHTML, nDimensionPx, nEpaisseur, sClasse)
{
	tabHTML.push("<div style=\"");
	tabHTML.push(this.ms_sStyleDimensionLaterale);
	tabHTML.push(":");
	// On n'est pas exactement precis car il faudrait tenir compte de nEpaisseur mais celui-ci change avec la selection
	tabHTML.push(nDimensionPx - this.ms_nPaddingRendezVous * 2);
	tabHTML.push(";");
	tabHTML.push(this.ms_sStyleDimension);
	tabHTML.push(":");
	tabHTML.push(nEpaisseur + 2);
	tabHTML.push("px\" class=\"");
	tabHTML.push(sClasse);
	tabHTML.push("\"/></div>");
};

// Trouve l'epaisseur des cellules bordures d'un rendez-vous en fonction de l'epaisseur des bordures du style
WDPlanning.prototype.__nGetRendezVousEpaisseurBordure = function __nGetRendezVousEpaisseurBordure(oStyle)
{
	// Epaisseur des elements sur le bord de la table
	var nEpaisseur = this.ms_nPaddingRendezVous;
	if (0 < oStyle.m_nBordureV)
	{
		return Math.max(0, nEpaisseur - oStyle.m_nBordureV);
	}
	else
	{
		return nEpaisseur;
	}

};

// Fixe les evenements sur un rendez-vous
WDPlanning.prototype.__SetRendezVousEvenements = function __SetRendezVousEvenements(oRendezVous, oDiv)
{
	// Intercepte le :
	//						Rendez-vous		Page
	// Debut du drag-drop	mousedown
	// En drag-drop							mousemove
	// Fin du drag-drop						mouseup
	// Selection/Autres		onclick
	// Entree en saisie		ondblclick
	this.m_oDragRendezVous.InitElement(oRendezVous, oDiv);

	var oThis = this;
	var oThisRendezVous = oRendezVous;
	oRendezVous.m_fOnClick = function(oEvent) { oEvent = oEvent ? oEvent : event; return oThis.__OnRendezVousClic(oEvent, oThisRendezVous); };
	oRendezVous.m_fOnDblClick = function(oEvent) { oEvent = oEvent ? oEvent : event; return oThis.__OnRendezVousDoubleClic(oEvent, oThisRendezVous); };
	HookOnXXX(oDiv, 'onclick', 'click', oRendezVous.m_fOnClick);
	HookOnXXX(oDiv, 'ondblclick', 'dblclick', oRendezVous.m_fOnDblClick);
};

// Supprime le HTML des rendez-vous
WDPlanning.prototype.__HTMLVideRendezVous = function __HTMLVideRendezVous()
{
	// Utilise le tableau des rendez-vous precedents
	var tabRendezVous = this.m_oOldDonnees.m_tabRendezVous;
	var i;
	var nLimiteI = tabRendezVous.length;
	for (i = 0; i < nLimiteI; i++)
	{
		// Supprime le rendez-vous
		this.__HTMLVideUnRendezVous(tabRendezVous[i]);
	}
};

// Supprime le HTML d'un rendez-vous
WDPlanning.prototype.__HTMLVideUnRendezVous = function __HTMLVideUnRendezVous(oRendezVous)
{
	// Supprime les evenements
	var oDiv = oRendezVous.m_oDiv;
	if (oDiv)
	{
		// Supprime les evenements
		UnhookOnXXX(oDiv, 'ondblclick', 'dblclick', oRendezVous.m_fOnDblClick);
		oRendezVous.m_fOnDblClick = null;
		delete oRendezVous.m_fOnDblClick;
		UnhookOnXXX(oDiv, 'onclick', 'click', oRendezVous.m_fOnClick);
		oRendezVous.m_fOnClick = null;
		delete oRendezVous.m_fOnClick;
		this.m_oDragRendezVous.LibereElement(oRendezVous, oDiv);

		// Puis supprime le div du HTML
		oDiv.parentNode.removeChild(oDiv);
		// Puis supprime la reference
		oDiv = null;
		oRendezVous.m_oDiv = null;
		delete oRendezVous.m_oDiv;
	}
};

// Modifie l'epaisseur des cellules bordures d'un rendez-vous
WDPlanning.prototype.__HTMLAfficheRendezVousCellulesBordures = function __HTMLAfficheRendezVousCellulesBordures(oRendezVous, oTableRendezVous, oStyle, oStyleContenu)
{
	var tabCellules = oTableRendezVous.getElementsByTagName("td");
	// Epaisseur des bordures : elle change avec le style : il faut changer les tailles des cellules
	if (this.m_oParametres.m_oStyleRendezVous.m_nBordureV != this.m_oParametres.m_oStyleRendezVousSelect.m_nBordureV)
	{
		// Epaisseur des elements sur le bord de la table
		var nEpaisseur = this.__nGetRendezVousEpaisseurBordure(oStyle);

		tabCellules[0].style.paddingTop = nEpaisseur + "px";
		tabCellules[2].height = nEpaisseur + 2;
	}

	// Change la classe du texte
	tabCellules[0].className = this.ms_sNomRendezVousTitre + " " + oStyle.m_sClasses;
	// Si on a un contenu
	var tabClasses = [];
	if (oRendezVous.m_sImage)
	{
		tabClasses.push(this.ms_sNomRendezVousImage);
	}
	if (oRendezVous.m_sContenu && oStyleContenu.m_sClasses)
	{
		tabClasses.push(oStyleContenu.m_sClasses);
	}
	tabCellules[1].className = tabClasses.join(" ");
};

// Affiche les elements specifiques au rendez-vous selectionne
WDPlanning.prototype.__HTMLAfficheRendezVousSelection = function __HTMLAfficheRendezVousSelection()
{
	// Si un element est selectionne
	if (this.m_oRendezVousSelection)
	{
		// Affiche le bouton de suppression
		this.__HTMLAfficheRendezVousSuppression(this.m_oRendezVousSelection);

		var oDiv = this.m_oRendezVousSelection.m_oDiv;
		var oTable = oDiv.firstChild;
		// Style du rendez-vous
		oTable.className = this.ms_sNomRendezVousSelect;
		oDiv.style.zIndex = this.ms_nZIndexRendezVousSelection;
		// Epaisseur des bordures : elle change avec le style : il faut changer les tailles des cellules
		this.__HTMLAfficheRendezVousCellulesBordures(this.m_oRendezVousSelection, oTable, this.m_oParametres.m_oStyleRendezVousSelect, this.m_oParametres.m_oStyleLibContenuSelect);

		// Entre en saisie
		if (this.m_oParametres.m_bEditTitreRDVSelection)
		{
			this.m_oParametres.m_bEditTitreRDVSelection = false;
			this.__OnRendezVousDoubleClic(null, this.m_oRendezVousSelection);
		}
	}
};

// Supprime les elements specifiques au rendez-vous selectionne
WDPlanning.prototype.__HTMLVideRendezVousSelection = function __HTMLVideRendezVousSelection(bRAZ)
{
	// Il faut valider le div aussi car si on est en reception traitement AJAX, m_oRendezVousSelection
	// contient deja le nouveau rendez-vous qui n'est pas encore liee a son DIV
	if (this.m_oRendezVousSelection && this.m_oRendezVousSelection.m_oDiv)
	{
		var oDiv = this.m_oRendezVousSelection.m_oDiv;
		var oTable = oDiv.firstChild;
		// Epaisseur des bordures : elle change avec le style : il faut changer les tailles des cellules
		this.__HTMLAfficheRendezVousCellulesBordures(this.m_oRendezVousSelection, oTable, this.m_oParametres.m_oStyleRendezVous, this.m_oParametres.m_oStyleLibContenu);
		// Style du rendez-vous
		oDiv.style.zIndex = this.ms_nZIndexRendezVous;
		oTable.className = this.ms_sNomRendezVous;
	}

	// Masque le bouton de suppression
	this.__HTMLVideRendezVousSuppression();
};

// Affiche le bouton de suppression
WDPlanning.prototype.__HTMLAfficheRendezVousSuppression = function __HTMLAfficheRendezVousSuppression(oRendezVous)
{
	// Si le bouton existe : le supprime
	this.__HTMLVideRendezVousSuppression();

	// On n'affiche pas le bouton si l'utilisateur n'a pas le droit de supprimer
	if (this.m_oParametres.m_bSupprimeParUtilisateur)
	{
		// Trouve le parent d'ajout : parent du corps pour ne pas etre coupe par l'overflow
		var oDiv = oRendezVous.m_oDiv;
		var oParent = this.m_oHote;

		// Et le (re)cree
		var oRendezVousSuppression = document.createElement("img");
		oRendezVousSuppression.src = this.ms_sImageSupprime;
		oRendezVousSuppression.className = this.ms_sNomRendezVousSupprime;

		this.__HTMLPlaceRendezVousSuppression(oRendezVousSuppression, oParent, oDiv);
		this.m_oRendezVousSuppression = oParent.appendChild(oRendezVousSuppression);

		// Ajoute l'evenement
		HookOnXXX(this.m_oRendezVousSuppression, 'onclick', 'click', this.m_fOnRendezVousSupprime);
	}
};

// Place le bouton de suppression
WDPlanning.prototype.__HTMLPlaceRendezVousSuppressionAutonome = function __HTMLPlaceRendezVousSuppressionAutonome()
{
	var oRendezVousSelection = this.oGetRendezVousSelection();
	if (this.m_oRendezVousSuppression && oRendezVousSelection && oRendezVousSelection.m_oDiv)
	{
		this.__HTMLPlaceRendezVousSuppression(this.m_oRendezVousSuppression, this.m_oHote, oRendezVousSelection.m_oDiv);
	}
};
WDPlanning.prototype.__HTMLPlaceRendezVousSuppression = function __HTMLPlaceRendezVousSuppression(oRendezVousSuppression, oParent, oDiv)
{
	// En mode quirks, il y a le padding en plus
	// - En mode ressources en ligne, c'est le padding "avant" => this.ms_nPaddingLateralDebut
	// - En mode ressources en colonne, c'est le padding "apres" => this.ms_nPaddingLateralFin
	var nPaddingTop = this._vnGetPaddingTopPourRendezVous();
	var nPaddingRight = this._vnGetPaddingRightPourRendezVous();

	var nTop = 0;
	var nLeft = 0;
	var oElement = oDiv;
	var oParentOffsetParent = oParent.offsetParent;
	while ((oElement != oParent) && (oElement != oParentOffsetParent) && (oElement != document.body))
	{
		nTop += oElement.offsetTop - oElement.scrollTop;
		nLeft += oElement.offsetLeft - oElement.scrollLeft;
		oElement = oElement.offsetParent;
	}
	// 6 et 8 : positionnement "arbitraire" de l'image de suppression pour etre sur le coin mais rentrant de un pixel
	oRendezVousSuppression.style.top = (nTop - 6 + nPaddingTop) + "px";
	oRendezVousSuppression.style.left = (nLeft + oDiv.offsetWidth - 8 - nPaddingRight) + "px";

	// Si la croix n'est pas visible : ne l'affiche pas
	// Calcule la position dans les coordonnees du positionnement du rendez-vous
	var oParentDiv = oDiv.parentNode.parentNode;
	// On fait le calcul (x < scroll) || (x > scroll + client) : on eleve scrollXxx directement
	nTop = oDiv.offsetTop + oParentDiv.offsetTop + nPaddingTop - this.m_oHoteCorps.scrollTop;
	nLeft = oDiv.offsetLeft + oParentDiv.offsetLeft + oDiv.offsetWidth - nPaddingRight - this.m_oHoteCorps.scrollLeft;
	oRendezVousSuppression.style.visibility = ((0 > nTop) || (this.__nGetClientHeight(this.m_oHoteCorps) < nTop) || (0 > nLeft) || (this.__nGetClientWidth(this.m_oHoteCorps) < nLeft)) ? "hidden" : "visible";
};

// Masque le bouton de suppression
WDPlanning.prototype.__HTMLVideRendezVousSuppression = function __HTMLVideRendezVousSuppression()
{
	// Supprime l'evenement sur le bouton s'il existe
	if (this.m_oRendezVousSuppression)
	{
		UnhookOnXXX(this.m_oRendezVousSuppression, 'onclick', 'click', this.m_fOnRendezVousSupprime);
	}
	// Si le bouton existe : le supprime
	bHTMLVideDepuisVariable(this, "m_oRendezVousSuppression");
};

// - Position des rendez-vous

// Recupere la dimension laterale d'un element (hauteur de ligne dans le cas en ligne et largeur de colonne dans le cas en colonne)
WDPlanning.prototype.__nGetDimensionPxSansBordure = function __nGetDimensionPxSansBordure(nDimensionPx, oStyle)
{
	if (0 < oStyle.m_nBordureV)
	{
		// - * 1 et pas - * 2 pour firefox et ie
		return nDimensionPx - (bIEQuirks ? 0 : oStyle.m_nBordureV);
	}
	return nDimensionPx;
};

// Recupere la dimension laterale des ressources (hauteur de ligne dans le cas en ligne et largeur de colonne dans le cas en colonne)
WDPlanning.prototype.__nGetDimensionPxSansBordureRessources = function __nGetDimensionPxSansBordureRessources(bPremiereRessource)
{
	var nDimensionPx = this.__nGetDimensionPxSansBordure(this.m_oParametres.m_nDimensionLateralePxRessource, this.m_oParametres.m_oStyleNormal);
	if (bPremiereRessource)
	{
		return this.__nGetDimensionPxSansBordure(nDimensionPx, this.m_oParametres.m_oStyleLibHeure);
	}
	else
	{
		return nDimensionPx;
	}
};


// Recupere la partie heure dans une journee une heure arrondie par defaut
// DD/MM/AAAA HH:MM:SS:MMM => HH:00:00:000
WDPlanning.prototype.__nGetHeureArrondiDefaut = function __nGetHeureArrondiDefaut(nHeure)
{
	// 3600000 = 3600 * 1000 = 1 heure en ms
	return Math.floor(nHeure / 3600000);
};

// Recupere la partie heure dans une journee une heure arrondie par defaut
// DD/MM/AAAA HH:MM:SS:MMM => HH:00:00:000 (si MM = SS = MMM = 0) ou HH+1:00:00:000
WDPlanning.prototype.__nGetHeureArrondiExces = function __nGetHeureArrondiExces(nHeure)
{
	// 3600000 = 3600 * 1000 = 1 heure en ms
	return Math.ceil(nHeure / 3600000);
};

// Recupere la partie heure (dans la journee) dans une date
// DD/MM/AAAA HH:MM:SS:MMM => HH:MM:SS:MMM (en ms depuis 00:00)
WDPlanning.prototype.__nGetHeureJour = function __nGetHeureJour(nDate)
{
	var oTemp = new Date(nDate);
	oTemp.setUTCHours(0, 0, 0, 0);
	return nDate - oTemp.getTime();
};

// Corrige une heure pour etre dans la plage des heures affichables
// bSensFuture : Si vrai on arrondi en priorite la date vers le futur
WDPlanning.prototype.__nCorrigeDateHeure = function __nCorrigeDateHeure(nDate, bSensFutur)
{
	// Si on est en affichage par journee ou demi-journee :
	// this.m_oParametres.m_nHeureAfficheMin contient deja 0
	// this.m_oParametres.m_nHeureAfficheMax contient deja 86400000
	// => ce qui revient a ne rien faire
	var nHeureJour = this.__nGetHeureJour(nDate);
	if (nHeureJour < this.m_oParametres.m_nHeureAfficheMin)
	{
		// Si on est le matin : avant l'heure min
		if (bSensFutur)
		{
			// Avance la date
			return nDate - nHeureJour + this.m_oParametres.m_nHeureAfficheMin;
		}
		else
		{
			// Recule la date au jour precedent
			// 86400000 = 24 * 3600 * 1000 = 1 jour en ms
			return nDate - nHeureJour - 86400000 + this.m_oParametres.m_nHeureAfficheMax;
		}
	}
	else if (nHeureJour >= this.m_oParametres.m_nHeureAfficheMax)
	{
		// Si on est le soir : apres l'heure max
		if (bSensFutur)
		{
			// Avance la date au jour suivant
			// 86400000 = 24 * 3600 * 1000 = 1 jour en ms
			return nDate - nHeureJour + 86400000 + this.m_oParametres.m_nHeureAfficheMin;
		}
		else
		{
			// Recule la date
			return nDate - nHeureJour + this.m_oParametres.m_nHeureAfficheMax;
		}
	}
	return nDate;
};

// Calcule la position en pixel du debut d'un rendez-vous
WDPlanning.prototype.__nGetDebutRendezVous = function __nGetDebutRendezVous(nDate, nDateReference)
{
	return this.__nGetDimensionPxDepuisDifferenceDate(nDate, nDateReference, true);
};

// Calcule la longueur en pixel d'un rendez-vous
WDPlanning.prototype.__nGetLongueurRendezVous = function __nGetLongueurRendezVous(nDate, nDateReference)
{
	return this.__nGetDimensionPxDepuisDifferenceDate(nDate, nDateReference, false);
};

// Calcule la position en pixel d'une date donnee par rapport a une autre
// nDate doit etre une date dans la plage valide
// bDepuisDebut : indique que l'on compare a la date de debut. il faut le savoir car on a alors une rupture de plus (la premiere)
// mais elle n'apparait pas dans le calcul de nOffsetJour
WDPlanning.prototype.__nGetDimensionPxDepuisDifferenceDate = function __nGetDimensionPxDepuisDifferenceDate(nDate, nDateReference, bDepuisDebut)
{
	// Calcule la duree depuis le debut de l'affichage
	var nOffsetMs = nDate - nDateReference;

	// Corrige pour les zones non affichees
	// => Commence par corriger en nombres de jours
	var nOffsetJour = Math.floor((nDate - nDateReference) / 86400000);
	// Si est sur deux jour
	var nHeureJourReference = this.__nGetHeureJour(nDateReference);
	var nHeureJour = this.__nGetHeureJour(nDate);
	if (nHeureJour < nHeureJourReference)
	{
		nOffsetJour++;
	}
	// Si on est en affichage par journee ou demi-journee :
	// this.m_oParametres.m_nHeureAfficheMin contient deja 0
	// this.m_oParametres.m_nHeureAfficheMax contient deja 86400000
	// => ce qui revient a ne rien faire
	nOffsetMs -= nOffsetJour * (this.m_oParametres.m_nHeureAfficheMin + 86400000 - this.m_oParametres.m_nHeureAfficheMax);
	nDateReference += nOffsetJour * 86400000;
	// => Puis corrige pour le dernier jour
	if (nHeureJourReference < this.m_oParametres.m_nHeureAfficheMin)
	{
		nOffsetMs -= this.m_oParametres.m_nHeureAfficheMin - nHeureJourReference;
		nOffsetJour--;
	}
	else if (nHeureJourReference >= this.m_oParametres.m_nHeureAfficheMax)
	{
		nOffsetMs -= this.m_oParametres.m_nHeureAfficheMin + nHeureJourReference - this.m_oParametres.m_nHeureAfficheMax;
		nOffsetJour--;
	}

	// Et retourne la valeur selon la dimension d'une heure
	var nDimensionPx = this.__nGetDimensionPxDepuisDureeMs(nOffsetMs);
	// Compense pour les ruptures
	// Les ruptures n'existent que pour le mode avec les ressources en colonne. Donc dans le cas avec les ressources en ligne
	// this.m_oParametres.m_nHauteurLibJour n'existe pas et on n'entre pas dans le test : ce qui est correct
	if (this.m_oParametres.m_nHauteurLibJour)
	{
		nDimensionPx += (nOffsetJour + (bDepuisDebut ? 1 : 0)) * this.m_oParametres.m_nHauteurLibJour;
	}
	return nDimensionPx;
};

// Trouve la position en point par rapport au debut de l'heure
WDPlanning.prototype.__nGetPositionDansGraduation = function __nGetPositionDansGraduation(nPosition, oGraduation)
{
	// Calcule la difference de position
	var nPositionDansGraduation = nPosition - oGraduation.m_nPosition;
	// Si on est sur la premiere rupture : nPositionDansGraduation < 0
	nPositionDansGraduation = Math.max(nPositionDansGraduation, 0);
	// Si on est sur une autre rupture : nPositionDansGraduation > this.m_oParametres.m_nDimensionPxGraduation
	nPositionDansGraduation = Math.min(nPositionDansGraduation, this.m_oParametres.m_nDimensionPxGraduation);

	return nPositionDansGraduation;
};

// Recupere la description de l'heure dans lequel le point se trouve
// bFavoriseJourSuivant : si on est a une limite de jour : favorise le debut du jour suivant
WDPlanning.prototype.__oGetGraduation = function __oGetGraduation(nPosition, bFavoriseJourSuivant)
{
	// Calcule la position en nombre d'heures depuis le debut de l'affichage => on obtient donc l'heure de debut de la zone
	// Normalement cette heure est aligne sur la resolution
	var nGraduationNumero = Math.floor(nPosition / this.m_oParametres.m_nDimensionPxGraduation);
	nGraduationNumero = Math.min(nGraduationNumero, this.m_tabGraduations.length - 1);
	// A cause des ruptures de jours, trouve l'heure exacte qui est forcement apres car les ruptures decalent vers le bas
	// Le calcul est fait pour avoir une valeur valide en cas de clic sur une rupture
	var oGraduation;
	do
	{
		oGraduation = this.m_tabGraduations[nGraduationNumero];
		nGraduationNumero--;

	} while ((nGraduationNumero >= 0) && (oGraduation.m_nPosition > nPosition));

	// Donc si on est sur une rupture on en tient compte
	if (bFavoriseJourSuivant)
	{
		var bGraduationSuivante = false;
		// Si on est en fait sur la rupture du jour suivant
		// Les ruptures n'existent que pour le mode avec les ressources en colonne. Donc dans le cas avec les ressources en ligne
		// this.m_oParametres.m_nHauteurLibJour n'existe pas et on n'entre pas dans le test : ce qui est correct
		if (this.m_oParametres.m_nHauteurLibJour)
		{
			// Ici this.m_oParametres.m_nDimensionPxGraduation fonctionne que l'on soit en affichage par heure ou en affichage par jour (le calcul est dans __oGetGraduation)
			var nFinGraduation = oGraduation.m_nPosition + this.m_oParametres.m_nDimensionPxGraduation;
			var nDebutJourSuivant = nFinGraduation + this.m_oParametres.m_nHauteurLibJour;
			if ((nPosition >= nFinGraduation) && (nPosition < nDebutJourSuivant))
			{
				bGraduationSuivante = true;
			}
		}
//		else
//		{
//			// Uniquement si on n'est pas en mode a la journee
//			bGraduationSuivante = true;
//		}
		// +/-2 car nGraduationNumero a ete decremente dans la boucle
		if (bGraduationSuivante && (nGraduationNumero < (this.m_tabGraduations.length - 2)) && this.m_tabGraduations[nGraduationNumero + 2].m_bRupture)
		{
			oGraduation = this.m_tabGraduations[nGraduationNumero + 2];
		}
	}
	else if (oGraduation.m_bRupture && (oGraduation.m_nPosition == nPosition) && (0 <= nGraduationNumero))
	{
		// il y deja eu un -- sur la graduation
		oGraduation = this.m_tabGraduations[nGraduationNumero];
	}

	return oGraduation;
};

// Conversion d'une dimension (px) en duree (ms)
WDPlanning.prototype.__nGetDureeMsDepuisDimensionPx = function __nGetDureeMsDepuisDimensionPx(nDureeMs)
{
	return nDureeMs * this.m_oParametres.m_nGraduationDureeMs / this.m_oParametres.m_nDimensionPxGraduation;
};

// Conversion d'une duree (ms) en dimension (px)
WDPlanning.prototype.__nGetDimensionPxDepuisDureeMs = function __nGetDimensionPxDepuisDureeMs(nDureeMs)
{
	return nDureeMs * this.m_oParametres.m_nDimensionPxGraduation / this.m_oParametres.m_nGraduationDureeMs;
};

// Convertie une nouvelle position (deja aligne sur la resolution) en date
WDPlanning.prototype.__oGetDateFromPosAlignResolution = function __oGetDateFromPosAlignResolution(nPosition, bFavoriseJourSuivant)
{
	// Trouve la date (verifiant la resolution) la plus proche de la position donnee

	// A cause des ruptures de jours, trouve l'heure exacte qui est forcement apres car les ruptures decalent vers le bas
	var oGraduation = this.__oGetGraduation(nPosition, bFavoriseJourSuivant);

	// Trouve la position en point par rapport au debut de l'heure
	var nPositionDansGraduation = this.__nGetPositionDansGraduation(nPosition, oGraduation);
	// En deduit la date
	var nDatePosition = oGraduation.m_nDateDebut + this.__nGetDureeMsDepuisDimensionPx(nPositionDansGraduation);
	// Et construit l'objet date
	return new Date(parseInt(nDatePosition, 10));
};

// - Methodes publiques (utilisees par le Drag-Drop)

// Arrondi la variation en fonction de la granularite autorisee
WDPlanning.prototype.__nAppliqueResolution = function __nAppliqueResolution(nPosition, dResolutionPx)
{
	// A cause des ruptures de jours, trouve l'heure exacte qui est forcement apres car les ruptures decalent vers le bas
	var oGraduation = this.__oGetGraduation(nPosition, false);

	// Trouve la position (corrigee) en point par rapport au debut de l'heure
	var nPositionDansGraduation = this.__nGetPositionDansGraduation(nPosition, oGraduation);

	// Arrondi la position en fonction de la granularite autorisee
	var nOffetNbResolution = Math.round(nPositionDansGraduation / dResolutionPx);
	return oGraduation.m_nPosition + Math.round(nOffetNbResolution * dResolutionPx);
};

// Applique la resolution du debut (resolution de la precision de placement
WDPlanning.prototype.nAppliqueResolutionDeplacement = function nAppliqueResolutionDeplacement(nPosition)
{
	var dResolutionDeplacementPx = this.__nGetDimensionPxDepuisDureeMs(this.m_oParametres.m_nResolutionDeplacement);
	var nDebut = this.__nAppliqueResolution(nPosition, dResolutionDeplacementPx);
	if (nDebut > nPosition)
	{
		nDebut -= Math.round(dResolutionDeplacementPx);
	}
	return nDebut;
};


// Applique la resolution de taille
// nDebutPositionCorrection : Debut - debut corrige
WDPlanning.prototype.nAppliqueResolutionTaille = function nAppliqueResolutionTaille(nOffsetPosition, nDebutPositionCorrection)
{
	// Et la longeur : arrondi la position en fonction de la granularite autorisee
	var dResolutionLongeurPx = this.__nGetDimensionPxDepuisDureeMs(this.m_oParametres.m_nResolutionTaille);
	var nLongueur = Math.round(Math.round(nOffsetPosition / dResolutionLongeurPx) * dResolutionLongeurPx);
	// On applique quand meme une resolution de 1 pour avoir les calculs pour la position des ruptures
	nLongueur = this.__nAppliqueResolution(nLongueur, 1.0);
	if ((nLongueur < nOffsetPosition + nDebutPositionCorrection) || (0 == nLongueur))
	{
		nLongueur += Math.round(dResolutionLongeurPx); ;
	}

	return nLongueur
};

// Recupere la ressource en fonction de la position
// nRessourcePrecedente : ressource "actuelle"/par defaut
// => valeur retournee si on n'est pas dans une ressource
// => valeur recherche en premier (valeur la plus probable : accelere le calcul
WDPlanning.prototype.nGetRessourceDepuisPosition = function nGetRessourceDepuisPosition(oEvent, nRessourcePrecedente)
{
	var oOriginalTarget = clWDUtil.oGetOriginalTarget(oEvent);

	// Si on n'a pas change de ressource
	if (bEstFils(oOriginalTarget, this.oGetConteneurRessource(nRessourcePrecedente), document))
	{
		return nRessourcePrecedente;
	}

	// On n'est plus dans la meme ressource : trouve la nouvelle ressource
	var tabRessource = this.m_oDonnees.m_tabRessources;
	var i;
	var nLimiteI = tabRessource.length;
	for (i = 0; i < nLimiteI; i++)
	{
		if (bEstFils(oOriginalTarget, this.oGetConteneurRessource(i), document))
		{
			return i;
		}
	}

	// Non trouve (on est hors de la zone des ressource
	return nRessourcePrecedente;
};

// Touve le conteneur des rendez-vous d'une ressource
WDPlanning.prototype.oGetConteneurRessource = function oGetConteneurRessource(nRessource)
{
	return this.oGetIDElement(this.ms_sNomRessource, nRessource);
};

// Nom d'une ressource par index
WDPlanning.prototype.sGetNomRessource = function sGetNomRessource(nRessource)
{
	return this.m_oDonnees.m_tabRessources[nRessource].m_sNomAffiche;
};

// Lit le rendez-vous selectionne
WDPlanning.prototype.oGetRendezVousSelection = function oGetRendezVousSelection(oRendezVous)
{
	return this.m_oRendezVousSelection;
};

//////////////////////////////////////////////////////////////////////////
// Manipulation d'un champ planning avec les ressources en colonne

// Constructeur
function WDPlanningVertical(sAliasChamp, sAliasZR, sAliasAttribut)
{
	// Si on est pas dans l'init d'un protoype
	if (sAliasChamp)
	{
		// Appel le constructeur de la classe de base
		WDPlanning.prototype.constructor.apply(this, arguments);
	}
}

// Declare l'heritage
WDPlanningVertical.prototype = new WDPlanning();
// Surcharge le constructeur qui a ete efface
WDPlanningVertical.prototype.constructor = WDPlanningVertical;

// Constantes specifiques

// Classes
WDPlanningVertical.prototype.ms_sNomFondRupture = "WDPLN-FondRupture";
// Paddings
WDPlanningVertical.prototype.ms_nPaddingLibJour = 3;
// Indique la position des titres de ressources et d'heures
WDPlanningVertical.prototype.ms_sNomGeneralSpecifique = "WDPLN-ZoneGeneralVertical";
WDPlanningVertical.prototype.ms_sTitresRessourcesPosition = WDPlanning.prototype.ms_sNomTitresHorizontal;
WDPlanningVertical.prototype.ms_sTitresHeuresPosition = WDPlanning.prototype.ms_sNomTitresVertical;
// Indique le sens de la fusion des colonnes
WDPlanningVertical.prototype.ms_bTableTrParRessource = false;
// Et les dimension
WDPlanningVertical.prototype.ms_sStyleDebut = "top";
WDPlanningVertical.prototype.ms_sStyleDimension = "height";
WDPlanningVertical.prototype.ms_sStyleDebutLateral = "left";
WDPlanningVertical.prototype.ms_sStyleDimensionLaterale = "width";
WDPlanningVertical.prototype.ms_sCurseurRedim = "N-resize";

// Methode d'initialisation generale de la classe
// Filtre et ne s'execute que lors de l'init du PREMIER champ de ce type
WDPlanningVertical.prototype._vInitInitiale = function _vInitInitiale()
{
	// Appel de la methode de la classe de base
	WDPlanning.prototype._vInitInitiale.apply(this, arguments);

	var sPrefixeSpecifique = "." + this.ms_sNomGeneralSpecifique + " ";

	// Regles specifiques (la table des regles a ete cree par WDPlanning::_vInitInitiale)
	// - Corps
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomCorps, ["overflow-x:auto", "overflow-y:scroll", "position:relative"]);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "td." + this.ms_sNomCorpsQuadrillage, ["height:0px"]);
	// - Rendez-vous
	var nPaddingRight = this._vnGetPaddingRightPourRendezVous() + this.ms_nPaddingRendezVous;
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomRendezVousRepetition, ["position:absolute", "top:" + this.ms_nPaddingRendezVous + "px", "right:" + nPaddingRight + "px"]);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomRendezVousImportance, ["position:absolute", "bottom:" + this.ms_nPaddingRendezVous + "px", "right:" + nPaddingRight + "px"]);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "div." + this.ms_sNomRendezVousRedimFin, ["position:absolute", "bottom:" + this.ms_nPaddingRendezVous + "px"]);
	if (bIEQuirks)
	{
		this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomRendezVousExterne, ["padding-left:" + this.ms_nPaddingLateralDebut + "px", "padding-right:" + this.ms_nPaddingLateralFin + "px"]);
	}
	// - Rupture des jours
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomFondRupture, ["z-index:" + this.ms_nZIndexFondRupture, "position:relative"]);
	// - Libelle des heures : aligne a droite par defaut
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomTitresHeures, ["text-align:right"]);
	// Le dessin avec clipping ne marche pas dans IE en mode quirks, on fait l'ancien mode avec overflow-x/overflow-y
	var tabStyle = ["z-index:" + this.ms_nZIndexFondRupture, "overflow:hidden", "padding-left:" + this.ms_nPaddingLibJour + "px", "padding-right:" + this.ms_nPaddingLibJour + "px"]
	if (bIEQuirks)
	{
		tabStyle.push("position:absolute");
		tabStyle.push("left:0px");
		tabStyle.push("top:0px");
	}
	else
	{
		tabStyle.push("position:relative");
	}
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomFondRupture + " ." + this.ms_sNomJour, tabStyle);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomHeure, ["position:relative", "left:0px"]); //, "right:0px"]);

	// S'auto efface pour ne plus etre appele
	WDPlanningVertical.prototype._vInitInitiale = WDChamp.prototype.m_pfVide;
};

// Construit le stype pour une dimension sans le sens principale (largeur (ressources en lignes), hauteur (ressources en colonnes))
WDPlanningVertical.prototype._vtabInitCSS_DimensionPxPrincipale = WDPlanning.prototype._tabInitCSS_DimensionHauteur;
// Construit le stype pour une dimension laterale (hauteur (ressources en lignes), largeur (ressources en colonnes))
WDPlanningVertical.prototype._vtabInitCSS_DimensionPxLaterale = WDPlanning.prototype._tabInitCSS_DimensionLargeur;

// Construit le style pour les bordures dans le sens perpendiculaire au defilement principal (gauche/droite (ressources en lignes), haut/bas (ressources en colonnes))
WDPlanningVertical.prototype._vtabInitCSS_BorduresPerpendiculaires = WDPlanning.prototype._tabInitCSS_BorduresHautBas;
// Construit le style pour les bordures dans le sens du defilement principal (haut/bas (ressources en lignes), droite/gauche (ressources en colonnes))
WDPlanningVertical.prototype._vtabInitCSS_BorduresLaterales = WDPlanning.prototype._tabInitCSS_BorduresGaucheDroite;

// Indique la dimension principale des titres de ressources
WDPlanningVertical.prototype._vnDimensionPxPrincipaleTitresRessources = function _vnDimensionPxPrincipaleTitresRessources()
{
	return this.m_oParametres.m_nHauteurTitresHorizontal;
};
WDPlanningVertical.prototype._vnDimensionPxPrincipaleTitresLibelles = function _vnDimensionPxPrincipaleTitresLibelles()
{
	return this.m_oParametres.m_nLargeurTitresVertical;
};

// Initialisation du style des libelle des jours
WDPlanningVertical.prototype._vInitCSS_LibJour = function _vInitCSS_LibJour()
{
	// Style general : hauteur d'une rupture de jour
	if (this.m_oParametres.m_nHauteurLibJour)
	{
		var oStyle = this.m_oParametres.m_oStyleLibJourSemaine;

		// Le dessin avec clipping ne marche pas dans IE en mode quirks, on fait l'ancien mode avec overflow-x/overflow-y
		if (bIEQuirks)
		{
			this.__StyleCree(this.__sGetSelecteur(undefined, "", this.ms_sNomTitresVertical), ["overflow-x:visible"]);
		}
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomTitresVertical, "div", this.ms_sNomFondRupture), ["overflow:visible", "padding:0px"]);

		var tabStyle = [];
		// Si on a une couleur de fond : normalement oui
		if (oStyle.m_cFond)
		{
			tabStyle.push("background-color:" + oStyle.m_cFond);
		}
		// Il faudrait prendre la largeur effective (this.__nGetLargeur()) du champ et pas la largeur des ressource
		var nOffsetLibJour = this.__nGetOffsetLibJour();
		this.m_nLargeurLibJour = this.__nGetLargeurLibJour(this.__nGetClientWidth(this.m_oHoteCorps), nOffsetLibJour);
		var nHauteur = this.m_oParametres.m_nHauteurLibJour + nOffsetLibJour;
		if (0 < oStyle.m_nBordureV)
		{
			var nBordure = oStyle.m_nBordureV;
			var oBordureCouleur = oStyle.m_cBordureV;
			tabStyle.push("border:solid " + nBordure + "px " + oBordureCouleur);
		}
		tabStyle.push("height:" + nHauteur + "px");
		tabStyle.push("width:" + this.m_nLargeurLibJour + "px");
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomTitresVertical, "", this.ms_sNomJour), tabStyle);

		// - Espace pour la rupture des jours dans le corps (ils n'ont pas de bordures)
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomCorps, "", this.ms_sNomJour), ["height:" + this.m_oParametres.m_nHauteurLibJour + "px"]);
		this.__StyleCree(this.__sGetSelecteur(this.ms_sNomTitresVertical, "td", this.ms_sNomFondRupture), ["height:" + this.m_oParametres.m_nHauteurLibJour + "px"]);
	}
};

// Construit le HTML des titres horizontaux
// tabHTML inclus deja un <table> ouvrant => il faut commencer a tr
WDPlanningVertical.prototype._vHTMLAfficheTitresHorizontal = function _vHTMLAfficheTitresHorizontal(tabHTML)
{
	// Genere la table
	tabHTML.push("<tr class=\"");
	tabHTML.push(this.ms_sNomTitresRessources);
	tabHTML.push("\">");

	var tabRessources = this.m_oDonnees.m_tabRessources;
	var i;
	var nLimiteI = tabRessources.length;
	for (i = 0; i < nLimiteI; i++)
	{
		tabHTML.push("<td");
		if (i == 0)
		{
			tabHTML.push(" class=\"");
			tabHTML.push(this.ms_sNomPremier);
			tabHTML.push("\"");
		}
		tabHTML.push(">");
		this.__HTMLAfficheDiv(tabHTML, this.m_oParametres.m_oStyleLibRessource.m_sClasses, undefined, clWDEncode.sEncodeInnerHTML(tabRessources[i].m_sNomAffiche, true, false));
		tabHTML.push("</td>");
	}
	tabHTML.push("</tr>");
};

// Construit le HTML des titres verticaux
// tabHTML inclus deja un <table> ouvrant => il faut commencer a tr
WDPlanningVertical.prototype._vHTMLAfficheTitresVertical = function _vHTMLAfficheTitresVertical(tabHTML)
{
	// Le dessin avec clipping ne marche pas dans IE en mode quirks, on fait l'ancien mode avec overflow-x/overflow-y
	if (bIEQuirks)
	{
		// Pour avoir une debordement des ruptures (sans mettre une classe)
		this.m_oHoteTitresVertical.style.position = "relative";
		this.m_oHoteTitresVertical.style.zIndex = this.ms_nZIndexFondRupture;
		this.m_oHoteTitresVertical.parentNode.style.position = "relative";
		this.m_oHoteTitresVertical.parentNode.style.zIndex = this.ms_nZIndexFondRupture;
	}

	// Selon la position des heures initialise
	var tabGraduations = this.m_tabGraduations;
	var i;
	var nLimiteI = tabGraduations.length;
	for (i = 0; i < nLimiteI; i++)
	{
		var oGraduation = tabGraduations[i];

		// Si on a une rupture
		if (oGraduation.m_bRupture && this.m_oParametres.m_nHauteurLibJour)
		{
			// Genere la table
			tabHTML.push("<tr><td class=\"");
			tabHTML.push(this.ms_sNomFondRupture);
			tabHTML.push("\"><div class=\"");
			tabHTML.push(this.ms_sNomFondRupture);
			tabHTML.push("\">");
			// La partie avec les rupture : dessus
			tabHTML.push("<div class=\"");
			tabHTML.push(this.ms_sNomJour);
			tabHTML.push(" ");
			tabHTML.push(this.m_oParametres.m_oStyleLibJourSemaine.m_sClasses);
			tabHTML.push("\">");
			tabHTML.push(clWDEncode.sEncodeInnerHTML(oGraduation.m_sRuptureLibelle, true, false));
			tabHTML.push("</div></div></td></tr>");
		}


		// Genere la table
		tabHTML.push("<tr class=\"");
		tabHTML.push(this.ms_sNomTitresHeures);
		tabHTML.push("\"><td");
		// Si on est sur une graduation, affiche une graduation
		// On utilise le style premier sur le dernier
		if ((i + 1) >= nLimiteI)
		{
			tabHTML.push(" class=\"");
			tabHTML.push(this.ms_sNomPremier);
			tabHTML.push("\"");
		}
		tabHTML.push(">");
		tabHTML.push("<div class=\"");
		tabHTML.push(this.ms_sNomHeureLibelle);
		tabHTML.push(" ");
		tabHTML.push(oGraduation.m_sLibelleClasse);
		if (oGraduation.m_sLibelleCouleurFond)
		{
			tabHTML.push("\" style=\"background-color:");
			tabHTML.push(oGraduation.m_sLibelleCouleurFond);
		}
		tabHTML.push("\"><span class=\"");
		tabHTML.push(oGraduation.m_sLibelleClasse);
		tabHTML.push("\">");
		tabHTML.push(clWDEncode.sEncodeInnerHTML(oGraduation.m_sLibelle, true, false));
		tabHTML.push("</span></div></td></tr>");
	}
};

// Zone de redimensionnement
WDPlanningVertical.prototype._vHTMLRendezVousRedimGauche = WDChamp.prototype.m_pfVide;
WDPlanningVertical.prototype._vHTMLRendezVousRedimDroite = WDChamp.prototype.m_pfVide;
WDPlanningVertical.prototype._vHTMLRendezVousRedimBas = WDPlanning.prototype.__HTMLRendezVousRedim;

// Recupere le defilement du corps : scrollLeft (ressources en ligne) ou scrollTop (ressources en colonne)
WDPlanningVertical.prototype._vnGetDefilementPrincipal = WDPlanning.prototype._nGetDefilementVertical;
WDPlanningVertical.prototype._vnGetDefilementLateral = WDPlanning.prototype._nGetDefilementHorizontal;
// Fixe le defilement du corps : scrollLeft (ressources en ligne) ou scrollTop (ressources en colonne)
WDPlanningVertical.prototype._vSetDefilementPrincipal = WDPlanning.prototype._SetDefilementVertical;
WDPlanningVertical.prototype._vSetDefilementLateral = WDPlanning.prototype._SetDefilementHorizontal;

// Sur le defilement du corps
WDPlanningVertical.prototype._vOnDefilementCorps = function _vOnDefilementCorps(nLargeurCorps, nHauteurCorps, nDefilementHorizontal, nDefilementVertical)
{
	// Si on doit afficher les ruptures de jour
	if (this.m_oParametres.m_nHauteurLibJour)
	{
		// Change la largeur si besoin
		var nLargeurLibJour = this.__nGetLargeurLibJour(nLargeurCorps, this.__nGetOffsetLibJour());
		if (nLargeurLibJour != this.m_nLargeurLibJour)
		{
			this.m_nLargeurLibJour = nLargeurLibJour;
			this.__StyleComplete(this.__sGetSelecteur(this.ms_sNomTitresVertical, "", this.ms_sNomJour), ["width:" + nLargeurLibJour + "px"]);
		}
	}
};

// Calcule la largeur du libelle du jour
WDPlanningVertical.prototype.__nGetLargeurLibJour = function __nGetLargeurLibJour(nLargeurCorps, nOffsetLibJour)
{
	// Il faudrait prendre la largeur effective (this.__nGetLargeur()) du champ et pas la largeur des ressource
	// sauf que avec ce code on ne detecte pas bien le defilement puisque les ruptures sont dans la zone basse donc si la zone se reduit cela ne fonctionne pas
	// Il faut tenir compte du padding pour les navigateurs respectant la norme.
	return this.m_oParametres.m_nLargeurTitresVertical + nLargeurCorps + nOffsetLibJour - 2 * (bIEQuirks ? 0 : this.ms_nPaddingLibJour);
};

// Modification de la largeur/hauteur du libelle des jours de la semaine pour tenir compte de la bordure et du mode quirks
// Attention : on retourne la valeur en negatif, faire un +=
WDPlanningVertical.prototype.__nGetOffsetLibJour = function __nGetOffsetLibJour()
{
	var oStyle = this.m_oParametres.m_oStyleLibJourSemaine;
	if (0 < oStyle.m_nBordureV)
	{
		var nBordure = oStyle.m_nBordureV;
		if (!bIEQuirks)
		{
			return -2 * nBordure;
		}
	}
	return 0;
};

// En mode quirks, il y a le padding en plus
// - En mode ressources en ligne, c'est le padding "avant" => this.ms_nPaddingLateralDebut
// - En mode ressources en colonne, c'est le padding "apres" => this.ms_nPaddingLateralFin
WDPlanningVertical.prototype._vnGetPaddingTopPourRendezVous = function _vnGetPaddingTopPourRendezVous()
{
	return 0;
//	return bIEQuirks ? 0 : 0;
};
WDPlanningVertical.prototype._vnGetPaddingRightPourRendezVous = function _vnGetPaddingRightPourRendezVous()
{
	return bIEQuirks ? this.ms_nPaddingLateralFin : 0;
};

// Fixe le debut dans le sens principal : left (ressources en ligne) ou top (ressources en colonne)
WDPlanningVertical.prototype.vSetDebut = function vSetDebut(oElement, sDebut)
{
	oElement.style.top = sDebut;
};
// Fixe la longueur dans le sens principal : width (ressources en ligne) ou height (ressources en colonne)
WDPlanningVertical.prototype.vSetLongueur = function vSetLongueur(oElement, sLongueur)
{
	oElement.style.height = sLongueur;
};

// Fixe le debut lateral : top (ressources en ligne) ou left (ressources en colonne)
WDPlanningVertical.prototype.vSetDebutLateral = function vSetDebutLateral(oElement, sDebut)
{
	oElement.style.left = sDebut;
};
// Fixe la longueur laterale : height (ressources en ligne) ou width (ressources en colonne)
WDPlanningVertical.prototype.vSetLongueurLateral = function vSetLongueurLateral(oElement, sLongueur)
{
	oElement.style.width = sLongueur;
};
// Fixe le bord final lateral : bottom (ressources en ligne) ou right (ressources en colonne)
WDPlanningVertical.prototype.vSetFinLateral = function vSetFinLateral(oElement, sFin)
{
	oElement.style.right = sFin;
};

// Retourne offsetLeft (ressources en ligne) ou offsetTop (ressources en colonne)
WDPlanningVertical.prototype.voGetOffsetDebut = function voGetOffsetDebut(oElement)
{
	return oElement.offsetTop;
};
// Retourne offsetWidth (ressources en ligne) ou offsetHeight (ressources en colonne)
WDPlanningVertical.prototype.voGetOffsetLongueur = function voGetOffsetLongueur(oElement)
{
	return oElement.offsetHeight;
};

// Retourne le deplacement important pour la position : X (ressources en ligne) ou Y (ressources en colonne)
WDPlanningVertical.prototype.vnGetOffsetPosition = function vnGetOffsetPosition(nOffsetPositionX, nOffsetPositionY)
{
	return nOffsetPositionY;
};
// Retourne la coordonnee importante pour la position : X (ressources en ligne) ou Y (ressources en colonne) selon le conteneur hote
WDPlanningVertical.prototype.vnGetPositionHote = function vnGetPositionHote(oElement, nPositionX, nPositionY)
{
	return _JCCP(nPositionY, oElement, false, false) + this.m_oHoteCorps.scrollTop;
};

// Appel de _sGetHTMLRendezVous avec les bonnes dimensions
WDPlanningVertical.prototype._vsGetHTMLRendezVous = function _vsGetHTMLRendezVous(oElement, nLongueur, nDimensionLateralePx)
{
	return this._sGetHTMLRendezVous(oElement, nDimensionLateralePx, nLongueur);
};

//////////////////////////////////////////////////////////////////////////
// Manipulation d'un champ planning avec les ressources en ligne

// Constructeur
function WDPlanningHorizontal(sAliasChamp, sAliasZR, sAliasAttribut)
{
	// Si on est pas dans l'init d'un protoype
	if (sAliasChamp)
	{
		// Appel le constructeur de la classe de base
		WDPlanning.prototype.constructor.apply(this, arguments);
	}
}

// Declare l'heritage
WDPlanningHorizontal.prototype = new WDPlanning();
// Surcharge le constructeur qui a ete efface
WDPlanningHorizontal.prototype.constructor = WDPlanningHorizontal;

// Constantes specifiques

WDPlanningHorizontal.prototype.ms_sSeparateurFormatLigne = "|";
// Indique la position des titres de ressources et d'heures
WDPlanningHorizontal.prototype.ms_sNomGeneralSpecifique = "WDPLN-ZoneGeneralHorizontal";
WDPlanningHorizontal.prototype.ms_sTitresRessourcesPosition = WDPlanning.prototype.ms_sNomTitresVertical;
WDPlanningHorizontal.prototype.ms_sTitresHeuresPosition = WDPlanning.prototype.ms_sNomTitresHorizontal;
// Indique le sens de la fusion des colonnes
WDPlanningHorizontal.prototype.ms_bTableTrParRessource = true;
// Et les dimension
WDPlanningHorizontal.prototype.ms_sStyleDebut = "left";
WDPlanningHorizontal.prototype.ms_sStyleDimension = "width";
WDPlanningHorizontal.prototype.ms_sStyleDebutLateral = "top";
WDPlanningHorizontal.prototype.ms_sStyleDimensionLaterale = "height";
WDPlanningHorizontal.prototype.ms_sCurseurRedim = "E-resize";

// Methode d'initialisation generale de la classe
// Filtre et ne s'execute que lors de l'init du PREMIER champ de ce type
WDPlanningHorizontal.prototype._vInitInitiale = function _vInitInitiale()
{
	// Appel de la methode de la classe de base
	WDPlanning.prototype._vInitInitiale.apply(this, arguments);

	var sPrefixeSpecifique = "." + this.ms_sNomGeneralSpecifique + " ";

	// Regles specifiques (la table des regles a ete cree par WDPlanning::_vInitInitiale)
	// - Corps
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomCorps, ["overflow-x:scroll", "overflow-y:auto", "position:relative"]);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomTitresHorizontal + " td", ["overflow:hidden"]);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "td." + this.ms_sNomCorpsQuadrillage, ["width:0px"]);
	// - Rendez-vous
	var nPaddingTop = this._vnGetPaddingTopPourRendezVous() + this.ms_nPaddingRendezVous;
	var nPaddingBottom = (bIEQuirks ? this.ms_nPaddingLateralFin : 0) + this.ms_nPaddingRendezVous;
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomRendezVousRepetition, ["position:absolute", "top:" + nPaddingTop + "px", "right:" + this.ms_nPaddingRendezVous + "px"]);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomRendezVousImportance, ["position:absolute", "bottom:" + nPaddingBottom + "px", "right:" + this.ms_nPaddingRendezVous + "px"]);
	// Pas sur que le top ici soit le plus correct (a quoi fait-il referencereference ? mais cela fonctionne)
	this.__StyleCreeGlobal(sPrefixeSpecifique + "div." + this.ms_sNomRendezVousRedimDebut, ["position:absolute", "left:" + this.ms_nPaddingRendezVous + "px", "top:" + this.ms_nPaddingRendezVous + "px"]);
	this.__StyleCreeGlobal(sPrefixeSpecifique + "div." + this.ms_sNomRendezVousRedimFin, ["position:absolute", "right:" + this.ms_nPaddingRendezVous + "px", "top:" + this.ms_nPaddingRendezVous + "px"]);
	if (bIEQuirks)
	{
		this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomRendezVousExterne, ["padding-top:" + this.ms_nPaddingLateralDebut + "px", "padding-bottom:" + this.ms_nPaddingLateralFin + "px"]);
	}
	this.__StyleCreeGlobal(sPrefixeSpecifique + "." + this.ms_sNomHeure, ["position:relative", "top:0px", "float:left"]); //, "bottom:0px"]);

	// S'auto efface pour ne plus etre appele
	WDPlanningHorizontal.prototype._vInitInitiale = WDChamp.prototype.m_pfVide;
};

// Construit le stype pour une dimension sans le sens principale (largeur (ressources en lignes), hauteur (ressources en colonnes))
WDPlanningHorizontal.prototype._vtabInitCSS_DimensionPxPrincipale = WDPlanning.prototype._tabInitCSS_DimensionLargeur;
// Construit le stype pour une dimension laterale (hauteur (ressources en lignes), largeur (ressources en colonnes))
WDPlanningHorizontal.prototype._vtabInitCSS_DimensionPxLaterale = WDPlanning.prototype._tabInitCSS_DimensionHauteur;

// Construit le style pour les bordures dans le sens perpendiculaire au defilement principal (gauche/droite (ressources en lignes), haut/bas (ressources en colonnes))
WDPlanningHorizontal.prototype._vtabInitCSS_BorduresPerpendiculaires = WDPlanning.prototype._tabInitCSS_BorduresGaucheDroite;
// Construit le style pour les bordures dans le sens du defilement principal (haut/bas (ressources en lignes), droite/gauche (ressources en colonnes))
WDPlanningHorizontal.prototype._vtabInitCSS_BorduresLaterales = WDPlanning.prototype._tabInitCSS_BorduresHautBas;

// Indique la dimension principale des titres de ressources
WDPlanningHorizontal.prototype._vnDimensionPxPrincipaleTitresRessources = function _vnDimensionPxPrincipaleTitresRessources()
{
	return this.m_oParametres.m_nLargeurTitresVertical;
};
WDPlanningHorizontal.prototype._vnDimensionPxPrincipaleTitresLibelles = function _vnDimensionPxPrincipaleTitresLibelles()
{
	var nNbLignes = 1;

	if (this.m_oParametres.m_bLigneTitreHeure)
	{
		nNbLignes++;
	}
	if (this.m_oParametres.m_bLigneTitreMois)
	{
		nNbLignes++;
	}
	if (this.m_oParametres.m_bLigneTitreJourDouble)
	{
		nNbLignes++;
	}

	return parseInt(this.m_oParametres.m_nHauteurTitresHorizontal / nNbLignes, 10);
};

// Initialisation du style des libelle des jours : pas de rupture dans ce mode
WDPlanningHorizontal.prototype._vInitCSS_LibJour = function _vInitCSS_LibJour()
{
	var tabBordure = this._vtabInitCSS_BorduresPerpendiculaires([], this.m_oParametres.m_oStyleLibJourSemaine, null);
	// Note : pour les heures ont a un bordure sur le dernier (meme si on garde le meme style)
	var tabBordurePremier = this._vtabInitCSS_BorduresPerpendiculaires([], this.m_oParametres.m_oStyleLibJourSemaine, this.m_oParametres.m_oStyleLibJourSemaine);
	var tabBordureCote = this._vtabInitCSS_BorduresLaterales([], this.m_oParametres.m_oStyleLibJourSemaine, null);
	var nDimensionPxPrincipale = this.__nGetDimensionPxSansBordure(this.m_oParametres.m_nDimensionPxGraduation, this.m_oParametres.m_oStyleLibJourSemaine);
	this.__InitCSS_Titres(this.ms_sNomTitresHeures + "." + this.ms_sNomJour, this.ms_sTitresHeuresPosition, tabBordure, tabBordurePremier, tabBordureCote, this.m_oParametres.m_oStyleLibJourSemaine, this.m_oParametres.m_oStyleLibJourSemaine, nDimensionPxPrincipale, this._vnDimensionPxPrincipaleTitresLibelles());
};


// Construit le HTML des titres horizontaux
// tabHTML inclus deja un <table> ouvrant => il faut commencer a tr
WDPlanningHorizontal.prototype._vHTMLAfficheTitresHorizontal = function _vHTMLAfficheTitresHorizontal(tabHTML)
{
	// Genere la table

	// Si on dessine les heures, decide du nombre de colonnes par jour
	var nNbGraduationsParJour = 1;
	if (this.m_oParametres.m_bLigneTitreHeure)
	{
		// Normalement le calcul tomber juste
		nNbGraduationsParJour = (this.m_oParametres.m_nHeureAfficheMax - this.m_oParametres.m_nHeureAfficheMin) / 3600000;
	}

	// Premiere ligne : les titres des mois
	if (this.m_oParametres.m_bLigneTitreMois)
	{
		this.__HTMLAfficheTitresMois(tabHTML, nNbGraduationsParJour);
	}

	// Seconde ligne : les titres des jours (eventuellement double)
	this.__HTMLAfficheTitresJours(tabHTML, nNbGraduationsParJour);

	// Troisieme ligne : les titres des heures
	if (this.m_oParametres.m_bLigneTitreHeure)
	{
		this.__HTMLAfficheTitresHeures(tabHTML, nNbGraduationsParJour);
	}
};

// Premiere ligne : les titres des mois
WDPlanningHorizontal.prototype.__HTMLAfficheTitresMois = function __HTMLAfficheTitresMois(tabHTML, nNbGraduationsParJour)
{
	tabHTML.push("<tr class=\"");
	tabHTML.push(this.ms_sNomTitresHeures);
	tabHTML.push(" ");
	tabHTML.push(this.ms_sNomJour);
	tabHTML.push("\">");

	// Selon la position des heures initialise
	var tabGraduations = this.m_tabGraduations;
	var i;
	var nLimiteI = tabGraduations.length;
	// Pas de ++, l'avancement est en interne sur
	var nNbJoursAfficheMois = 0;
	this.m_tagLargeurMois = [];
	for (i = 0; i < nLimiteI; i += nNbJoursAfficheMois * nNbGraduationsParJour)
	{
		var oGraduation = tabGraduations[i];

		// Trouve le nombre de jours affiche dans le mois
		nNbJoursAfficheMois = this.__nGetNbJoursAfficheMois(nNbGraduationsParJour, i);
		var nNbGraduationsMois = nNbGraduationsParJour * nNbJoursAfficheMois;

		// Genere la table
		tabHTML.push("<td colspan=\"");
		tabHTML.push(nNbGraduationsMois);
		// Si on est sur une graduation, affiche une graduation
		// On utilise le style premier sur le dernier
		if ((i + nNbGraduationsMois) >= nLimiteI)
		{
			tabHTML.push("\" class=\"");
			tabHTML.push(this.ms_sNomPremier);
		}
		tabHTML.push("\">");

		// Traite le contenu de la rupture
		var tabRuptureLibelle = oGraduation.m_sRuptureLibelle.split(this.ms_sSeparateurFormatLigne);
		var nLargeur = this.__nGetDimensionPxSansBordure(this.m_oParametres.m_nDimensionPxGraduation * nNbGraduationsMois, this.m_oParametres.m_oStyleLibJourSemaine);
		this.m_tagLargeurMois.push(nLargeur);

		tabHTML.push("<div class=\"");
		tabHTML.push(this.ms_sNomJour);
		tabHTML.push(" ");
		tabHTML.push(this.m_oParametres.m_oStyleLibJourSemaine.m_sClasses);
		tabHTML.push("\" style=\"");
		tabHTML.push(this._tabInitCSS_DimensionLargeur([], nLargeur, this.ms_nPaddingTitreCalcul, 0, true).join(";"));
		tabHTML.push("\">");
		tabHTML.push(clWDEncode.sEncodeInnerHTML(tabRuptureLibelle[0], true, false));
		tabHTML.push("</div></td>");
	}
	tabHTML.push("</tr>");
};

// nombre de jour dans le mois
WDPlanningHorizontal.prototype.__nGetNbJoursAfficheMois = function __nGetNbJoursAfficheMois(nNbGraduationsParJour, nGraduation)
{
	// Selon la position des heures initialise
	var tabGraduations = this.m_tabGraduations;
	var i;
	var nLimiteI = tabGraduations.length;
	var nNbJoursAfficheMois = 1;
	var nMois = tabGraduations[nGraduation].m_nMois;
	for (i = nGraduation + nNbGraduationsParJour; i < nLimiteI; i += nNbGraduationsParJour, nNbJoursAfficheMois++)
	{
		if (tabGraduations[i].m_nMois != nMois)
		{
			break;
		}
	}
	return nNbJoursAfficheMois;
};

// Seconde ligne : les titres des jours (eventuellement double)
WDPlanningHorizontal.prototype.__HTMLAfficheTitresJours = function __HTMLAfficheTitresJours(tabHTML, nNbGraduationsParJour)
{
	tabHTML.push("<tr class=\"");
	tabHTML.push(this.ms_sNomTitresHeures);
	tabHTML.push(" ");
	tabHTML.push(this.ms_sNomJour);
	tabHTML.push("\">");

	var nLargeur = this.__nGetDimensionPxSansBordure(this.m_oParametres.m_nDimensionPxGraduation * nNbGraduationsParJour, this.m_oParametres.m_oStyleLibJourSemaine);
	var sStyle = this._tabInitCSS_DimensionLargeur([], nLargeur, this.ms_nPaddingTitreCalcul, 0, true).join(";");
	if (this.m_oParametres.m_bLigneTitreMois)
	{
		sStyle += ";text-align:center";
	}

	// Selon la position des heures initialise
	var tabGraduations = this.m_tabGraduations;
	var i;
	var nLimiteI = tabGraduations.length;
	for (i = 0; i < nLimiteI; i += nNbGraduationsParJour)
	{
		var oGraduation = tabGraduations[i];

		// Normalement on est sur une rupture (= changement de jour)
		// Genere la table
		tabHTML.push("<td colspan=\"");
		tabHTML.push(nNbGraduationsParJour);
//		// Si on est sur plusieurs lignes
//		if (this.m_oParametres.m_bLigneTitreJourDouble)
//		{
//			tabHTML.push("\" rowspan=\"")
//			tabHTML.push(2);
//		}
		// Si on est sur une graduation, affiche une graduation
		// On utilise le style premier sur le dernier
		if ((i + nNbGraduationsParJour) >= nLimiteI)
		{
			tabHTML.push("\" class=\"");
			tabHTML.push(this.ms_sNomPremier);
		}
		tabHTML.push("\">");

		// Traite le contenu de la rupture
		var tabRuptureLibelle = oGraduation.m_sRuptureLibelle.split(this.ms_sSeparateurFormatLigne);

		// La partie avec les rupture : dessus
		var j;
		var nLimiteJ = tabRuptureLibelle.length;
		for (j = this.m_oParametres.m_bLigneTitreMois ? 1 : 0; j < nLimiteJ; j++)
		{
			tabHTML.push("<div class=\"");
			tabHTML.push(this.ms_sNomJour);
			tabHTML.push(" ");
			tabHTML.push(this.m_oParametres.m_oStyleLibJourSemaine.m_sClasses);
			tabHTML.push("\" style=\"");
			tabHTML.push(sStyle);
			tabHTML.push("\">");
			tabHTML.push(clWDEncode.sEncodeInnerHTML(tabRuptureLibelle[j], true, false));
			tabHTML.push("</div>");
		}
		tabHTML.push("</td>");
	}
	tabHTML.push("</tr>");
//	if (this.m_oParametres.m_bLigneTitreJourDouble)
//	{
//		tabHTML.push("<tr/>")
//	}
};

// Troisieme ligne : les titres des heures
WDPlanningHorizontal.prototype.__HTMLAfficheTitresHeures = function __HTMLAfficheTitresHeures(tabHTML, nNbGraduationsParJour)
{
	tabHTML.push("<tr class=\"");
	tabHTML.push(this.ms_sNomTitresHeures);
	tabHTML.push("\">");


	// Selon la position des heures initialise
	var tabGraduations = this.m_tabGraduations;
	var i;
	var nLimiteI = tabGraduations.length;
	var nNbGraduationsAvantFinJour;
	var nNbColonnesPourHeure;
	for (i = 0; i < nLimiteI; i += nNbColonnesPourHeure, nNbGraduationsAvantFinJour -= nNbColonnesPourHeure)
	{
		var oGraduation = tabGraduations[i];

		// Si on commence un nouveau jour
		if (oGraduation.m_bRupture)
		{
			nNbGraduationsAvantFinJour = nNbGraduationsParJour;
		}

		// Calcule le nombre de colonne a utiliser
		nNbColonnesPourHeure = Math.min(nNbGraduationsAvantFinJour, this.m_oParametres.m_nNbGraduationParHeureAffichee);

		// Genere la table
		tabHTML.push("<td");
		if (1 < nNbColonnesPourHeure)
		{
			tabHTML.push(" colspan=\"");
			tabHTML.push(nNbColonnesPourHeure);
			tabHTML.push("\"");
		}
		// Si on est sur une graduation, affiche une graduation
		// On utilise le style premier sur le dernier
		if ((i + nNbColonnesPourHeure) >= nLimiteI)
		{
			tabHTML.push(" class=\"");
			tabHTML.push(this.ms_sNomPremier);
			tabHTML.push("\"");
		}
		tabHTML.push(">");

		tabHTML.push("<div class=\"");
		tabHTML.push(this.ms_sNomHeureLibelle);
		tabHTML.push(" ");
		tabHTML.push(oGraduation.m_sLibelleClasse);
		tabHTML.push("\" style=\"");
		var nLargeur = this.__nGetDimensionPxSansBordure(this.m_oParametres.m_nDimensionPxGraduation * nNbColonnesPourHeure, this.m_oParametres.m_oStyleLibHeure);
		tabHTML.push(this._tabInitCSS_DimensionLargeur([], nLargeur, this.ms_nPaddingTitreCalcul, 0, true).join(";"));
		if (oGraduation.m_sLibelleCouleurFond)
		{
			tabHTML.push(";background-color:");
			tabHTML.push(oGraduation.m_sLibelleCouleurFond);
		}
		tabHTML.push("\">");
		tabHTML.push(clWDEncode.sEncodeInnerHTML(oGraduation.m_sLibelle, true, false));
		tabHTML.push("</div></td>");
	}
	tabHTML.push("</tr>");

	// Ajoute une serie de colonnes vides pour IE
	if (bIEQuirks)
	{
		tabHTML.push("<tr style=\"height:0px\">");
		var sCellule = "<td style=\"width:" + (this.m_oParametres.m_nDimensionPxGraduation * nNbColonnesPourHeure) + "\" />";
		for (i = 0; i < nLimiteI; i++)
		{
			tabHTML.push(sCellule);
		}
		tabHTML.push("</tr>");
	}
};

// Construit le HTML des titres verticaux
// tabHTML inclus deja un <table> ouvrant => il faut commencer a tr
WDPlanningHorizontal.prototype._vHTMLAfficheTitresVertical = function _vHTMLAfficheTitresVertical(tabHTML)
{
	// Genere la table
	var tabRessources = this.m_oDonnees.m_tabRessources;
	var i;
	var nLimiteI = tabRessources.length;
	for (i = 0; i < nLimiteI; i++)
	{
		tabHTML.push("<tr class=\"");
		tabHTML.push(this.ms_sNomTitresRessources);
		tabHTML.push("\"><td");
		if (i == 0)
		{
			tabHTML.push(" class=\"");
			tabHTML.push(this.ms_sNomPremier);
			tabHTML.push("\"");
		}
		tabHTML.push(">");
		this.__HTMLAfficheDiv(tabHTML, this.m_oParametres.m_oStyleLibRessource.m_sClasses, undefined, clWDEncode.sEncodeInnerHTML(tabRessources[i].m_sNomAffiche, true, false));
		tabHTML.push("</td>");
	}
	tabHTML.push("</tr>");
};

// Zone de redimensionnement
WDPlanningHorizontal.prototype._vHTMLRendezVousRedimGauche = WDPlanning.prototype.__HTMLRendezVousRedim;
WDPlanningHorizontal.prototype._vHTMLRendezVousRedimDroite = WDPlanning.prototype.__HTMLRendezVousRedim;
WDPlanningHorizontal.prototype._vHTMLRendezVousRedimBas = WDChamp.prototype.m_pfVide;

// Recupere le defilement du corps : scrollLeft (ressources en ligne) ou scrollTop (ressources en colonne)
WDPlanningHorizontal.prototype._vnGetDefilementPrincipal = WDPlanning.prototype._nGetDefilementHorizontal;
WDPlanningHorizontal.prototype._vnGetDefilementLateral = WDPlanning.prototype._nGetDefilementVertical;
// Fixe le defilement du corps : scrollLeft (ressources en ligne) ou scrollTop (ressources en colonne)
WDPlanningHorizontal.prototype._vSetDefilementPrincipal = WDPlanning.prototype._SetDefilementHorizontal;
WDPlanningHorizontal.prototype._vSetDefilementLateral = WDPlanning.prototype._SetDefilementVertical;

// Sur le defilement du corps : pas de rupture dans ce mode
WDPlanningHorizontal.prototype._vOnDefilementCorps = function _vOnDefilementCorps(nLargeurCorps, nHauteurCorps, nDefilementHorizontal, nDefilementVertical)
{
	// Affiche correctement les ruptures de mois
	if (this.m_oParametres.m_bLigneTitreMois)
	{
		// Trouve le TR
		var tabTR = this.m_oHoteTitresHorizontal.getElementsByTagName("tr");
		if (tabTR && tabTR.length && tabTR[0])
		{
			var oTR = tabTR[0];

			// Parcours les td
			var tabTD = oTR.getElementsByTagName("td");
			// Si on a bien les elements (et que l'on en a le bon nombre
			if (tabTD && tabTD.length && tabTD.length == this.m_tagLargeurMois.length)
			{
				var nLargeurTotale = 0;
				var i;
				var nLimiteI = tabTD.length;
				for (i = 0; i < nLimiteI; i++)
				{
					var nLargeur = this.m_tagLargeurMois[i];
					var oTD = tabTD[i];
					// Si le mois est le premier visible
					if ((nDefilementHorizontal >= nLargeurTotale) && (nDefilementHorizontal <= (nLargeur + nLargeurTotale)))
					{
						// Force le defilement de l'element
						this.__DecaleRuptureMois(oTD, nDefilementHorizontal - nLargeurTotale, nLargeur);
					}
					else
					{
						// Stope le defilement de l'element
						this.__DecaleRuptureMois(oTD, 0, nLargeur);
					}
					nLargeurTotale += nLargeur;
				}
			}
		}
	}
};

// Decale un libelle de mois
WDPlanningHorizontal.prototype.__DecaleRuptureMois = function __DecaleRuptureMois(oTD, nDecalage, nLargeur)
{
	oTD.style.paddingLeft = nDecalage + "px";
	oTD.style.width = Math.max(1, (nLargeur - nDecalage)) + "px";
	oTD.firstChild.style.width = Math.max(1, (nLargeur - nDecalage)) + "px";
	oTD.firstChild.style.minWidth = Math.max(1, (nLargeur - nDecalage)) + "px";
	oTD.firstChild.style.maxWidth = Math.max(1, (nLargeur - nDecalage)) + "px";

};

// En mode quirks, il y a le padding en plus
// - En mode ressources en ligne, c'est le padding "avant" => this.ms_nPaddingLateralDebut
// - En mode ressources en colonne, c'est le padding "apres" => this.ms_nPaddingLateralFin
WDPlanningHorizontal.prototype._vnGetPaddingTopPourRendezVous = function _vnGetPaddingTopPourRendezVous()
{
	return bIEQuirks ? this.ms_nPaddingLateralDebut : 0;
};
WDPlanningHorizontal.prototype._vnGetPaddingRightPourRendezVous = function _vnGetPaddingRightPourRendezVous()
{
	return 0;
//	return bIEQuirks ? 0 : 0;
};

// Fixe le debut dans le sens principal : left (ressources en ligne) ou top (ressources en colonne)
WDPlanningHorizontal.prototype.vSetDebut = function vSetDebut(oElement, sDebut)
{
	oElement.style.left = sDebut;
};
// Fixe la longueur dans le sens principal : width (ressources en ligne) ou height (ressources en colonne)
WDPlanningHorizontal.prototype.vSetLongueur = function vSetLongueur(oElement, sLongueur)
{
	oElement.style.width = sLongueur;
};

// Fixe le debut lateral : top (ressources en ligne) ou left (ressources en colonne)
WDPlanningHorizontal.prototype.vSetDebutLateral = function vSetDebutLateral(oElement, sDebut)
{
	oElement.style.top = sDebut;
};
// Fixe la longueur laterale : height (ressources en ligne) ou width (ressources en colonne)
WDPlanningHorizontal.prototype.vSetLongueurLateral = function vSetLongueurLateral(oElement, sLongueur)
{
	oElement.style.height = sLongueur;
};
// Fixe le bord final lateral : bottom (ressources en ligne) ou right (ressources en colonne)
WDPlanningHorizontal.prototype.vSetFinLateral = function vSetFinLateral(oElement, sFin)
{
	oElement.style.bottom = sFin;
};

// Retourne offsetLeft (ressources en ligne) ou offsetTop (ressources en colonne)
WDPlanningHorizontal.prototype.voGetOffsetDebut = function voGetOffsetDebut(oElement)
{
	return oElement.offsetLeft;
};
// Retourne offsetWidth (ressources en ligne) ou offsetHeight (ressources en colonne)
WDPlanningHorizontal.prototype.voGetOffsetLongueur = function voGetOffsetLongueur(oElement)
{
	return oElement.offsetWidth;
};

// Retourne le deplacement important pour la position : X (ressources en ligne) ou Y (ressources en colonne)
WDPlanningHorizontal.prototype.vnGetOffsetPosition = function vnGetOffsetPosition(nOffsetPositionX, nOffsetPositionY)
{
	return nOffsetPositionX;
};
// Retourne la coordonnee importante pour la position : X (ressources en ligne) ou Y (ressources en colonne) selon le conteneur hote
WDPlanningHorizontal.prototype.vnGetPositionHote = function vnGetPositionHote(oElement, nPositionX, nPositionY)
{
	return _JCCP(nPositionX, oElement, true, false) + this.m_oHoteCorps.scrollLeft;
};

// Appel de _sGetHTMLRendezVous avec les bonnes dimensions
WDPlanningHorizontal.prototype._vsGetHTMLRendezVous = function _vsGetHTMLRendezVous(oElement, nLongueur, nDimensionLateralePx)
{
	return this._sGetHTMLRendezVous(oElement, nLongueur, nDimensionLateralePx);
};

//////////////////////////////////////////////////////////////////////////
// Le gestionnaire de dragdrop pour le champ planning : gestion des ressources et d'un fantome

// Constructeur
function WDDragPlanning (nDelaiAvantDeplacement, nDelaiEntreDeplacement, oChampPlanning)
{
	// Si on est pas dans l'init d'un protoype
	if (nDelaiAvantDeplacement !== undefined)
	{
		// Appel le constructeur de la classe de base
		WDDrag.prototype.constructor.apply(this, [nDelaiAvantDeplacement, nDelaiEntreDeplacement]);

		// Sauve l'objet attache
		this.m_oChampPlanning = oChampPlanning;
	}
}

// Declare l'heritage
WDDragPlanning.prototype = new WDDrag();
// Surcharge le constructeur qui a ete efface
WDDragPlanning.prototype.constructor = WDDragPlanning;

// Initialisation
WDDragPlanning.prototype.Init = function Init()
{
	// Appel de la methode de la classe de base
	WDDrag.prototype.Init.apply(this, arguments);
};

// Gestion pour un element
WDDragPlanning.prototype.InitElement = function InitElement(oElement, oDiv)
{
	// Intercepte le mousedown sur le rendez-vous
	var oThis = this;
	var oElementLocal = oElement;
	oElement.m_fMouseDown = function(oEvent) { oEvent = oEvent ? oEvent : event; oThis.OnMouseDown.apply(oThis, [oEvent, oElementLocal]); return oThis._bStopPropagation(oEvent); };
	HookOnXXX(oDiv, 'onmousedown', 'mousedown', oElement.m_fMouseDown);
};
WDDragPlanning.prototype.LibereElement = function LibereElement(oElement, oDiv)
{
	// Supprime l'evenement mousedown sur le rendez-vous
	UnhookOnXXX(oDiv, 'onmousedown', 'mousedown', oElement.m_fMouseDown);
	oElement.m_fMouseDown = null;
	delete oElement.m_fMouseDown;
};

// Appel lors du debut d'un clic pour le deplacement
// Pose les hooks
WDDragPlanning.prototype._vbOnMouseDown = function _vbOnMouseDown(oEvent)
{
	// Pas de drag-drop si on est en saisie
	if (this.m_oChampPlanning.m_oPopupSaisie.m_oRendezVous)
	{
		return false;
	}

	// Appel de la classe de base : sauve la position de la souris et place les hooks
	if (!WDDrag.prototype._vbOnMouseDown.apply(this, arguments))
	{
		return false;
	}

	// Suppression du fantome : on est sur de ne plus avoir un ancien fantome
	this.__FantomeSupprime();

	return true;
};

// Appel lors du deplacement de la souris
WDDragPlanning.prototype._vOnMouseMove = function _vOnMouseMove(oEvent)
{
	// Appel de la classe de base
	WDDrag.prototype._vOnMouseMove.apply(this, arguments);

	// Creation du fantome (si besoin)
	if (!this.m_oDivFantome)
	{
		// _vbFantomeCree est redefinie dans les classes derivees et transmet les parametres a _FantomeCree
		if (!this._vbFantomeCree(oEvent))
		{
			return;
		}
	}
	// Deplacement du fantome
	// _vbFantomeDeplace est redefinie dans les classes derivees et transmet les parametres a _bFantomeDeplace
	this._vbFantomeDeplace(oEvent);
};

// Appel lors du relachement de la souris
WDDragPlanning.prototype._vOnMouseUp = function _vOnMouseUp(oEvent)
{
	// Si besoin il faut que la fonction dans la classe derivee fasse une derniere MAJ du Fantome
//	this._vbFantomeDeplace(oEvent);

	// Suppression du fantome
	this.__FantomeSupprime();

	// Appel de la classe de base
	WDDrag.prototype._vOnMouseUp.apply(this, arguments);
};

// Creation du fantome (a redefinir)
WDDragPlanning.prototype._vbFantomeCree = function _vbFantomeCree(oEvent)
{
	// Appel de _FantomeCree dans les derivees
	return true;
};

// Creation du fantome
WDDragPlanning.prototype._FantomeCree = function _FantomeCree(nDebut, nLongueur, nRessource, sCouleur)
{
	if (!this.m_oDivFantome)
	{
		// Creation du fantome
		var oDivFantome = document.createElement("div");
		oDivFantome.style.position = "absolute";

		// Positionne le fantome pour prendre toute la place et le dimensionne au meme endroit que le rendez-vous
		this.m_oChampPlanning.nHTMLAfficheUnRendezVousSuperposition(oDivFantome, 0, 1, (0 == nRessource));
		this.m_oChampPlanning.vSetDebut(oDivFantome, nDebut);
		this.m_oChampPlanning.vSetLongueur(oDivFantome, nLongueur);

		this.m_nDivFantomeDebut = nDebut;
		this.m_nDivFantomeLongueur = nLongueur;
		oDivFantome.style.backgroundColor = sCouleur ? sCouleur : "#cccccc";
		oDivFantome.style.opacity = _JCPO(60, oDivFantome);
		// Colle le fantome au premier plan
		oDivFantome.style.zIndex = this.m_oChampPlanning.ms_nZIndexFantome;
		// Et masque le bouton de suppression pour qu'il ne passe pas dessus
		if (this.m_oChampPlanning.m_oRendezVousSuppression)
		{
			this.m_oChampPlanning.m_oRendezVousSuppression.style.visibility = "hidden";
		}

		this.m_oDivFantome = this.m_oChampPlanning.oGetConteneurRessource(nRessource).appendChild(oDivFantome);
		this.m_nDivFantomeRessource = nRessource;
	}
};

// Deplacement du fantome
WDDragPlanning.prototype._vbFantomeDeplace = function _vbFantomeDeplace(oEvent)
{
	// Appel de _bFantomeDeplace dans les derivees
	return true;
};

// Deplacement du fantome
WDDragPlanning.prototype._bFantomeDeplace = function _bFantomeDeplace(nDebut, nLongueur, nRessource)
{
	// Si le fantome n'a jamais ete cree (simple clic sans mouvement)
	if (!this.m_oDivFantome)
	{
		return false;
	}

	this.m_oChampPlanning.vSetDebut(this.m_oDivFantome, nDebut);
	this.m_oChampPlanning.vSetLongueur(this.m_oDivFantome, nLongueur);

	// Changement de conteneur si besoin
	if (this.m_nDivFantomeRessource != nRessource)
	{
		this.m_oDivFantome = this.m_oDivFantome.parentNode.removeChild(this.m_oDivFantome);
		this.m_oDivFantome = this.m_oChampPlanning.oGetConteneurRessource(nRessource).appendChild(this.m_oDivFantome);
		this.m_nDivFantomeRessource = nRessource;
	}

	return true;
};

// Suppression du fantome
WDDragPlanning.prototype.__FantomeSupprime = function __FantomeSupprime()
{
	if (bHTMLVideDepuisVariable(this, "m_oDivFantome"))
	{
		// Reaffiche le bouton de suppression
		if (this.m_oChampPlanning.m_oRendezVousSuppression)
		{
			this.m_oChampPlanning.m_oRendezVousSuppression.style.visibility = "visible";
		}
		delete this.m_nDivFantomeRessource;
		delete this.m_nDivFantomeLongueur;
		delete this.m_nDivFantomeDebut;
	}
};

// Le gestionnaire de dragdrop des rendez-vous
function WDDragRendezVous(oChampPlanning)
{
	// Si on est pas dans l'init d'un protoype
	if (oChampPlanning)
	{
		// Appel le constructeur de la classe de base
		WDDragPlanning.prototype.constructor.apply(this, [250, 50, oChampPlanning]);
	}
}

// Declare l'heritage
WDDragRendezVous.prototype = new WDDragPlanning();
// Surcharge le constructeur qui a ete efface
WDDragRendezVous.prototype.constructor = WDDragRendezVous;

// Initialisation
WDDragRendezVous.prototype.Init = function Init()
{
	// Appel de la methode de la classe de base
	WDDragPlanning.prototype.Init.apply(this, arguments);
};

// Appel lors du debut d'un clic pour le deplacement
// Pose les hooks
WDDragRendezVous.prototype._vbOnMouseDown = function _vbOnMouseDown(oEvent, oRendezVous)
{
	// Appel de la classe de base : sauve la position de la souris et place les hooks
	if (!WDDragPlanning.prototype._vbOnMouseDown.apply(this, [oEvent]))
	{
		return false;
	}

	// Selectionne le rendez-vous
	var bRes = this.m_oChampPlanning.bOnRendezVousSelection(oEvent, oRendezVous);
	if (bRes)
	{
		// Determine si on est en deplacement ou en redimensionnement
		this.m_eDragMode = this.__eGetDragMode(oEvent, oRendezVous);
		// Verifie si l'action est autorise
		switch (this.m_eDragMode)
		{
		case this.ms_eDragRedimDebut:
		case this.ms_eDragRedimFin:
			bRes = this.m_oChampPlanning.m_oParametres.m_bRedimensionnementRendezVous;
			break;
		case this.ms_eDragDrop:
		default:
			bRes = this.m_oChampPlanning.m_oParametres.m_bDeplacementRendezVous;
			break;
		}
	}

	// Si on doit annuler
	if (!bRes)
	{
		delete this.m_eDragMode;
		// Annule la selection
		this.OnMouseUp(oEvent);

		return false;
	}

	return true;
};

// Determine si on est en deplacement ou en redimensionnement
WDDragRendezVous.prototype.__eGetDragMode = function __eGetDragMode(oEvent, oRendezVous)
{
	// Seln la classe de l'element clique
	var oSource = clWDUtil.oGetOriginalTarget(oEvent);
	if (oSource)
	{
		switch (oSource.className)
		{
		case this.m_oChampPlanning.ms_sNomRendezVousRedimDebut:
			return this.ms_eDragRedimDebut;
		case this.m_oChampPlanning.ms_sNomRendezVousRedimFin:
			return this.ms_eDragRedimFin;
		}
	}
	return this.ms_eDragDrop;
};

// Appel lors du deplacement de la souris
WDDragRendezVous.prototype._vOnMouseMove = function _vOnMouseMove(oEvent)
{
	// Appel de la classe de base
	WDDragPlanning.prototype._vOnMouseMove.apply(this, arguments);
};

// Appel lors du relachement de la souris
WDDragRendezVous.prototype._vOnMouseUp = function _vOnMouseUp(oEvent)
{
	// Uniquement les clics "lents"
	if (this.m_nDateMouseDown === undefined)
	{
		// Dernier deplacement du fantome
		if (this._vbFantomeDeplace(oEvent))
		{
			// C'est un clic "lent" : drag-drop : effectue le deplacement
			this.__Deplacement(oEvent);
		}
	}

	delete this.m_eDragMode;

	// Appel de la classe de base
	WDDragPlanning.prototype._vOnMouseUp.apply(this, arguments);
};

// Effectue le deplacement
WDDragRendezVous.prototype.__Deplacement = function __Deplacement(oEvent)
{
	var nDebut = this.m_oChampPlanning.voGetOffsetDebut(this.m_oDivFantome);
	var nLongueur = this.m_oChampPlanning.voGetOffsetLongueur(this.m_oDivFantome);
	var nRessource = this.m_nDivFantomeRessource;

	switch (this.m_eDragMode)
	{
	case this.ms_eDragRedimDebut:
	case this.ms_eDragRedimFin:
		// Notifie du redimensionnement de la selection
		this.m_oChampPlanning.OnRendezVousRedimensionne(oEvent, nDebut, nLongueur);
		break;
	case this.ms_eDragDrop:
	default:
		// Notifie du deplacement (et/ou du changement de ressources)
		this.m_oChampPlanning.OnRendezVousDeplacement(oEvent, nDebut, nLongueur, nRessource);
		break;
	}
};

// Creation du fantome (a redefinir)
WDDragRendezVous.prototype._vbFantomeCree = function _vbFantomeCree(oEvent)
{
	// Appel _FantomeCree avec les bons parametres
	var oRendezVous = this.m_oChampPlanning.oGetRendezVousSelection();
	var oRendezVousDiv = oRendezVous.m_oDiv;
	this._FantomeCree(this.m_oChampPlanning.voGetOffsetDebut(oRendezVousDiv), this.m_oChampPlanning.voGetOffsetLongueur(oRendezVousDiv), oRendezVous.m_nRessource, oRendezVous.m_cFond);

	return true;
};

// Deplacement du fantome
WDDragRendezVous.prototype._vbFantomeDeplace = function _vbFantomeDeplace(oEvent)
{
	var oChampPlanning = this.m_oChampPlanning;

	var nDebut = this.m_nDivFantomeDebut;
	var nLongueur = this.m_nDivFantomeLongueur;
	var nRessource = this.m_nDivFantomeRessource;

	// Arrondi la variation en fonction de la granularite autorisee
	var nOffsetPosition = oChampPlanning.vnGetOffsetPosition(this.nGetOffsetPosX(oEvent), this.nGetOffsetPosY(oEvent));
	var nFin = nDebut + nLongueur;

	// Selon le mode de redimensionnement
	switch (this.m_eDragMode)
	{
	case this.ms_eDragRedimDebut:
		nDebut = oChampPlanning.nAppliqueResolutionDeplacement(nDebut + nOffsetPosition);
		nLongueur = oChampPlanning.nAppliqueResolutionTaille(nLongueur - nOffsetPosition);
		// Si la variation de hauteur (arrondie) est negative
		if (nLongueur <= 0)
		{
			nLongueur = oChampPlanning.nAppliqueResolutionTaille(0, 0);
		}
		break;

	case this.ms_eDragRedimFin:
		nLongueur = oChampPlanning.nAppliqueResolutionTaille(nLongueur + nOffsetPosition, 0);
		// Si la variation de hauteur (arrondie) est negative
		if (nLongueur <= 0)
		{
			nLongueur = oChampPlanning.nAppliqueResolutionTaille(0, 0);
		}
		break;
	case this.ms_eDragDrop:
	default:
		nDebut = oChampPlanning.nAppliqueResolutionDeplacement(nDebut + nOffsetPosition);
		nLongueur = oChampPlanning.nAppliqueResolutionTaille(nLongueur);
		// Changement de ressource ?
		nRessource = oChampPlanning.nGetRessourceDepuisPosition(oEvent, nRessource);
		break;
	}

	// Appel de _bFantomeDeplace pour effectue l'affichage
	return this._bFantomeDeplace(nDebut, nLongueur, nRessource);
};

// Le gestionnaire de selection d'une periode pour la creation d'un rendez-vous
function WDDragPeriodeSelect(oChampPlanning)
{
	// Si on est pas dans l'init d'un protoype
	if (oChampPlanning)
	{
		// Appel le constructeur de la classe de base
		// 200 : Pour ne pas appeler le PCode en boucle
		WDDragPlanning.prototype.constructor.apply(this, [0, 200, oChampPlanning]);
	}
}

// Declare l'heritage
WDDragPeriodeSelect.prototype = new WDDragPlanning();
// Surcharge le constructeur qui a ete efface
WDDragPeriodeSelect.prototype.constructor = WDDragRendezVous;

// Initialisation
WDDragPeriodeSelect.prototype.Init = function Init()
{
	// Appel de la methode de la classe de base
	WDDragPlanning.prototype.Init.apply(this, arguments);
};

// Stoppe la propagation sauf si on est en edition de champ
WDDragPeriodeSelect.prototype._vbStopPropagation = function _vbStopPropagation()
{
	return !this.m_oChampPlanning.m_oParametres.m_bSelectionPeriode;
};

// Appel lors du debut d'un clic pour le deplacement
// Pose les hooks
WDDragPeriodeSelect.prototype._vbOnMouseDown = function _vbOnMouseDown(oEvent, oRessource)
{
	// Si on clic sur un rendez-vous ne fait rien
	var oSource = clWDUtil.oGetOriginalTarget(oEvent);
	if (oSource != this.m_oChampPlanning.oGetConteneurRessource(oRessource.m_nRessource))
	{
		return false;
	}

	// Valide que l'on a le droit de selectionner une periode
	if (!this.m_oChampPlanning.m_oParametres.m_bSelectionPeriode)
	{
		return false;
	}

	// Appel de la classe de base : sauve la position de la souris et place les hooks
	if (!WDDragPlanning.prototype._vbOnMouseDown.apply(this, [oEvent]))
	{
		return false;
	}

	// Calcule la position initiale du fantome
	var oPosition = this.__oGetPositionFantome(oEvent, oRessource);
	// Lancement de la selection
	if (!this.m_oChampPlanning.bOnPeriodeSelect(oEvent, oPosition.m_nDebut, oPosition.m_nLongueur, oRessource.m_nRessource))
	{
		// Annule la selection
		this.OnMouseUp(oEvent);
		return false;
	}

	this.m_oRessource = oRessource;
	return true;
};

// Appel lors du deplacement de la souris
WDDragPeriodeSelect.prototype._vOnMouseMove = function _vOnMouseMove(oEvent)
{
	// Appel de la classe de base
	WDDragPlanning.prototype._vOnMouseMove.apply(this, arguments);
};

// Appel lors du relachement de la souris
WDDragPeriodeSelect.prototype._vOnMouseUp = function _vOnMouseUp(oEvent)
{
	// Dernier deplacement du fantome
	if (this._vbFantomeDeplace(oEvent))
	{
		// C'est un clic "lent" : drag-drop : effectue le deplacement
		this.__Creation(oEvent);
	}

	delete this.m_oRessource;

	// Appel de la classe de base
	WDDragPlanning.prototype._vOnMouseUp.apply(this, arguments);
};

// Effectue la creation
WDDragPeriodeSelect.prototype.__Creation = function __Creation(oEvent)
{
	// Calcule la position du fantome (en double entre l'appel de _vbFantomeDeplace de _vOnMouseUp)
	var oPosition = this.__oGetPositionFantome(oEvent, this.m_oRessource);
	// Lancement de la creation
	this.m_oChampPlanning.OnRendezVousAjoute(oEvent, oPosition.m_nDebut, oPosition.m_nLongueur, this.m_oRessource.m_nRessource);
};

// Creation du fantome (a redefinir)
WDDragPeriodeSelect.prototype._vbFantomeCree = function _vbFantomeCree(oEvent)
{
	// Calcule la position du fantome
	var oPosition = this.__oGetPositionFantome(oEvent, this.m_oRessource);
	// Lancement de la selection
	if (!this.m_oChampPlanning.bOnPeriodeSelect(oEvent, oPosition.m_nDebut, oPosition.m_nLongueur, this.m_oRessource.m_nRessource))
	{
		// Annule la selection
		this.OnMouseUp(oEvent);
		return false;
	}

	// Appel _FantomeCree avec les bons parametres
	this._FantomeCree(oPosition.m_nDebut, oPosition.m_nLongueur, this.m_oRessource.m_nRessource, this.m_oChampPlanning.m_oParametres.m_oStyleSelection.m_cFond);
	return true;
};

// Deplacement du fantome
WDDragPeriodeSelect.prototype._vbFantomeDeplace = function _vbFantomeDeplace(oEvent)
{
	// Calcule la position du fantome
	var oPosition = this.__oGetPositionFantome(oEvent, this.m_oRessource);
	// Lancement de la selection
	if (!this.m_oChampPlanning.bOnPeriodeSelect(oEvent, oPosition.m_nDebut, oPosition.m_nLongueur, this.m_oRessource.m_nRessource))
	{
		// Annule la selection
		this.OnMouseUp(oEvent);
		return false;
	}

	// Appel _bFantomeDeplace avec les bons parametres
	return this._bFantomeDeplace(oPosition.m_nDebut, oPosition.m_nLongueur, this.m_oRessource.m_nRessource);
};

// Calcule la position du fantome
// retourne un objet avec m_nDebut et m_nLongueur
WDDragPeriodeSelect.prototype.__oGetPositionFantome = function __oGetPositionFantome(oEvent, oRessource)
{
	var oChampPlanning = this.m_oChampPlanning;
	// Recupere le dragdrop actuel
	var nPosition = oChampPlanning.vnGetPositionHote(oRessource.m_oDiv, this.nGetPosX(), this.nGetPosY());
	var nOffsetPosition = oChampPlanning.vnGetOffsetPosition(this.nGetOffsetPosX(oEvent), this.nGetOffsetPosY(oEvent));

	// Inverse la position si besoin pour avoir des coordonnees positives
	if (nOffsetPosition < 0)
	{
		nPosition = nPosition + nOffsetPosition;
		nOffsetPosition = -nOffsetPosition;
	}

	// Calcule la position du haut
	var nDebut = oChampPlanning.nAppliqueResolutionDeplacement(nPosition);
	// Et la longeur : arrondi la position en fonction de la granularite autorisee
	var nLongueur = oChampPlanning.nAppliqueResolutionTaille(nOffsetPosition, nPosition - nDebut);

	return {
		m_nDebut: nDebut,
		m_nLongueur: nLongueur
	};
};

// Objet pour la recherche dans une colonne
function WDPopupSaisiePlanning(oObjetParent)
{
	// Si on est pas dans l'init d'un protoype
	if (oObjetParent)
	{
		// Appel le constructeur de la classe de base
		WDPopupSaisie.prototype.constructor.apply(this, [oObjetParent, true]);
	}
}

// Declare l'heritage
WDPopupSaisiePlanning.prototype = new WDPopupSaisie();
// Surcharge le constructeur qui a ete efface
WDPopupSaisiePlanning.prototype.constructor = WDPopupSaisiePlanning;

// Initialisation
WDPopupSaisiePlanning.prototype.Init = function Init()
{
	// Appel de la methode de la classe de base
	WDPopupSaisie.prototype.Init.apply(this, arguments);
};

// Debut de la saisie
// nReductionLargeur : pour la saisie dans le champ table : on ne prend pas toute la largeur
WDPopupSaisiePlanning.prototype._vDebut = function _vDebut(oConteneurParent, nReductionLargeur, oRendezVous)
{
	// Appel de la classe de base
	WDPopupSaisie.prototype._vDebut.apply(this, arguments);

	// Memorise le rendez-vous
	this.m_oRendezVous = oRendezVous;
	// Force la valeur
	this.m_oSaisie.value = oRendezVous.m_sTitre;
};

// Valide la saisie
WDPopupSaisiePlanning.prototype._vValide = function _vValide(oEvent, sValeur)
{
	// Appel de la classe de base
	WDPopupSaisie.prototype._vValide.apply(this, arguments);

	// Appel du champ
	this.m_oObjetParent.OnRendezVousValideSaisie(oEvent, this.m_oRendezVous, sValeur);
};

// Annule la saisie
WDPopupSaisiePlanning.prototype._vAnnule = function _vAnnule()
{
	// Libere nos valeurs
	this.m_oRendezVous = null;
	delete this.m_oRendezVous;

	// Appel de la classe de base
	WDPopupSaisie.prototype._vAnnule.apply(this, arguments);
};

// Manipulation d'un rendez-vous du champ planning
// oRendezVous : structure du champ planning contenant les donnees du rendez-vous (cette classe n'est qu'un wrapper)
function WDRendezVous(oChampPlanning, oRendezVous)
{
	// Appel le constructeur de la classe de base
	// Si un jour on derive de la classe, mettre un parametre pour proteger l'appel
	WDTypeAvance.prototype.constructor.apply(this, []);

	if (oChampPlanning && oRendezVous)
	{
		this.m_oChampPlanning = oChampPlanning;
		this.m_oRendezVous = oRendezVous;
	}
}

// Declare l'heritage
WDRendezVous.prototype = new WDTypeAvance(true);
// Surcharge le constructeur qui a ete efface
WDRendezVous.prototype.constructor = WDRendezVous;

// Lire une propriete
WDRendezVous.prototype.GetProp = function GetProp(nPropriete)
{
	switch (nPropriete)
	{
	case 0:		// Titre
		return this.m_oRendezVous.m_sTitre;
	case 1:		// CouleurFond
		return this.m_oRendezVous.m_cFondContenu;
	case 2:		// DateDebut : format AAAAMMJJHHMMSSCCC
		return this.__DateHeure2WL(this.m_oRendezVous.m_oDateDebut);
	case 3:		// DateFin : format AAAAMMJJHHMMSSCCC
		return this.__DateHeure2WL(this.m_oRendezVous.m_oDateFin);
	case 4:		// Contenu
		return this.m_oRendezVous.m_sContenu;
	case 8:		// Categorie
		return this.m_oRendezVous.m_sCategorie;
	case 14:	// ID (attention c'est l'ID utilisateur par l'ID unique du rendez-vous)
		return this.m_oRendezVous.m_sIDUtilisateur;
	case 15:	// Bulle
		return this.m_oRendezVous.m_sBulle;
	case 16:	// Ressource
		return this.m_oChampPlanning.sGetNomRessource(this.m_oRendezVous.m_nRessource);
	default:
		return WDTypeAvance.prototype.GetProp.apply(this, arguments);
	}
};

WDRendezVous.prototype.__DateHeure2WL = function __DateHeure2WL(oDate)
{
	// Pas d'utilisation de "JS_DateToWD" ("_JDTW") car on utilise la date en UTC (pour avoir la meme reponse quelque soit l'endroit de consultation)
	var tabResultat = [];
	// L'annee est >= 1970
	this.__CompleteEntier(tabResultat, oDate.getUTCFullYear(), 4);
	// Le moins est entre 0 et 11
	this.__CompleteEntier(tabResultat, oDate.getUTCMonth() + 1, 2);
	// Le jour est entre 1 et 31
	this.__CompleteEntier(tabResultat, oDate.getUTCDate(), 2);
	// Les heures (entre 0 et 23)
	this.__CompleteEntier(tabResultat, oDate.getUTCHours(), 2);
	this.__CompleteEntier(tabResultat, oDate.getUTCMinutes(), 2);
	this.__CompleteEntier(tabResultat, oDate.getUTCSeconds(), 2);
	this.__CompleteEntier(tabResultat, oDate.getUTCMilliseconds(), 3);
	return tabResultat.join("");
};
WDRendezVous.prototype.__CompleteEntier = function __CompleteEntier(tabResultat, nValeur, nTailleMin)
{
	var sValeur = nValeur + "";
	while (sValeur.length < nTailleMin)
	{
		sValeur = "0" + sValeur;
	}
	tabResultat.push(sValeur);
};

// Manipulation d'une repetition de rendez-vous
function WDRepetition()
{
	// Appel le constructeur de la classe de base
	// Si un jour on derive de la classe, mettre un parametre pour proteger l'appel
	WDTypeAvance.prototype.constructor.apply(this, [true]);
}

// Declare l'heritage
WDRepetition.prototype = new WDTypeAvance();
// Surcharge le constructeur qui a ete efface
WDRepetition.prototype.constructor = WDRepetition;

// Lire une propriete
WDRepetition.prototype.GetProp = function GetProp(nPropriete)
{
	switch (sPropriete)
	{
	default:
		return WDTypeAvance.prototype.GetProp.apply(this, arguments);
	}
};
