/* version 1.2 */
	var ModalBox = Class.create({
							  
		initialize : function(src){ // src parameter : url or dom element
			
			/* known datas */
				
				this.src = src;
				this.window	= (window.event) ? document.body : window; // IE Hack
				this.isModernBrowser = Prototype.Browser.IE8 || Prototype.Browser.Opera || Prototype.Browser.Gecko;
				
				if (typeof this.src == 'undefined') {
					// trace('Modal box message : no datas !', {method : 'warn'});
				} else {
				
				/* default values */
				
					this.useBackgroundMask 		= true; 			// is there a mask hidding page content when modalbox is opened ? true by default
					this.isDraggable 			= false; 			// is modal box draggable ? false by default /!\ when draggable, scrolling and resizing won't re-calculate position
					this.modalBoxClassName		= 'modalbox';		// modal box css class name and id prefix
					this.backgroundMaskClassName= 'backgroundMask';	// background mask css class name and id prefix
					this.hiddenClassName 		= 'elsewhere';		// hidding dom object css classname (elsewhere actually places elements outside browser to allow size computation
					this.effectsDuration 		= 0.2;				// show/hide period
					this.backgroundMaskOpacity	= '0.4';			// max background mask opacity (0 to 1)
					this.showEffect				= 'Appear';			// default showing effect
					this.hideEffect				= 'Fade';			// default hiding effect
					this.delayedCloseDelay		= 1;				// default delayed closure
					this.errorMessage			= 'Sorry, something went wrong :( Please try again.'; // default  error message
					this.params					= {};				// default xhr request parameters
					this.method					= 'put';			// default config
																				 
				/* default callbacks */
				
					this.xhrStart	= function(){};
					this.xhrEnd		= function(){};
					
				
				/* implementation and status variable */
				
					if (typeof this.src == 'object') {
						this.srcType = 'domElement';
						this.content = $(this.src);
					} else if (typeof this.src == 'string') {
						this.srcType = 'url';
					} else {return false};
					
					this.uid = parseInt(Math.random(new Date().getTime(), 10) * 10000);
					// trace('Modal box object called | source type : ' + this.srcType + ' | uid : ' + this.uid);
					
					this.isCreated = false;
					this.isVisible = false;
					
					this.finalCoordinates = {};
					this.finalCoordinates.left = 0;
					this.finalCoordinates.top = 0;
					
					
				/* default values and callbacks overwritings */
				
					if(arguments[1]){
					
						this.options = arguments[1];
						
						if (this.options.effectsDuration) this.effectsDuration 					= this.options.effectsDuration;
						if (this.options.modalBoxClassName) this.modalBoxClassName 				= this.options.modalBoxClassName;
						if (this.options.backgroundMaskClassName) this.backgroundMaskClassName 	= this.options.backgroundMaskClassName;
						if (this.options.hiddenClassName) this.hiddenClassName 					= this.options.hiddenClassName;
						if (this.options.useBackgroundMask) this.useBackgroundMask 				= (this.options.useBackgroundMask === 'false') ? false : true;
						if (this.options.backgroundMaskOpacity) this.backgroundMaskOpacity 		= this.options.backgroundMaskOpacity;
						if (this.options.showEffect) this.showEffect 							= this.options.showEffect;
						if (this.options.hideEffect) this.hideEffect 							= this.options.hideEffect;
						if (this.options.delayedCloseDelay) this.delayedCloseDelay 				= this.options.delayedCloseDelay;
						if (this.options.errorMessage) this.errorMessage 						= this.options.errorMessage;
						if (this.options.params) this.params 									= this.options.params;
						if (this.options.method) this.method 									= this.options.method;
						
						if (this.options.xhrStart) this.xhrStart 								= this.options.xhrStart;
						if (this.options.xhrEnd) this.xhrEnd 									= this.options.xhrEnd;
						
						if (this.options.isDraggable) this.isDraggable 							= (this.options.isDraggable === 'false') ? false : true;
					
					}
					
				
				/* events observers functions (implementation) */
				
					this.setPositionsFunc	= function(){
						if (!this.isDraggable) this.setFinalPosition();
						this.setBackgroundMaskFinalPosition();
					}.bindAsEventListener(this);
					this.closeFunc				= this.close.bindAsEventListener(this);
					this.hideFunc				= this.hide.bindAsEventListener(this);
					this.refreshFunc			= this.refresh.bindAsEventListener(this);
					this.keyPressFunc 			= function(e){
						var code;
						if (!e) var e = window.event;
						if (e.keyCode) code = e.keyCode;
						else if (e.which) code = e.which; // browsers hacks
						switch(code) {
							case Event.KEY_ESC 	: this.hide(); /*trace('"escape" key pressed -> hide box');*/ break;
						};
					}.bindAsEventListener(this);
				
				}
				
		},
		
		create : function(){
			
			var afterFinish = function(){};
			if(arguments[0]){
				var options = arguments[0];
				if (options.afterFinish) afterFinish = options.afterFinish;
			}
			
			/* background mask creation if wanted (see options) */
				if(this.useBackgroundMask) {
					var backgroundMask = Builder.node('div', { className : this.backgroundMaskClassName + ' ' + this.hiddenClassName, id : this.backgroundMaskClassName + this.uid });
					document.body.appendChild(backgroundMask);
					this.backgroundMask = backgroundMask;
				}
			
			/* dom canvas creation */
				var box = Builder.node('div', { className : this.modalBoxClassName + ' '+this.hiddenClassName, id : this.modalBoxClassName + this.uid });
				document.body.appendChild(box);
				this.box = box;
				if (this.isDraggable) new Draggable(this.box);
			
			/* update content */
			
				/* if background mask, show it */
				if(this.useBackgroundMask) {
					this.setBackgroundMaskFinalPosition();
					this.cssShow(this.backgroundMask, {opacity: this.backgroundMaskOpacity});
				}
				
				/* errors while ajax request behavior */
				var showError = function(){
					this.box.update('<p class="error">' + this.errorMessage + '</p>');
					this.delayedClose();
				}.bind(this);
				
				/* ajax or dom request */
				if (this.srcType == 'url') {
					new Ajax.Updater({success : this.box}, this.src, {
						evalScripts		: true,
						evalJS			: true,
						parameters		: this.params,
						method			: this.method,
						onCreate		: function(){this.xhrStart();}.bind(this),
						onException		: function(){/*trace('Oooops ! xhr failed :(', {method :'warn'});*/ showError();}.bind(this),
						onFailure		: function(){/*trace('Argh, bad xhr response code :(', {method :'warn'});*/ showError();}.bind(this),
						onComplete		: function(){afterFinish(); this.xhrEnd();}.bind(this)
					});
				} else {
					if (this.content) {
						this.box.update($(this.content));
						afterFinish();
					}
				}
			
			/* ok it's done */
				this.isCreated = true;
				// trace('Modal box is Created - id : ' + this.box.id);
			
		},
		
		setBehaviors : function(commut){
			
			var isCommutOn = (commut == 'on') ? true : false;
			
			/* default box close handlers  */
			this.closers = this.box.select('.close');
			for (var index = 0, len = this.closers.length; index < len; ++index) {
				var f = function(){
					var closer = this.closers[index];
					(isCommutOn) ? closer.observe('click', this.closeFunc) : closer.stopObserving('click', this.closeFunc);
				}.bind(this); f();
			}
			
			/* default box hide handlers  */
			this.hiders = this.box.select('.hide');
			for (var index = 0, len = this.hiders.length; index < len; ++index) {
				var f = function(){
					var hider = this.hiders[index];
					(isCommutOn) ? hider.observe('click', this.hideFunc) : hider.stopObserving('click', this.hideFunc);
				}.bind(this); f();
			}
			
			/* default box refresh handlers  */
			this.refreshers = this.box.select('.refresh');
			for (var index = 0, len = this.refreshers.length; index < len; ++index) {
				var f = function(){
					var refresher = this.refreshers[index];
					(isCommutOn) ? refresher.observe('click', this.refreshFunc) : refresher.stopObserving('click', this.refreshFunc);
				}.bind(this); f();
			}
			
			/* re-compute box position if window resize event */
			(isCommutOn) ? Event.observe(this.window, 'resize', this.setPositionsFunc) : Event.stopObserving(this.window, 'resize', this.setPositionsFunc);
			
			/* re-compute box position if window scroll event */
			(isCommutOn && !this.isModernBrowser) ? Event.observe(this.window, 'scroll', this.setPositionsFunc) : Event.stopObserving(this.window, 'scroll', this.setPositionsFunc);
			
			/* hides modal box if esc pressed */
			(isCommutOn) ? Event.observe(document, 'keypress', this.keyPressFunc) : Event.stopObserving(document, 'keypress', this.keyPressFunc);
			
			// trace((isCommutOn) ? 'Modal box behaviors initialized' : 'Modal box behaviors uninitialized');
			
		},
		
		show : function(){
			if (this.src){
				var thenDoYourJob = function(){
					this.setBehaviors('on');
					this.setFinalPosition();
					this.cssShow(this.box, {
						effect : this.showEffect,
						afterFinish : function(){
							this.isVisible = true;
						//	trace('modal box visible');
						}.bind(this)
					})
				}.bind(this);
				if (!this.isCreated) {
					this.create({afterFinish : thenDoYourJob});
				} else {
					if(this.useBackgroundMask) {
						this.setBackgroundMaskFinalPosition();
						this.cssShow(this.backgroundMask, {opacity: this.backgroundMaskOpacity});
					}
					thenDoYourJob.call();
				}
			} // if datas
		},
		
		hide : function(){
			if(this.box && this.isVisible){
				this.cssHide(this.box, {
					effect : this.hideEffect,
					afterFinish : function(){
						this.isVisible = false;
						// trace('modal box not visible');
						this.setBehaviors('off');
					}.bind(this)
				});
				if(this.useBackgroundMask) this.cssHide(this.backgroundMask);
			}
		},
		
		close : function(){
			if(this.box && this.isVisible){
				var thenDoTheStuff = function(){
					// trace('Adios ModalBox' + this.uid + ' !');
					this.isCreated = false;
					this.isVisible = false;
					this.box.remove();
				}.bind(this);
				this.cssHide(this.box, {
					afterFinish : thenDoTheStuff,
					effect : this.hideEffect
				});
				if (this.useBackgroundMask) {
					this.cssHide(this.backgroundMask, {
						afterFinish : function(){this.backgroundMask.remove();}.bind(this)
					});
				}
			}
		},
		
		delayedClose : function(){
			if (arguments[0]) this.delayedCloseDelay = arguments[0];
			var delayedCloser = function(){
				if(this.box && this.isVisible)this.close();
			}.bind(this);
			delayedCloser.delay(this.delayedCloseDelay);
		},
		
		refresh : function(){
			if (this.backgroundMask) this.useBackgroundMask = false; // if background mask used, not touched 
			this.isCreated = false;
			this.box.remove();
			this.show();
			if (this.backgroundMask) this.useBackgroundMask = true; // if background mask used, touched back
		},
		
		cssShow : function(elt){
			
			var afterFinish = function(){};
			var opacity 	= '1';
			var effect		= 'Appear';
			
			if(arguments[1]){
				var options = arguments[1];
				if (options.afterFinish) afterFinish 	= options.afterFinish;
				if (options.opacity) opacity		 	= options.opacity;
				if (options.effect) effect				= options.effect;
			}
			
			elt.setStyle({opacity : 0});
			elt.removeClassName(this.hiddenClassName);
			Effect[effect](elt, {
				to			:  opacity,
				duration	: this.effectsDuration,
				afterFinish : afterFinish
			});
			
		},
		
		cssHide : function(elt){
			
			var afterFinish = function(){};
			var effect 		= 'Fade';
			
			if(arguments[1]){
				var options = arguments[1];
				if (options.afterFinish) afterFinish = options.afterFinish;
				if (options.effect) effect = options.effect;
			}
			
			Effect[effect](elt, {
				duration : this.effectsDuration,
				afterFinish : function(){
					elt.addClassName(this.hiddenClassName).writeAttribute('style', '');
					afterFinish();
				}.bind(this)
			});
			
		},
		
		setFinalPosition : function(){
			
			this.updateFinalPositionCoordinates();
			var finalBoxStyle 	= {
				left 		: this.finalCoordinates.left + 'px',
				top 		: this.finalCoordinates.top + 'px',
				index 		: '1000',
				position 	: this.isModernBrowser ? 'fixed' : 'absolute' 
			};
			// trace (this.finalCoordinates);
			this.box.setStyle(finalBoxStyle);
			
		},
		
		setBackgroundMaskFinalPosition : function(){
			
			if(this.useBackgroundMask) {
				var finalBackgroundStyle = {
					top			: this.isModernBrowser ? '0' : this.getWindowScroll() + 'px',
					position 	: this.isModernBrowser ? 'fixed' : 'absolute'
				};
				this.backgroundMask.setStyle(finalBackgroundStyle);
			}
		},
		
		updateFinalPositionCoordinates : function(){
			
			var boxDim 			= this.getBoxDimensions();
			var windowDim 		= this.getWindowDimensions();
			
			this.finalCoordinates.left 	= parseInt( ((windowDim.width - boxDim.width)/2), 10);
			this.finalCoordinates.top 	= parseInt( ((windowDim.height - boxDim.height)/2 + this.getWindowScroll()), 10);
			
		},
		
		getBoxDimensions : function(){
			
			var boxDimensions		= this.box.getDimensions();
			
			// trace('box dimensions : ' + boxDimensions.width + 'px x ' + boxDimensions.height + 'px');
			return boxDimensions;
			
		},
		
		getWindowDimensions : function() { // returns array containing width and height in pixels
			
			var windowDimensions = {};
			var w = this.window;
			
			windowDimensions.width = w.innerWidth || document.documentElement.clientWidth || w.clientWidth;
			windowDimensions.height = w.innerHeight || document.documentElement.clientHeight || w.clientHeight;
			
			// trace('window dimensions : ' + windowDimensions.width + 'px x ' + windowDimensions.height + 'px');
			return windowDimensions;
			
		},
		
		getWindowScroll : function() { // returns value in pixels of scrolling offset
			
			var windowScroll;
			if( typeof( window.pageYOffset ) == 'number' ) {//Netscape compliant
				windowScroll = window.pageYOffset;
			} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {//DOM compliant
				windowScroll = document.body.scrollTop;
			} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {//IE6 standards compliant mode
				windowScroll = document.documentElement.scrollTop;
			};
			
			// trace('window scroll : ' + windowScroll + 'px');
			return windowScroll ? windowScroll : 0;
			
		}
		
	});;
/*
 * Script spécifique développé en interne pour afficher des box en surimpression sur une page
 */
var PopupBox = Class.create();
PopupBox.prototype = {

	box: 		null,
	winDim: 	null,
	backHTML: 	"<div id='backPopup' class='fixedBox' style='display:none;'>&nbsp;</div>",
	backPopup:	null,
	bindedPositionFunc: null,
	bindedEscapeFunc: null,
	durationBack: 0.5,
	durationBox: 1.0,
	queueParams: { position: 'end', scope: 'popupBox' },
	
	initialize: function(box) {
		if (!box) return;
		this.box = $(box);
		this.appendBack();
		this.appendBox();
		this.positionElements();
		this.appearElements();
		this.bindedPositionFunc = this.positionElements.bind(this);
		this.bindedEscapeFunc = this.escapeHandler.bind(this);
		
		Event.observe(window, "resize", this.bindedPositionFunc);
		Event.observe(document, "keypress", this.bindedEscapeFunc);
		
	},
	
	// Apparition des éléments
	appearElements: function() {
		this.appearBack();
		this.appearBox();
	},
	// Apparition du fond
	appearBack: function() {
		new Effect.Appear(this.backPopup, {from: 0.0, to: 0.5, duration: this.durationBack, queue: this.queueParams });
	},
	// Apparition de la box
	appearBox: function() {
		this.hideSelectBoxes();
		new Effect.Appear(this.box, {duration: this.durationBox, queue: this.queueParams });
	},
	// Fermeture de la box
	close: function() {
		if (this.box) this.box.remove();
		if (this.backPopup) this.backPopup.remove();
		if (this.loading) this.loading.remove();
		Event.stopObserving(window, "resize", this.bindedPositionFunc);
		Event.stopObserving(document, "keypress", this.bindedEscapeFunc);
		this.showSelectBoxes();
	},
	// Fondu avant fermeture
	fade: function() {
		var that = this;
		var effectList = [];
		if (this.box) effectList.push(new Effect.Fade(this.box,{sync:true}));
		if (this.backPopup) effectList.push(new Effect.Fade(this.backPopup,{sync:true}));
		new Effect.Parallel(effectList, {duration: 1.0, delay: 2.0, afterFinish: function() {that.close()} });
	},
	// Insertion du fond dans le DOM
	appendBack: function() {
		new Insertion.Bottom(document.body, this.backHTML);
		this.backPopup = $("backPopup");	
	},
	// Insertion de la box dans le DOM
	appendBox: function() {
		document.body.appendChild(this.box);
	},
	// Positionnement du fond
	positionBack: function(isReset) {
		if (!this.winDim || isReset) this.winDim = this.getWindowDim();
		this.backPopup.setStyle({
			width: this.winDim[0] + "px",
			height: this.winDim[1] + "px"
		});		
	},
	// Positionnement de la box
	positionBox: function(isReset) {
		if (!this.winDim || isReset) this.winDim = this.getWindowDim();
		this.box.addClassName('fixedBox');
		this.box.setStyle({
			zIndex: 20,
			left: Math.floor( (this.winDim[0]-this.box.getWidth()) / 2) + "px",
			top: Math.floor( (this.winDim[1]-this.box.getHeight()) / 2) + "px"
		});
	},
	// Positionnement du spinner
	positionLoading: function(isReset) {
		if (this.isAjax) {
			if (!this.winDim || isReset) this.winDim = this.getWindowDim();
			this.loading.addClassName('fixedBox');
			this.loading.setStyle({
				zIndex: 30,
				left: Math.floor( (this.winDim[0]-this.loading.getWidth()) / 2) + "px",
				top: Math.floor( (this.winDim[1]-this.loading.getHeight()) / 2) + "px"
			});
		}
	},
	// Positionnement des éléments
	positionElements: function() {
		this.positionBack(true);
		this.positionLoading(false);
		this.positionBox(false);
	},
	// récupère les dimensions de la fenêtre du navigateur
	getWindowDim: function() { 
		var width 	= 0;
		var height 	= 0;
		if ( typeof(window.innerWidth) == 'number' ) {
			//Non-IE
			width 	= window.innerWidth;
			height 	= window.innerHeight;
		} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
			//IE 6+ in 'standards compliant mode'
			width 	= document.documentElement.clientWidth;
			height 	= document.documentElement.clientHeight;
		} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
			//IE 4 compatible
			width 	= document.body.clientWidth;
			height 	= document.body.clientHeight;
		};
		return [width, height];
	},
	
	// cache toutes les drop-boxes de la page (débug spécifique à IE6) + scroll vers le haut (pas de css fixed chez IE6)
	hideSelectBoxes: function() {
		var isIE6 = false /*@cc_on || @_jscript_version <= 5.7 @*/;
		if (isIE6) {
			$$('select').invoke("setStyle",{visibility: "hidden"});
			if (window.XMLHttpRequest) {
			} else {
				new Effect.ScrollTo('session');
			}
		}
	},
	
	// affiche toutes les drop-boxes de la page (débug spécifique à IE6)
	showSelectBoxes: function() {
		var isIE6 = false /*@cc_on || @_jscript_version <= 5.7 @*/;
		if (isIE6) $$('select').invoke("setStyle",{visibility: "visible"});
	},
	
	// scrolling vers le haut pour cadrer les éléments positionnés en absolu (auto-complétion notamment)
	scrollTop: function(){
		//Effect.ScrollTo('session', {duration:0.3}); // incompatibilité versions scriptaculous
	},
	
	escapeHandler: function(event) { 
		if (Event.KEY_ESC == event.keyCode) {
			var boxForm = this.box.down("form");
			if (boxForm) {
				boxForm.reset();
				// Si la box contient un form, on fait d'abord un reset du form et on attend un peu pour
				// laisser les éventuels contrôles js du form se faire avant de le supprimer du DOM
				// => Evite certains effets indésirable, comme la non-disparition des suggestions dans un autocompleter...
				window.setTimeout(this.close.bind(this),200);
			} else {
				this.close();
			}
		}
	}
	
};

/*
 * Descendant de PopupBox spcialisé pour afficher un contenu AJAX
 */
var AjaxPopupBox = Class.create();
AjaxPopupBox.prototype = Object.extend(new PopupBox(), {
  
  isAjax: true,
  url: null,
  form: null,
  durationBack: 0.3,
  durationBox: 0.3,
  xhrOnAir: false, // real-time XHR status (true/false), default false
	  
  initialize: function(url,params, jsFunction) {
	var that = this;
	this.createDiv("AjaxPopupBox");
	this.box = $("AjaxPopupBox");
	this.createDiv("AjaxPopupLoading");
	this.loading = $("AjaxPopupLoading");
	this.url = url;
	this.jsFunc = jsFunction;
	
	this.appendBack();
	this.positionBack();
	this.positionLoading();
	this.appearBack();
	this.scrollTop();
	
	this.bindedPositionFunc = this.positionElements.bind(this);
	this.bindedEscapeFunc = this.escapeHandler.bind(this);
	
	Event.observe(window, "resize", this.bindedPositionFunc);
	Event.observe(document, "keypress", this.bindedEscapeFunc);
	
	this.update(this.url,{
		method: "get",
		parameters: params,
		onComplete: function(response) {
			if (response.status == 200) {
				that.appendBox();
				that.appearBox();
			} else {
				that.close();
			}
		}
	});
  },
  
  // Création d'une div avec un id spécifié
  createDiv: function(id) {
  	var div = document.createElement("div");
  	div.id = id;
  	div.style.display = "none";
  	document.body.appendChild(div);
  },
  
  // Requête et mise à jour de la box
  update: function(url,params,isSubmit) {
  	var that = this;
  	var params 	= params || {};
  	var url 	= url || this.url;
  	var requestParams = params.parameters || (isSubmit ? Form.serialize(that.form,true) : {});
  	
  	// Ajout d'un paramètre pour forcer l'interprétation de la requête en UTF-8
  	requestParams["form-encoding"] = "UTF-8";
  	
  	this.loading.show();
  	
  	if(!this.xhrOnAir) new Ajax.Updater("AjaxPopupBox",url,{
  		method: 		params.method 		|| "post",
  		parameters: 	requestParams,
  		evalScripts:	true, // Les balises script sont interprétés dans la réponse
  		
  		onCreate: function(){that.xhrOnAir = true;},
  		
  		onSuccess: function(response) {	if (params.onSuccess) params.onSuccess(response); that.xhrOnAir = false; },
  		onFailure: function(response) { if (params.onFailure) params.onFailure(response); that.close(); that.xhrOnAir = false; },
  		
  		onComplete: function(response) { 
			if (params.onComplete) params.onComplete(response);
  			that.loading.hide();
			that.positionBox();
  			that.form = that.box.down("form");
			if (that.form) that.form.onsubmit = that.submit.bind(that, 'submit', that.form.getAttribute("action"));
			that.xhrOnAir = false;
  		}
  		
  	});
  },
  
  // Simule un submit classique, mais en restant dans la box Ajax
  submit: function(event,url,params) {
  	if (!checkForms(16000)) return false;
  	this.update(url,params,true);
  	return false; // bloque le submit standard
  }
});;


	var NotificationsManager = Class.create({
	
	  initialize: function(item){
	  	
	  	this.item = item;
	  	this.hoverClassName = 'hover';
	  	
	  	this.item.observe('mouseover', this.setMouseOver.bind(this));
	  	this.item.observe('mouseout', this.setMouseOut.bind(this));
	  	
	  },
	  
	  setMouseOver	: function(){ this.item.addClassName(this.hoverClassName); },
	  setMouseOut	: function(){ this.item.removeClassName(this.hoverClassName); }
	  
	});;


	var DomElementsController = Class.create({
	
	  initialize: function(handler, target) {
	  
		this.handler  			= $(handler);
		this.target 			= $(target);
		this.uid				= parseInt(Math.random(new Date().getTime(), 10) * 10000);
		this.window				= (window.event) ? document.body : window; // IE Hack
		
		// default state
		this.target.isOpen 		= false;
		
		// default parameters
		this.eventChoice 		= 'mouseover';
		this.toggleClassName 	= 'hidden';
		this.targetClassName 	= 'targetsubmenu';
		this.targetZIndex		= 10;
		this.targetStyle		= false;
		this.targetAlign		= false;
		this.effectDuration		= 0.2;
		
		// callbacks functions
		this.afterCreate 		= function(){};
		this.afterOpen 			= function(){};
		this.afterClose 		= function(){};
		
		
		// options ?
		if(arguments[2]) {
			this.options = arguments[2];
			
			// parameters
			if(this.options.event)				this.eventChoice 		= this.options.event;				// string
			if(this.options.toggleClassName) 	this.toggleClassName 	= this.options.toggleClassName;		// string
			if(this.options.targetClassName) 	this.targetClassName 	= this.options.targetClassName;		// string
			if(this.options.targetZIndex) 		this.targetZIndex 		= this.options.targetZIndex;		// number
			if(this.options.targetStyle) 		this.targetStyle 		= this.options.targetStyle;			// {} -> no style
			if(this.options.targetAlign) 		this.targetAlign 		= this.options.targetAlign;			// right / middle /left
			if(this.options.effectDuration) 	this.effectDuration		= this.options.effectDuration;		// time in second
			
			
			// callbacks
			if(this.options.afterCreate) 		this.afterCreate 		= this.options.afterCreate;
			if(this.options.afterOpen) 			this.afterOpen 			= this.options.afterOpen;
			if(this.options.afterClose) 		this.afterClose 		= this.options.afterClose;
		}
		
		// link both element with same class name
		this.handler.addClassName(this.uid);
		this.target.addClassName(this.uid).addClassName(this.targetClassName);
		
		// move target to the bottom of the dom tree
		document.body.appendChild(this.target);
		
		// set target styles
		this.setTargetDefaultStyle();
		
		// listeners callbacks
		this.opener = this.open.bind(this); 
		this.closer = this.shouldIClose.bind(this); 
		
		// listener initiated
		this.eltListenerSwitcher(this.handler, 'on', this.opener);
		this.afterCreate();
		
	  },
   
	  open: function() {
		this.target.setStyle({'opacity' : 0});
		this.target.removeClassName(this.toggleClassName);
		this.eltListenerSwitcher(this.handler, 'off', this.opener);
		this.eltListenerSwitcher(this.window, 'on', this.closer);
		this.afterOpenFinished = function(){this.target.isOpen = true; this.afterOpen();};
		this.target.appear({duration: this.effectDuration, afterFinish: this.afterOpenFinished.bind(this)});
	  },
	  
	  close: function() {
		this.target.addClassName(this.toggleClassName);
		this.eltListenerSwitcher(this.handler, 'on', this.opener);
		this.eltListenerSwitcher(this.window, 'off', this.closer);
		this.target.isOpen = false;
		this.afterClose();
	  },
	  
	  shouldIClose: function(event){
	  	var element = Event.element(event);
		if (this.eventChoice == 'click') { // when click event chosen, handler does toggle target
			if ( (element === this.handler) && this.target.isOpen || !element.hasClassName(this.uid) ) this.close();
		} else {
			if( !(element.hasClassName(this.uid) || element.up('.' + this.uid)) ) this.close();
		}
	  },
	  
	  eltListenerSwitcher : function(element, choice, callback){
	  	if('off' == choice) {
			Event.stopObserving(element, this.eventChoice, callback);
		} else {
			Event.observe(element, this.eventChoice, callback);
		}
	  },
	  
	  setTargetDefaultStyle: function(){
	  
	  	if (this.targetStyle) {
		
			this.target.stylecss = this.targetStyle;
			
		} else {
		
			this.handler.position 		= this.handler.cumulativeOffset();
			this.handler.dimensions		= this.handler.getDimensions();
			this.target.position 		= this.target.cumulativeOffset();
			this.target.dimensions		= this.target.getDimensions();
			
			
			this.target.borderLeftWidth 	= parseInt( this.target.getStyle('border-left-width') ) 	|| false;
			this.target.borderRightWidth 	= parseInt( this.target.getStyle('border-right-width') )	|| false;
			this.target.borderTopWidth 		= parseInt( this.target.getStyle('border-top-width') )	|| false;
			this.target.borderBottomWidth 	= parseInt( this.target.getStyle('border-bottom-width') )	|| false;
			
			if ( this.target.borderLeftWidth && this.target.borderRightWidth && this.target.borderTopWidth && this.target.borderBottomWidth ){
				this.handler.dimensions.width += parseInt( this.target.getStyle('border-left-width') ) + parseInt( this.target.getStyle('border-right-width') );
				this.handler.dimensions.height += parseInt( this.target.getStyle('border-top-width') ) + parseInt( this.target.getStyle('border-bottom-width') );
			}
			
			var position	= 'absolute';
			
			if(this.targetAlign == 'right') {
				var left = parseInt(this.handler.position.left + this.handler.dimensions.width - this.target.dimensions.width) + 'px';
			} else if (this.targetAlign == 'middle'){
				var left = parseInt( this.handler.position.left - (this.target.dimensions.width - this.handler.dimensions.width)/2 ) + 'px';
			} else {
				var left = this.handler.position.left + 'px';
			}
			
			var top			= parseInt(this.handler.position.top + this.handler.dimensions.height) + 'px';
			var zIndex		= this.targetZIndex;

			this.target.stylecss = {
				'position'	: position,
				'left'		: left,
				'top'		: top,
				'z-index'	: zIndex
			};
		
	  	}
		
		this.target.setStyle( this.target.stylecss );
		
	  }
	  
	});;
