/*
        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()" ///////////////////////////////////////////////////////////////////////////
}

