/*
	Plugin per la gestione di finestre draggabili, ridimensionabili e con tante opzioni.
	Autore: 	Marco Pegoraro
	Data:		12 Dicembre 2006
	Url:		http://www.consulenza-web.com/jquery-validation-plugin.dc-13.html TD
	
	Questo plugin permette di realizzare floating windows interne alla pagina con un sacco di 
	opzioni.
	Le finestre possono essere spostate, ridimensionate, massimizzate, chiuse e nascoste.
	
	Il tutto utilizzando la comoda notazione jQuery e partendo da un semplice DIV xHTML con 
	contenuto.
	
	
	COME FUNZIONA:
	-----------------------------------------------------------------------------------------------
	
	Innanzitutto vediamo un DIV "tipo" utilizzabile come floating window:
	<div id="w1" class="xWin">Il mio contenuto</div> // La classe è importante!!!
	
	Ora vediamo il Js da eseguire al document.ready().
	$("#w1").xWin();
	
	Questo genera una floating window con opzioni predefinite. Ci sono un sacco di opzioni che si
	possono utilizzare per personalizzare la finestra generata.
	Innanzitutto la finestra è composta da:
	- barra del titolo
		- pulsanti di azione ([massimizza|riduci a box], chiudi)
	- box del contenuto (contiene quello che c'era dentro al div)
	- barra di stato (status bar)
		- pulsante per il ridimensionamento.
	
	Cliccando sulla barra del titolo e spostando il mouse si muove la finestra.
	Cliccando sul pulsante di ridimensionamento e spostando il mouse si ridimensiona la finestra.
	Doppio click sulla barra del titolo per massimizzare/ridurre a box.
	Click sull'icona di massimizzazione/riduzione per massimizzare/ridurre a box.
	Click sull'icona di chiusura per chiudere la finestra.
	
	
	OPZIONI DI CONFIGURAZIONE:
	-----------------------------------------------------------------------------------------------
	
	Le opzioni di configurazione vanno date utilizzando la classica notazione jQuery:
	$("#w1").xWin({ resizable: "no", moveable: "no" });
	
	// Dimensione e posizionamento iniziale.
	width:			Larghezza iniziale in pixel (int). Default: 200.
	height:			Altezza iniziale in pixel (int). Default: 200.
	top:			Posizione iniziale dall'alto in pixel (int). Default: 50.
	left:			Posizione iniziale da sinistra in pixel (int). Default: 50.
	
	// Attributi:
	title:			Titolo della finesta, stringa.
	status:			Testo in status bar, stringa.
	
	// Comportamenti:
	resizable:		[si|no] definisce se la finestra si può ridimensionare.
	moveable:		[si|no] definisce se è possibile spostare la finestra.
	closeable:		[si|no] definisce se è possibile chiudere la finestra.
	
	// Preimpostazioni al caricamento.
	start:			[center] posiziona la finestra al centro della pagina. Da sistemare!
	show:			[no] nasconde inizialmente la finestra.
	
	// Configurazioni avanzate:
	inParent:		[si|no] definisce se circoscrivere la finestra nell'elemento genitore.
					L'elemento genitore deve avere posizione assoluta (da sistemare).
	
	// Circoscrivere una finestra:
	minX:			distanza minima dal bordo sinistro.
	maxX:			distanza massima dal bordo sinistro.
	minY:			distanza minima dal bordo superiore.
	maxY:			distanza massima dal bordo superiore.
	
	
	Una volta "caricata" una finestra è possibile chiamare nuovamente la funzione "xWin"
	sull'oggetto. Passando alcuni parametri speciali è possibile interagire con l'oggetto stesso
	modificandone le proprietà.
	
	title:			ridefinisce il testo nella barra del titolo.
	status:			ridefinisce il testo nella status bar.
	show:			visualizza la finestra.
	hide:			nasconde la finestra.
	destroy:		distrugge la finestra (rimuove l'html dalla pagina)
	ret:			Sperimentale. Imposta un valore nell'attributo "ret" del DIV principale. 
					In teoria serve per poter creare delle finestre di dialogo simili nel
					comportamento alle GUI xWindow o GTK (che poi sono uguali +- in qualunque
					altro toolkit per interfaccie grafiche)
	

					
	TO DO:
	-----------------------------------------------------------------------------------------------
	- Callback su vari eventi: ready, show, hide, maximize, minimize, close, moved, ecc...
	- Caricamento dinamico del contenuto (Ajax).
	- Opzione per finestre modali.
*/

jQuery.fn.xWin = function( cfg ) {
	// Preimpostazione per la variabile in input che è opzionale.                                //
	cfg					= cfg || {};
	
		
	// Salvo l'oggetto su cui lavoro nella variabile di configurazione che è locale all'istanza. //
	// Lo salvo come ID. Successivamente potrò utilizzare questa variabile per riferirmi         //
	// all'oggetto corretto nel caso ci siano più istanze nella finestra.                        //
	cfg.obj				= "#"+$(this).attr("id");
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Intercetto lo stato di creazione della finestra per agire solamente sulle proprietà di    //
	// stato e titolo modificandole. In questo modo per modificare queste proprietà è            //
	// sufficiente richiamare il plugin con una nuova configurazione.                            //
	if ( this.attr("xWin") == "done" ) {
		if ( cfg.status ) 	{ $(cfg.obj + " .xWin_sts span:last").html(cfg.status); }
		if ( cfg.title ) 	{ $(cfg.obj + " .xWin_tit span:first").html(cfg.title); }
		if ( cfg.show )		{ $(cfg.obj).fadeIn(); }
		if ( cfg.hide )		{ $(cfg.obj).fadeOut(); }
		if ( cfg.destroy )	{ $(cfg.obj).fadeOut().remove(); }
		if ( cfg.ret != null )	{ $(cfg.obj).attr("ret", cfg.ret); }
		return false;
	} // Fine modifica proprietà "status" e "title". //////////////////////////////////////////////
	
	
	
	// Preimpostazione per le variabili che definiscono le dimensioni dei vari elementi della    //
	// finestra. Vengono poi utilizzate per ricalcolare dinamicamente le dimensioni.             //
	cfg.width 			= cfg.width 	|| 200;			// Larghezza della finestra.             //
	cfg.height			= cfg.height 	|| 200;			// Altezza della finestra.               //
	cfg.top				= cfg.top		|| 50;			// Posizione in altezza.                 //
	cfg.left			= cfg.left		|| 50;			// Posizione da sinistra.                //
	
	// Preimpostazioni per le dimensioni minime e massime.                                       //
	cfg.minW			= cfg.minW		|| 50;			// Larghezza minima.                     //
	cfg.minH			= cfg.minH		|| 50;			// Altezza minima.                       //
	cfg.maxW			= cfg.maxW		|| 0;			// Larghezza massima.                    //
	cfg.maxH			= cfg.maxH		|| 0;			// Altezza massima.                      //
	
	// Preimpostazioni per le posizioni massime e minime.                                        //
	cfg.minX			= cfg.minX		|| -1;			// Posizione minima X.                   //
	cfg.minY			= cfg.minY		|| -1;			// Posizione minima Y.                   //
	
	// L'opzione "inParent" limita la finestra nello spazio occupato dal genitore.               //
	if ( cfg.inParent == "si" ) {
		cfg.minX = 0;
		cfg.minY = 0;
		cfg.maxX = parseInt($(this).parent().width());
		cfg.maxY = parseInt($(this).parent().height());
	}
	
	// Preimpostazioni per titolo e status bar.                                                  //
	cfg.title			= cfg.title		|| "xWin";		// Barra del titolo.                     //
	cfg.status			= cfg.status	|| "xWin";		// Barra di stato.                       //
	cfg.resizable		= cfg.resizable	|| "si";		// Opzione per finestra ridimensionabile.//
	cfg.closeable		= cfg.closeable || "si";		// Definisce se la finestra è chiudibile.//
	cfg.moveable		= cfg.moveable	|| "si";		// Definisce se è possibile spostare.    //
	
	
	// Inizializzazione dei flag per spostamento e ridimensionamento della finestra.             //
	cfg.dragging		= false;
	cfg.resizing		= false;
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Costruzione della struttura della finestra. Aggiungo alcuni tag per definire box di       //
	// contenuto, titolo e status bar.                                                           //
	// Definisco il box del contenuto della finestra.                                            //
	this.html('<div class="xWin_cnt">' + this.html() + '</div>');
	// Costruzione del div per la barra del titolo.                                              //
	tit = '<div class="xWin_tit"><span class="xWin_title">' + cfg.title + '</span></div>';
	this.prepend(tit);
	// Costruzione della statusbar.                                                              //
	sts = '<div class="xWin_sts"><span class="xWin_resize"></span><span>' + cfg.status + '</span></div>';
	this.append(sts);
	// Controllo per l'opzione finestra ridimensionabile.                                        //
	if ( cfg.resizable == "no" ) $(cfg.obj + " div.xWin_sts span.xWin_resize").remove();
	// Aggiunta dei bottoni per il dimensionamento fisso alla barra del titolo.                  //
	if ( cfg.resizable 	== "si" ) 	$(cfg.obj + " div.xWin_tit").prepend('<span class="xWin_title_toScreen"></span>');
	if ( cfg.closeable 	== "si" )	$(cfg.obj + " div.xWin_tit").prepend('<span class="xWin_title_close"></span>');
	//alert($(cfg.obj + " div.xWin_tit").html());
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	// Imposto lo z-index iniziale per la finestra. Successivamente viene incrementato al        //
	// click del mouse.                                                                          //
	this.css("z-index", 1000);
	this.css("display", "block");
	
	
	// Imposto un attributo arbitrario che definisce che la finestra è già stata creata. Serve   //
	// per poter richiamare la funzione dell'oggetto al fine di modificare titolo e statusBar    //
	// ma senza ridefinire tutta la finestra.                                                    //
	this.attr("xWin", "done");
	
	// Salvo nella configurazione locale gli elementi della finestra su cui bisognerà agire      //
	// durante le varie operazioni di ridimensionamento, dragging e altro.                       //
	cfg.oCnt = $(cfg.obj + " .xWin_cnt");
	cfg.oTit = $(cfg.obj + " .xWin_tit");
	cfg.oSts = $(cfg.obj + " .xWin_sts");
	cfg.oRes = $(cfg.obj + " .xWin_resize");
	
	
	// Preimpostazione per finestrella centrata nello schermo.                                   //
	// !!! DA SISTEMARE !!!                                                                      //
	if ( cfg.start == "center" ) {
		cfg.left 	= screen.width/2 - parseInt(cfg.width)/2;
		cfg.top 	= screen.height/2 - parseInt(cfg.height)/2;
	} // Fine preimpostazione per finestrella centrata nello schermo. /////////////////////////////
	
	// Lancio il calcolo delle posizioni iniziali della finestra e delle componenti interne.     //
	paint();
	
	// Preimpostazione per partire con la finestra nascosta.                                     //
	$(cfg.obj).hide();
	if ( cfg.show != "no" ) $(cfg.obj).fadeIn();
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// GESTIONE DEL DRAGGING PER SPOSTAMENTO E RIDIMENSIONAMENTO DELLA FINESTRA.                 //
	// Inizializzazione del dragging sulla barra del titolo per spostare la finestra.            //
	cfg.oTit.mousedown(function( e ) {
		// Definisco l'inizio del dragging per lo spostamento della finestra. FLAG.              //
		cfg.dragging	= true;
		
		// Calcolo l'offset in base all'angolo in alto a sinistra della finestra.                //
		// Questo serve per far sì che si possa fare il drag da qualunque punto della barra del  //
		// titolo senza che la finestra subisca uno "scatto" alla posizione del mouse.           //
		cfg.drgOffX = e.clientX - $(cfg.obj).left().split("px")[0];
		cfg.drgOffY = e.clientY - $(cfg.obj).top().split("px")[0];
	});
	// Definisco l'inizio del dragging per il ridimensionamento della finestra.                  //
	cfg.oRes.mousedown(function( e ) {
		// Definisco l'inizio del dragging per il ridimensionamento della finestra.              //
		cfg.resizing	= true;
		
		// Calcolo l'offset del posizionamento del mouse sul box di ridimensionamento.           //
		cfg.resOffX		= parseFloat(cfg.left) + parseFloat(cfg.width) - e.clientX;
		cfg.resOffY		= parseFloat(cfg.top) + parseFloat(cfg.height) - e.clientY;
	});
	// Controllo sul movimento del mouse.                                                        //
	$(document).mousemove(function( e ) {
		
		// Ricalcolo gli estremi dell'elemento genitore per ovviare a ridimensionamenti.
		if ( cfg.inParent == "si" ) {
			cfg.maxX = parseInt($(cfg.obj).parent().width());
			cfg.maxY = parseInt($(cfg.obj).parent().height());
		}
		
		
		// Azioni da effettuare per il dragging su spostamento della finestra.                   //
		if ( cfg.dragging == true && cfg.moveable == "si" ) {
			// Calcolo la nuova posizione per la finestra.                                       //
			// Angolo in alto a sinistra.                                                        //
			pT = e.clientY - cfg.drgOffY;
			pL = e.clientX - cfg.drgOffX;
			// Angolo in basso a destra.                                                         //
			aT = pT + $(cfg.obj).height();
			aL = pL + $(cfg.obj).width();
			
			// Predispongo le variabili di controllo che decidono se applicare o meno lo         //
			// lo spostamento richiesto con il mouse.                                            //
			okX = true;okY = true;
			
			// Applico le restrizioni minime in orizzontale.                                     //
			if ( parseFloat(cfg.minX) >= 0 ) 	if ( pL < parseFloat(cfg.minX) ) 	okX = false;
			// Applico le restrizioni massime in orizzontale.                                    //
			if ( parseFloat(cfg.maxX) > 0 ) 	if ( aL >= parseFloat(cfg.maxX) ) 	okX = false;
			// Applico le restrizioni minime in verticale.                                       //
			if ( parseFloat(cfg.minY) >= 0 ) 	if ( pT < parseFloat(cfg.minY) ) 	okY = false;
			// Applico le restrizioni massime in verticale.                                      //
			if ( parseFloat(cfg.maxY) > 0 ) 	if ( aT > parseFloat(cfg.maxY) ) 	okY = false;
			
			if ( okX == true ) { cfg.left 	= pL; }
			if ( okY == true ) { cfg.top 	= pT; }
			
			// Applico il paint solamente se c'è stato un movimento.                             //
			if ( okX || okY ) { paint(); }
		} // Fine operazioni di dragging su spostamento della finestra.                          //
		
		// Azioni da effettuare per il dragging su ridimensionamento della finesta.              //
		if ( cfg.resizing == true ) {
			// Calcolo le nuove dimensioni della finestra per applicare i controlli.             //
			w = e.clientX - parseFloat(cfg.left) + cfg.resOffX;
			h = e.clientY - parseFloat(cfg.top) + cfg.resOffY;
			// Calcolo l'angolo in basso a destra per vedere se sfora lo spazio delimitato da    //
			// maxX e maxY.                                                                      //
			aL = parseInt($(cfg.obj).left()) + w + 1;
			aT = parseInt($(cfg.obj).top()) + h + 1;
			
			// Predispongo le variabili di controllo che decidono se applicare o meno il         //
			// ridimensionamento richiesto.                                                      //
			okW = true;
			okH = true;
			
			// Controllo limite di grandezza minimo.                                             //
			if ( w < parseFloat(cfg.minW) ) okW = false;
			// Controllo limite di larghezza massimo.                                            //
			if ( parseFloat(cfg.maxW) > 0 ) if ( w > parseFloat(cfg.maxW) ) okW = false;
			if ( aL > parseInt(cfg.maxX) ) okW = false;
			// Controllo limite di altezza minimo.                                               //
			if ( h < parseFloat(cfg.minH) ) okH = false;
			// Controllo limite di altezza massimo.                                              //
			if ( parseFloat(cfg.maxW) > 0 ) if ( h > parseFloat(cfg.maxH) ) okH = false;
			if ( aT > parseInt(cfg.maxY) ) okH = false;
			
			if ( okW ) cfg.width = w;
			if ( okH ) cfg.height = h;
			
			// Ridisegno i componenti interni per dimensioni e posizionamento.                   //
			if ( okW || okH ) paint();
		} // Fine operazioni di dragging su ridimensionamento della finestra.                    //
	});
	// Termine del dragging per qualunque tipo di oggetto.                                       //
	$(document).mouseup(function() {
		// Azzeramento del FLAG per il dragging per lo spostamento della finestra.               //
		cfg.dragging	= false;
		
		// Azzeramento del FLAG per il dragging per il ridimensionamento della finestra.         //
		cfg.resizing	= false;
	}); // Fine gestione del dragging.                                                           //
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Gestione del click sulla finestra per portarla in primo piano.                            //
	this.mousedown(function() {
		zi = parseInt($(this).css("z-index"));
		$(".xWin").each(function() { zi++ });
		$(this).css("z-index", zi);
	}); // Fine gestione click sulla finestra per portarla in primo piano.                       //
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Aggiungo i controlli per il ridimensionamento a schermo pieno o a box della finestra.     //
	if ( cfg.resizable == "si" ) {
		// Doppio click sulla barra del titolo.                                                  //
		$(cfg.obj + " div.xWin_tit").dblclick(function() { boxize(); });
		// Click sull'icona nella barra del titolo.                                              //
		$(cfg.obj + " div.xWin_tit span.xWin_title_toScreen").click(function() { boxize(); });
	} // Fine controlli per la massimizzazione e la riduzione a box.                             //
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Controllo sulla chiusura della finestra.                                                  //
	$(cfg.obj + " div.xWin_tit span.xWin_title_close").click(function() {
		$(cfg.obj).fadeOut();
	}); // Fine controllo sulla chiusura della finestra. //////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Effettua il ridimensionamento alle dimensioni massime o al box della finestra.            //
	function boxize() {
		// Riporta il box alle dimensioni originali.                                             //
		if ( $(cfg.obj).attr("p") == "all" ) {
			$(cfg.obj + " div.xWin_tit span.xWin_title_toScreen").removeClass("xWin_title_toBox");
			
			cfg.top		= $(cfg.obj).attr("pt");
			cfg.left	= $(cfg.obj).attr("pl");
			cfg.width	= $(cfg.obj).attr("pw");
			cfg.height	= $(cfg.obj).attr("ph");
			$(cfg.obj).attr("p", "");
			
		
		// Espande il box nelle dimensioni massime consentite.                                   //
		} else {
			$(cfg.obj + " div.xWin_tit span.xWin_title_toScreen").addClass("xWin_title_toBox");
			
			$(cfg.obj).attr("pw", parseInt($(cfg.obj).width()));
			$(cfg.obj).attr("ph", parseInt($(cfg.obj).height()));
			$(cfg.obj).attr("pt", parseInt($(cfg.obj).top()));
			$(cfg.obj).attr("pl", parseInt($(cfg.obj).left()));
			$(cfg.obj).attr("p", "all");
			
			
			if ( cfg.minX >= 0 ) 	cfg.left 	= cfg.minX; else cfg.left 	= 0;
			if ( cfg.minY >= 0 ) 	cfg.top		= cfg.minY; else cfg.top	= 0;
			
			if ( cfg.maxW > 0 )		cfg.width	= cfg.maxW; else cfg.width 	= screen.width;
			if ( cfg.maxH > 0 )		cfg.heigth	= cfg.maxH; else cfg.height = screen.height;
			
			if ( cfg.inParent == "true" ) {
				if ( cfg.maxX > 0 )		cfg.width	= cfg.maxX;
				if ( cfg.maxY > 0 )		cfg.height	= cfg.maxY;
			} else {
				if ( cfg.maxX > 0 )		cfg.width	= parseInt(cfg.maxX) - parseInt(cfg.minX) -1;
				if ( cfg.maxY > 0 )		cfg.height	= parseInt(cfg.maxY) - parseInt(cfg.minY) -1;
			}
			
		}
		
		paint();
	} // Fine "boxise()" //////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	
	
	
	
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Ricalcola le dimensioni dei vari componenti della finestra in base alle dimensioni della  //
	// finestra stessa contenute nella configurazione.                                           //
	function paint() {
		// Imposto dimensioni e posizionamento della finestra.                                   //
		$(cfg.obj).width		( cfg.width 	+ "px" );
		$(cfg.obj).height		( cfg.height 	+ "px" );
		$(cfg.obj).top			( cfg.top 		+ "px" );
		$(cfg.obj).left			( cfg.left		+ "px" );
		
		// Calcolo le dimensioni e la posizione della barra di stato.                            //
		cfg.oSts.top		( ( $(cfg.obj).height() - cfg.oSts.height() ) + "px");
		cfg.oSts.width		( $(cfg.obj).width() + "px" );
		
		// Calcolo le dimensioni e la posizione del box di contenuto.                            //
		cfg.oCnt.top		( cfg.oTit.height() + "px");
		cfg.oCnt.width		( $(cfg.obj).width() + "px" );
		cfg.oCnt.height		( ( $(cfg.obj).height() - cfg.oTit.height() - cfg.oSts.height() ) + "px" );
	} // Fine "paint()" ///////////////////////////////////////////////////////////////////////////
}

