var Overlay = function (className, properties) {
	// Caratteristiche overlay	
	this.id = className + Math.floor(Math.random() * 100);
	this.YUIoverlay = new YAHOO.widget.Panel(this.id, properties);
	
	// Stabilisce per quanto tempo resta visibile la finestra prima di essere chiusa
	this.visibleFor = 0;
	
	// Timeout apertura/chiusura
	this.showTimeout = null;
	this.hideTimeout = null;

	// Effetti
	this.showEffect = null;
	this.hideEffect = null;
	
	// Ancoraggio
	this.corner = {	overlay: null,
					context: null };
	
	// Chiamata Ajax
	this.scriptUrl = "";
	
	// Metodo di connessione
	this.connectionMethod = 'POST';
	
	// Identifica un overlay a più passi
	this.stepOverlay = false;
	
	// Se true nasconde il terzo passo della finestra
	this.hideAfterLoad = false;
	
	// Se true vengono visualizzati i messaggi di errore
	this.debugMode = false;
	
	// Contenuto della finestra per il loading
	this.loaderContent = {	header: '',
							body: '<div id="oLoader" class="loader"></div>',
							footer: ''
	};
	
	// Colore overlay da prendere al momento
	this.color = 'blu';
	
	// Colore di default overlay
	this.defaultColor = 'blu';
	
	// Colore overlay di errore
	this.errorColor = 'rosso';
	
	// Messaggio di errore generico
	this.defaultErrorMessage = 'Oops! Qualcosa è andato storto, riprova più tardi!';
	
	// Stabilisce se si debba o meno centrare l'overlay
	this.center = true;
	
	// Classi css addizionali per l'overlay
	this.cssClasses = new Array(className);
	
	// Centra automaticamente l'overlay alla sostituzione del contenuto del body
	this.YUIoverlay.changeBodyEvent.subscribe(function () {
		this.centerOverlay();
	});
	
	/**
	 * Overlay.addClass
	 * 
	 * Aggiunge una classe css alla lista di classi dell'overlay
	 * 
	 * @param className String nome della classe
	 * @return void
	 */
	this.addClass = function (className) {
		this.cssClasses.push(className);
	};
	
	/**
	 * Overlay._setClasses
	 * 
	 * Imposta per l'overlay le classi css della lista
	 * 
	 * @return void
	 */
	this._setClasses = function () {
		var overlay = YAHOO.util.Dom.get(this.YUIoverlay.id);
		YAHOO.util.Dom.addClass(overlay, className);
		
		for(var i in this.cssClasses)
			YAHOO.util.Dom.addClass(overlay, this.cssClasses[i]);
	};
	
	/**
	 * Overlay.registerTransitions
	 * 
	 * Registra le modalità di apertura e chiusura dell'overlay
	 * 
	 * @return void
	 */
	this.registerTransitions = function (anchorShow, content, anchorHideId) {
		this.registerShow(anchorShow, content, anchorHideId);
		if(this.debugMode) Logger.log("transizioni registrate, l'overlay è agganciato a '" + (anchorShow.id ? anchorShow.id : anchorShow) + "'", 'registerTransitions', 'Overlay', 96);		
	};
	
	/**
	 * Overlay.registerShow
	 * 
	 * Registra le modalità per l'apertura dell'overlay
	 * 
	 * @return void
	 */
	this.registerShow = function (anchor, content, anchorHideId) {
		var me = this;

		YAHOO.util.Event.on(anchor, this.showEffect.on, function() {
			this.showTimeout = window.setTimeout(function () {
				me.show(anchor, content, anchorHideId);
												
			}, me.showEffect.delay * 1000);
			
			if(this.debugMode) Logger.log("scattato evento '" + this.showEffect.on + "' su '" + anchor.id + "'", 'registerShow', 'Overlay', 115);
		});
		
		if(this.debugMode) Logger.log("transizione show registrata per l'oggetto '" + (anchor.id ? anchor.id : anchor) + "'", 'registerShow', 'Overlay', 118);
	};
	
	/**
	 * Overlay.registerHide
	 * 
	 * Registra le modalità per la chiusura dell'overlay
	 * 
	 * @return void
	 */
	this.registerHide = function (anchorID) {
		var me = this;

		// Chiusura temporizzata
		if(this.visibleFor > 0 && !this.stepOverlay)
			this.registerTimedHide();
			
		// Chiusura in seguito ad un evento
		else if(this.hideEffect)
			YAHOO.util.Event.on(YAHOO.util.Dom.get(anchorID), this.hideEffect.on, function() {
				if(this.hideTimeout) clearTimeout(this.hideTimeout);
				this.hideTimeout = window.setTimeout(function () {
					me.hide();
				}, me.hideEffect.delay * 1000);
			});
		
		if(this.debugMode) Logger.log("transizione hide registrata per l'oggetto '" + anchorID + "'", 'registerHide', 'Overlay', 144);
	};

	/**
	 * Overlay.registerTimedHide
	 * 
	 * Registra la chiusura automatica temporizzata
	 * 
	 * @return void
	 */
	this.registerTimedHide = function () {
		var me = this;
		
		if(this.hideTimeout) clearTimeout(this.hideTimeout);
		this.hideTimeout = window.setTimeout(function () {
			me.hide();
		}, me.visibleFor * 1000);
	};
	
	/**
	 * Overlay.show
	 * 
	 * Mostra l'overlay
	 * 
	 * @param anchorShow HTMLElement elemento di ancoraggio per la show
	 * @param content Object { header, body, footer } contenuto dell'overlay
	 * @param fn function funzione da chiamare per impostare un qualche valore di configurazione dell'overlay (opzionale)
	 * @param anchorHideId String id elemento di ancoraggio per la hide
	 * @return void
	 */
	this.show = function (anchorShow, content, anchorHideId, fn) {
		if(content) this.setContent(content.header, content.body, content.footer);
		
		this.YUIoverlay.render(document.body);
		
		if(fn) fn();
		this._setClasses();
		
		if(anchorShow) this.setAnchor(anchorShow);
		this.YUIoverlay.show();
		
		this.registerHide(anchorHideId);
		
		// Centra l'overlay
		if(this.center) this.centerOverlay();
		
		this.color = this.defaultColor;	// Riporta l'overlay al colore di default
		
		if(this.debugMode && anchorShow) Logger.log("overlay ancorato all'oggetto '" + (anchorShow.id ? anchorShow.id : anchorShow) + "' è stato reso visibile", 'show', 'Overlay', 184);
	};
	
	/**
	 * Overlay.centerOverlay
	 * 
	 * Centra l'overlay
	 * 
	 * @return void
	 */
	this.centerOverlay = function () {
		window.scrollTo(0, 1);
		window.scrollTo(0, 0);
	};
	
	/**
	 * Overlay.hide
	 * 
	 * Nasconde l'overlay
	 * 
	 * @return void
	 */
	this.hide = function () {
		this.YUIoverlay.hide();
	};
	
	/**
	 * Overlay.onClose
	 * 
	 * Funzione da eseguire alla chiusura dell'overlay
	 * 
	 * @return void
	 */
	this.onClose = function (fn) {
		this.YUIoverlay.hideEvent.subscribe(fn);
	};
	
	/**
	 * Overlay.onShow
	 * 
	 * Funzione da eseguire all'apertura dell'overlay
	 * 
	 * @return void
	 */
	this.onShow = function (fn) {
		this.YUIoverlay.showEvent.subscribe(fn);
	};
	
	/**
	 * Overlay.setContent
	 * 
	 * Imposta il contenuto dell'overlay, header, body e footer
	 * 
	 * @return void
	 */
	this.setContent = function (header, body, footer) {
		this.YUIoverlay.setHeader(header);
		this.YUIoverlay.setBody(body);
		this.YUIoverlay.setFooter(footer);
		
		if(this.debugMode) Logger.log('contenuto overlay impostato', 'setContent', 'Overlay', 244);
	};
	
	/**
	 * Overlay.setAnchor
	 * 
	 * Imposta la posizione dell'overlay rispetto all'oggetto a cui è ancorato
	 * 
	 * @param anchor String | HTMLElement elemento di ancoraggio
	 * @return void
	 */
	this.setAnchor = function (anchor) {
		this.YUIoverlay.cfg.setProperty("context", [anchor, this.corner.overlay, this.corner.context]);
	};
	
	/**
	 * Overlay.setPosition
	 * 
	 * Imposta la posizione assoluta dell'overlay
	 * 
	 * @param x int ascissa
	 * @param y int ordinata
	 * @return void
	 * @deprecated use setProperty
	 */
	this.setPosition = function (x, y) {
		this.YUIoverlay.cfg.setProperty('xy', [ x, y ]);
	};
	
	/**
	 * Overlay.ajaxCall
	 * 
	 * Wrapper per getContentByAjax
	 * 
	 * @param actionString String url dello script da chiamare
	 * @param anchorShow HTMLElement elemento di ancoraggio per la show
	 * @param anchorHideId String id elemento di ancoraggio per la hide
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param secondStep boolean se true l'overlay si trova al secondo passo (opzionale)
	 * @return void
	 */
	this.ajaxCall = function (actionString, anchorShow, anchorHideId, obj, secondStep) {
		this.getContentByAjax(actionString, anchorShow, anchorHideId, obj, secondStep);
	};
	
	/**
	 * Overlay.getContentByAjax
	 * 
	 * Ottiene il contenuto di un overlay tramite una chiamata AJAX
	 * 
	 * @param actionString String url dello script da chiamare
	 * @param anchorShow HTMLElement elemento di ancoraggio per la show
	 * @param anchorHideId String id elemento di ancoraggio per la hide
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param formName String nome di un'eventuale form da cui estrarre i dati (opzionale)
	 * @param secondStep boolean se true l'overlay si trova al secondo passo (opzionale)
	 * @return void
	 */
	this.getContentByAjax = function (actionString, anchorShow, anchorHideId, obj, formName, secondStep) {
		// this.color = this.defaultColor;
		var me = this;
		
		var callback = {
		    success: function (o) {
				me._manageSuccessContent(o.responseText, anchorShow, anchorHideId, obj, secondStep);				
		    },
		    upload: function (o) { callback.success(o); },
		    failure: function (o) {
		    	obj.overlay.color = obj.overlay.errorColor;
		    	me._manageResult(obj, anchorShow, obj.overlay.defaultErrorMessage, anchorHideId, secondStep);
		    }
		};

		if(formName) YAHOO.util.Connect.setForm(formName, true, true);
		var conn = this._connect(actionString, callback);
		obj.show(null, this.loaderContent.body, null);
	};
	
	/**
	 * Overlay._manageSuccessContent
	 * 
	 * Gestisce la risposta con successo
	 * 
	 * @param responseText json risposta
	 * @param anchorShow HTMLElement elemento di ancoraggio per la show
	 * @param anchorHideId String id elemento di ancoraggio per la hide
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param secondStep boolean se true l'overlay si trova al secondo passo (opzionale)
	 * @return void
	 */
	this._manageSuccessContent = function (responseText, anchorShow, anchorHideId, obj, secondStep) {
		var pResponse = this._parseResult(responseText);
		
		if(Utilities.isArray(pResponse)) {
			this._manageResponse(pResponse[0], obj);
			pResponse = pResponse[1];
		} else if(pResponse.result) {
			this._manageResponse(pResponse, obj);
			if(pResponse.result == 'LP') return;
		}
		
		this._manageResult(obj, anchorShow, pResponse, anchorHideId, secondStep);
	};
	
	/**
	 * Overlay._manageResponse
	 * 
	 * Gestisce la risposta per una chiamata AJAX
	 * 
	 * @param pResponse Object risposta parsata
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @return void
	 */
	this._manageResponse = function (pResponse, obj) {
		if(pResponse.result == 'LP') {
			obj.overlay.hide();
			OverlayManager.show('lp', pResponse.lp, pResponse.enc_profile_id);
		} else if(pResponse.result == 'KO') {
			this.color = this.errorColor;
		}
	};
	
	/**
	 * Overlay._parseResult
	 * 
	 * Wrapper per la funzione di parse della risposta ibrida json + testo
	 * 
	 * @param response misc risposta
	 * @return Object
	 */
	this._parseResult = function (response) {
		return Utilities.parseHybridResponse(response);
	};
	
	/**
	 * Overlay.getResultByAjax
	 * 
	 * Come getContentByAjax ma ottiene una risposta ad un'azione anzichè il contenuto dell'overlay
	 * 
	 * @param actionString String url dello script da chiamare
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param fn function funzione da chiamare per la gestione del risultato
	 * @param formName String nome di un'eventuale form da cui estrarre i dati (opzionale)
	 * @return void
	 */
	this.getResultByAjax = function (actionString, obj, fn, formName) {
		// this.color = this.defaultColor;
		var me = this;
		
		var callback = {
		    success: function (o) {			
				me._manageSuccessResult(o.responseText, obj, fn);				
		    },
		    upload: function (o) { callback.success(o); },
		    failure: function (o) {
		    	obj.overlay.color = obj.overlay.errorColor;
		    	fn(obj, obj.overlay._createErrorStruct(this.defaultErrorMessage));
		    }
		};

		if(formName) YAHOO.util.Connect.setForm(formName, true, true);
		var conn = this._connect(actionString, callback);
		obj.show(null, this.loaderContent.body, null);
	};
	
	/**
	 * Overlay._manageSuccessResult
	 * 
	 * Gestisce la risposta di successo di una chiamata AJAX
	 * 
	 * @param responseText json risposta
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param fn function funzione da chiamare per la gestione del risultato
	 * @return void
	 */
	this._manageSuccessResult = function (responseText, obj, fn) {
		try {
			var response = Utilities.jsonParse(responseText);
					
			if(Utilities.needLP(responseText, true)) {
				obj.overlay.hide();
				Utilities.checkFeature(responseText, true);
			}
			else {
				if(response.result == 'KO') this.color = this.errorColor;
				fn(obj, response);
			}
		} catch (e) {
			obj.overlay.color = obj.overlay.errorColor;
			fn(obj, this._createErrorStruct(this.defaultErrorMessage));
		}
	};
	
	/**
	 * Overlay._createErrorStruct
	 * 
	 * Crea la struttura per l'errore
	 * 
	 * @param errorMessage String desrizione dell'errore
	 * @return Object { result, header, body, footer, params }
	 */
	this._createErrorStruct = function (errorMessage) {
		return {
			result: 'KO',
			header: '',
			body: errorMessage,
			footer: '',
			params: { }
		};
	};
	
	/**
	 * Overlay._connect
	 * 
	 * Esegue la chiamata AJAX
	 * 
	 * @param actionString String url dello script da chiamare
	 * @param callback Object { success, upload, failure } oggetto callback
	 * @return Object oggetto connessione
	 */
	this._connect = function (actionString, callback) {
		return (this.connectionMethod == 'POST') ?
	    		YAHOO.util.Connect.asyncRequest('POST', this.scriptUrl, callback, actionString) :
	    		YAHOO.util.Connect.asyncRequest('GET', this.scriptUrl + "?" + actionString, callback);
	};
	
	/**
	 * Overlay._manageResult
	 * 
	 * Gestisce il risultato ottenuto dalla chiamata
	 * 
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param anchorShow HTMLElement elemento di ancoraggio per la show
	 * @param responseText json risposta
	 * @param anchorHideId String id elemento di ancoraggio per la hide
	 * @param secondStep boolean se true l'overlay si trova al secondo passo (opzionale)
	 * @return void
	 */
	this._manageResult = function (obj, anchorShow, responseText, anchorHideId, secondStep) {
		var text = ''; 
		
		try {
			var json = Utilities.jsonParse(responseText);
			text = json.body;
		}
		catch (e) { text = responseText; }
		
		if(!obj.overlay.hideAfterLoad) obj.show(anchorShow, text, anchorHideId);
		else obj.overlay.overlay.hide();
		
		if(secondStep && !obj.overlay.hideAfterLoad && obj.overlay.visibleFor) { obj.overlay.registerTimedHide(); }
	};
	
	/**
	 * Overlay.stepTwo
	 * 
	 * Wrapper per setContentByAjax che rende le chiamate specifiche per gli overlay nel secondo passo
	 * 
	 * @param actionString String url dello script da chiamare
	 * @param anchorShow HTMLElement elemento di ancoraggio per la show
	 * @param anchorHideId String id elemento di ancoraggio per la hide
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param formName String nome di un'eventuale form da cui estrarre i dati (opzionale)
	 * @return void
	 */
	this.stepTwo = function (actionString, anchorShow, anchorHideId, obj, formName) {
		this.setContentByAjax(actionString, anchorShow, anchorHideId, obj, formName, true);
	};
	
	/**
	 * Overlay.setContentByAjax
	 * 
	 * Imposta il contenuto di un'overlay tramite una chiamata AJAX
	 * 
	 * @param actionString String url dello script da chiamare
	 * @param anchorShow HTMLElement elemento di ancoraggio per la show
	 * @param anchorHideId String id elemento di ancoraggio per la hide
	 * @param obj Object [Overlay extension] oggetto chiamante
	 * @param formName String nome di un'eventuale form da cui estrarre i dati (opzionale)
	 * @param secondStep boolean se true l'overlay si trova al secondo passo (opzionale)
	 * @return void
	 */
	this.setContentByAjax = function (actionString, anchorShow, anchorHideId, obj, formName, secondStep) {
		// obj.show(anchorShow, this.loaderContent.body, anchorHideId);
		this.getContentByAjax(actionString, anchorShow, anchorHideId, obj, formName, secondStep);
	};
	
	/**
	 * Overlay.debug
	 * 
	 * Restituisce true se è stata impostata la modalità debug
	 * 
	 * @deprecated
	 * @return boolean
	 */
	this.debug = function () {
		return this.debugMode;
	};
	
	/**
	 * Overlay.generateOverlay
	 * 
	 * Genera la grafica di un overlay
	 * 
	 * @param text String testo dell'overlay
	 * @return Object { header, body, footer }
	 */
	this.generateOverlay = function (text) {
		return { header: '<span class="o-tLeft"></span><span class="o-tRight"></span><span class="o-bLeft"></span><span class="o-bRight"></span>',
				body: '<div class="' + this.color + '">' +
					'<span class="tLeft"></span>' +
					'<span class="tRight"></span>' +
					'<span class="bLeft"></span>' +
					'<span class="bRight"></span>' +
					'<div class="box">' +
						text +
					'</div>' +
				'</div>',
				footer: ''
		};
	};
	
	/**
	 * Overlay.isSuccessResponse
	 * 
	 * Stabilisce se la risposta sia affermativa
	 * 
	 * @param response misc 
	 * @return boolean
	 */
	this.isSuccessResponse = function (response) {
		return response == 'OK' || response == 'LP';
	};
	
	/**
	 * Overlay.setWidth
	 * 
	 * Imposta la larghezza dell'overlay
	 * 
	 * @param width int larghezza
	 * @return void
	 * @deprecated use setProperty
	 */
	this.setWidth = function (width) {
		this.YUIoverlay.cfg.setProperty('width', width + 'px');
	};
	
	/**
	 * Overlay.blur
	 * 
	 * Toglie il focus dall'overlay
	 * 
	 * @return void
	 */
	this.blur = function () {
		this.YUIoverlay.renderEvent.unsubscribe();
	};
	
	/**
	 * Overlay.setProperty
	 * 
	 * Imposta una proprietà per l'overlay
	 * 
	 * @param property String nome della proprietà
	 * @param value misc valore della proprietà
	 * @return void
	 */
	this.setProperty = function (property, value) {
		this.YUIoverlay.cfg.setProperty(property, value);		
	}
};