/**
 * copyright (c) 2005-2006 - lx barjon <lx@iassa.com>
 * class toolTips
 * version : 0.7.5 (09-05-2006)
 * licence : GNU GPL
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 **************************************************************************
 *
 * @author lx barjon <lx@iassa.com>
 * @access public
 * @version 0.7.5
 */

var toolTips = {};
toolTips = Class.create();
toolTips.prototype = {

	initialize: function( options ) {
		this.version = '0.7.5';

		if ( !document.getElementById || !document.getElementsByTagName ) return;

		Object.extend( this.options = {
			pathToImgs: '',
			// mode = title
			//    -> recupère tous les tag <a> est stocke le contenu de l'attribut title pour un affichage perso
			//    -> ajoute les event (mouseover et mouseout) automatiquement
			// mode = nom_de_class (exemple 'tip')
			//    -> recup tous les tag ayant pour class nom_de_class (exemple <div class="tip"></div>)
			//    -> bouge le tag dans le container approprié (this.options.tipsContainer) pour un affichage perso
			// Il est possible d'utiliser les deux modes en même temps, dans ce cas il faut que les container ait un id différent
			mode:             'title',
			showOn: 'mouseouver',
			hideOn: 'mouseout',
			// si hideDelay > showDelay, hideDelay prend la valeur showDelay-0.1)
			showDelay:        1,       // delais avant affichage, en seconde
			hideDelay:        0.1,     // delais avant masquage, en seconde
			mouseOverTips:    false,   // true -> permet de garder le tip affiché s'il on passe la souris dessus
			// options possibles
			// fixX : pour fixer les tips sur l'axe des x, peut être utilisé seul (le tips ne bougera que sur les Y)
			//				ou avec fixY (le tips sera immobile aux coordonnées x,y fournies)
			// fixY : pour fixer les tips sur l'axe des y
			// il faut fournir l'unité pour ces 2 options : ex. fixX: "30%", fixY: "150px"
			// rend obsolete les options ecartX et ecart Y
			ecartX:           5,       // ecart sur X par rapport à la souris
			ecartY:           10,      // ecart sur Y par rapport à la souris
			fixToParent:      false,   // Cette option permet de fixer le tip par rapport au tag correspondant (le parent)
			                           // 'false' par défaut -> le positionnement du tip se fait par rapport à la position de la souris (le tip suit la souris). Les options fixX et fixY seront prise en compte
                                 // true -> le tip est positionné par rapport au parent (bas gauche par défaut, s'adapte en fonction de la zone d'affichage).
                                 // du coup les options ecartX et ecartY sont utilisées pour décaler le tip fonction de son positionnement par rapport au parent
			fixTPMode:          'BL',  // pour le positionnement du tip par rapport au parent
			                           // utile uniquement si fixToParent est à true
			                           //  - TL -> top left
			                           //  - TR -> top right
			                           //  - BL -> bottom left
			                           //  - BR -> bottom right
			hookToID:         false,   // accrocher les tips définis en fonction de leur id. L'id des tips doit être du type help_idElementToHook ou idElementToHook est l'id du tag auquel il faut attacher le tip correspondant
			useHelpButton:    false,   // ajoute des images sur lesquelles il faut passer la souris pour obtenir les tips
			hbEcartX:         0,       // pour le positionnement sur X des images
			hbEcartY:         -5,      // pour le positionnement sur Y des images
			getRemoteContent: false,   // si true -> récupère le contenu du type. Le contenu doit être une adresse http valide pour un dl de données via AJAX
			riseReload: false          // recharge l'url recup a chaque affichage (si getRemoteContent)
		}, options || {} );

		// vérif options showDelay et hideDelay
		if ( this.options.hideDelay > this.options.showDelay ) this.options.hideDelay = this.options.showDelay - 0.1;

		// création du div qui contiendra les tips
		this.container = $( 'tc_' + this.options.mode );
		if ( !this.container ) {
			var tipsContainer = Builder.node( 'div', {id: 'tc_' + this.options.mode, style: 'position: absolute; z-index: 5000; display: none;'} );
			document.getElementsByTagName( 'body' )[0].appendChild(tipsContainer);
			this.container = $('tc_' + this.options.mode);
		} else this.container.innerHTML = '';
		if ( !this.container ) return;

		// pour stocker le parent du tip actuellement affiché, pour le cas ou l'option mouseOverTips soit à true
		if ( this.options.mouseOverTips ) {
			this.currentTipsParent = false;
		}

		// pour stocker les infos concernant les tips
		this.elements = new Array();
		this._set_links_and_tooltips();
		if ( !this.options.fixToParent ) {
			Event.observe( document, "mousemove", this._mouse_positioning.bindAsEventListener(this) );
		}
	},

	mOver: function(event) {
		var element = Event.element(event);
		var mouseX = Event.pointerX(event);
		var mouseY = Event.pointerY(event);
		if ( !element ) return;
		if ( element.tipState == 'off' ) {
			this._cancel_rising();
			var _riseTips = this.rise_tips.bind( this );
			this.riseTimeout = setTimeout( function() { _riseTips(element, mouseX, mouseY); }, (this.options.showDelay * 1000) );
		} else {
			this._cancel_hidding();
		}
	},

	mOut: function(event) {
		var element = Event.element(event);
		if ( !element ) return;
		this._cancel_rising();
		if ( element.tipState == 'on' ) {
			var _hideTips = this.hide_tips.bind( this );
			this.hideTimeout = setTimeout( function() { _hideTips(element); }, (this.options.hideDelay * 1000) );
		}
	},

	rise_tips: function(element, mouseX, mouseY) {
		if ( this.options.mode == 'title' ) {
			this.container.innerHTML = element.tipContent;
			Element.show(this.container);
		} else {
			if ( this.options.getRemoteContent && this.options.riseReload ) {
				var myAjax = new Ajax.Updater( {
					success: element.tipContent.id
				}, element.url, {
					method: 'get',
					parameters: '',
					onFailure: function() {
						element.tipContent.innerHTML = '<p style="text-align: center;"><br />Erreur lors du transfert des informations distantes.<br /></p>';
					},
					evalScripts: true
				} );
			}
			Element.show(this.container);
			Element.show(element.tipContent);
			if ( this.options.fixToParent ) this._parent_positioning( element );
			else this._position_container( mouseX, mouseY );
		}
		element.tipState = 'on';
		if ( this.options.mouseOverTips ) {
			this.currentTipsParent = element;
		}
	},

	hide_tips: function(element) {
		if ( this.options.mode == 'title' ) {
			this.container.innerHTML = '';
		} else {
			Element.hide(element.tipContent);
		}
		Element.hide(this.container);
		element.tipState = 'off';
		if ( this.options.mouseOverTips ) {
			this.currentTipsParent = false;
		}
  },

	_tipsMOut: function() {
		var _hideTips = this.hide_tips.bind( this );
		var _ctp = this.currentTipsParent;
		this.hideTimeout = setTimeout( function() { _hideTips(_ctp); }, (this.options.hideDelay * 1000) );
	},

	_mouse_positioning: function(event) {
		var mouseX = Event.pointerX(event);
		var mouseY = Event.pointerY(event);
		this._position_container( mouseX, mouseY );
	},

	_parent_positioning: function(element) {
		var coord = Position.cumulativeOffset(element);
		var posX = coord[0];
		var posY = coord[1];
		if ( this.options.fixTPMode != 'TL') {
			if ( this.options.fixTPMode == 'TR' || this.options.fixTPMode == 'BR') posX += element.offsetWidth;
			if ( this.options.fixTPMode == 'BL' || this.options.fixTPMode == 'BR' ) posY += element.offsetHeight;
		}
		this._position_container( posX, posY );
	},

	_position_container: function( X, Y) {
		this.container.style.visibility = 'hidden';
		if ( this.options.fixX ) {
			this.container.style.left = this.options.fixX;
		} else {
			var farX = X + this.container.offsetWidth + this.options.ecartX;
			var limitX = (document.documentElement.scrollLeft || document.body.scrollLeft || 0) + (window.innerWidth || screen.availWidth) - 25;
			var xOverlap = limitX - this.container.offsetWidth;
			if (farX > limitX ) this.container.style.left = xOverlap + 'px';
			else this.container.style.left = (X + this.options.ecartX) + 'px';
		}
		if ( this.options.fixY ) {
			this.container.style.top = this.options.fixY;
		} else {
			var farY = Y + this.container.offsetHeight + this.options.ecartY;
			var limitY = (document.documentElement.scrollTop || document.body.scrollTop || 0) + (window.innerHeight || (screen.availHeight-window.screenTop)) -10;
			var yOverlap = limitY - this.container.offsetHeight;
			if (farY > limitY ) this.container.style.top = yOverlap + 'px';
			else this.container.style.top = (Y + this.options.ecartY) + 'px';
		}
		this.container.style.visibility = '';
	},

	_set_links_and_tooltips: function() {
		if ( this.options.mode == 'title' ) {
			var allLinks = document.getElementsByTagName( 'a' );
			var linkCpt = 0;
			for ( var cpt = 0; cpt < allLinks.length; cpt++ ) {
				if ( allLinks[cpt].title != '' ) {
					this.elements[linkCpt] = allLinks[cpt];
					this.elements[linkCpt].tipContent = allLinks[cpt].title;
					allLinks[cpt].title = '';
					this.elements[linkCpt].tipState = 'off';
					Event.observe( allLinks[cpt], this.options.showOn, this.mOver.bindAsEventListener(this) );
					Event.observe( allLinks[cpt], this.options.hideOn, this.mOut.bindAsEventListener(this) );
					linkCpt++;
				}
			}
		} else {
			var allLinks = new Array();
			var allTips = $$('.'+this.options.mode);
			for ( var cpt = 0; cpt < allTips.length; cpt++ ) {
			}
			for ( var cpt = 0; cpt < allTips.length; cpt++ ) {
				this.container.appendChild(allTips[cpt]);
				// détermine le parent du tip
				if ( this.options.hookToID ) {
					// l'id du tip doit être de la forme : help_idElementToHook
					var parent = $(allTips[cpt].id.substring(5, allTips[cpt].id.length));
				} else {
          parent = allTips[cpt].parentNode;
				}
				// ajouter une image pour afficher le tip ?
				if ( this.options.useHelpButton ) {
					// ajoute et positionne bouton image
					var helpImg = Builder.node( 'img', {className: 'tipHelpImg', src: this.options.pathToImgs + 'help.png', style: 'position: relative;'} );
					if ( parent.tagName.toLowerCase() == 'input' || parent.tagName.toLowerCase() == 'textarea' || parent.tagName.toLowerCase() == 'select' ) {
						parent.parentNode.appendChild(helpImg);
					} else parent.appendChild(helpImg);
					var posX = this.options.hbEcartX;
					var posY = this.options.hbEcartY;
					helpImg.style.left = posX + 'px';
					helpImg.style.top = posY + 'px';
					// parent devient bouton image
					parent = helpImg;
				}
				if ( this.options.mouseOverTips ) {
					Event.observe( allTips[cpt], "mouseover", this._cancel_hidding.bind(this), false );
					Event.observe( allTips[cpt], "mouseout", this._tipsMOut.bind(this), false );
				}
				this.elements[cpt] = parent;
				this.elements[cpt].tipContent = allTips[cpt];
				Element.hide(allTips[cpt]);
				if ( this.options.getRemoteContent ) {
					this.elements[cpt].url = this.elements[cpt].tipContent.innerHTML;
					this.elements[cpt].tipContent.innerHTML = 'Chargement&nbsp;...';
					var tipContent = this.elements[cpt].tipContent;
					var myAjax = new Ajax.Updater( {
						success: this.elements[cpt].tipContent.id
					}, this.elements[cpt].url, {
						method: 'get',
						parameters: '',
						onFailure: function(request) {
							tipContent.innerHTML = '<p style="text-align: center;"><br />Erreur lors du transfert des informations distantes.<br /></p>';
						},
						evalScripts: true
					} );
				}
				this.elements[cpt].tipContent.style.position = 'relative';
				this.elements[cpt].tipState = 'off';
				Event.observe( parent, "mouseover", this.mOver.bindAsEventListener(this) );
				Event.observe( parent, "mouseout", this.mOut.bindAsEventListener(this) );
			}
		}
	},

	_cancel_hidding: function() {
		if ( this.hideTimeout ) clearTimeout( this.hideTimeout );
	},

	_cancel_rising: function() {
		if ( this.riseTimeout ) clearTimeout( this.riseTimeout );
	}

}

