
/**
 * @fileOverview
 * This files is the core of the framework and it describes 2 modules.
 * 1. PV.WidgetManager
 * 2. PV.scriptsManager
 */

/**
 * @namespace
 *
 * @see PV.widgetManager
 * @see PV.scriptsManager
 *
 * @desc PV is the main namepace. All modules live within this namespace.
 */
var PV = PV || {};

/** @namespace PV.settings */
PV.settings = {
    /**
     * @field WIDGET_PATH
     * @default ../../widgets/
     * @desc Chemin des widgets. Ce chemin est utilisé par {@link PV.widgetManager.requireWidget}
     */
    WIDGET_PATH: "../../widgets/",

    /**
     * @field COMPONENT_PATH
     * @default ../../components/
     * @desc Chemin des modules complémentaires.
     */
    COMPONENT_PATH: "../../components/"
};


/**
 * @namespace PV.widgetManager
 *
 * @desc
 * PV.widgetManager est un module qui permet la cr&eacute;ation et la gestion de
 * widgets.<br/><br/>
 * Tout widget créer avec PV.widgetManager étend une classe <b>PVBaseWidget</b>
 *
 * @see PVBaseWidget
 */
PV.widgetManager = (function() {

    /**@ignore */
    Element.triggerEvent = function(element, eventName) {

        //firefox
        if (document.createEvent) {
            var evt = document.createEvent('HTMLEvents');
            evt.initEvent(eventName, true, true);
            return !element.dispatchEvent(evt);
        }

        //ie
        if (document.createEventObject) {
            var evt = document.createEventObject();
            return element.fireEvent('on' + eventName, evt);
        }
    };


    var widgetsHandler = {},
    loadedWidgets = {};

    var PVBaseWidget = new Class.create({
        /** @scope PVBaseWidget.prototype */

        /**
         * @name PVBaseWidget#create
         * @event
         * @param {Event} eventData
         */
        /*
         * @name PVBaseWidget#init
         * @event
         * @param {Event} eventData
         **/
        /*
         * @name PVBaseWidget#disableEvent
         * @event
         * @param {Event} eventData
         */
        /*
         * @name PVBaseWidget#enableEvent
         * @event
         * @param {Event} eventData
         */
        widgetBaseClass: null,
        settings: {
            disabled: false
        },
        widgetName: "baseWidget",

        /**
         * @constructs
         *
         * @param {Object} settings Paramètres de base du widget
         * @param {String | Element} Element L'id de l'élément ou l'élément
         * pour lequel le widget sera créé.
         *
         * @description
         * Classe de base des widgets. Tous les widgets créés avec
         * {@link PV.widgetManager.createWidget} <br/>
         * étendent cette classe. Il est à  noter que PVBaseWidget ne peut
         * être instantié à  l'extérieur de PV.widgetManager.
         *
         * <p><strong>Fonctionnement</strong></p>
         * <p><strong>1. Créer un prototype pour le nouveau widget</strong></p>
         * <pre name="code" class="js">
         * var spinBoxWidget = {
         *     settings: {
         *         itemClass: '.myItem',
         *         'upBtnClass': '.upBtn',
         *         'downBtnClass': '.downBtn'
         *     },
         *     _buildWidget: function() {
         *         //Construire le squelette du widget ici.
         *     },
         *     _init: function() {
         *         //
         *         var eventData = {widgetName: this.widgetName};
         *         this._fireEvent("spinBoxWidgetInit")
         *     }
         * };
         * </pre>
         *
         * <p><strong> 2. Enregister le widget </strong></p>
         * Une fois le prototype de futur widget créé, il faut l'enregister
         * auprès du widgetManager:
         * PV.widgetManager.createWidget("PvSpinBoxWidget",spinBoxWidget);
         *
         * <strong>PV.widgetManager.createWidget</strong> ou
         * <strong>PV.widgetManager.registerWidget</strong>
         * étendent alors PvBaseWidget avec les  paramètres définis dans le
         * nouveau prototype. Toutes les fonctions de PVBaseWidget qui n'ont
         * pas été redéfinies sont automatiquement disponibles dans le
         * prototype.<br/>
         *
         * Tous les widgets créés sont disponibles dans l'espace de nom
         * <b>PV.widgetManager.ui</b>.
         *
         * <p><strong> 3. cycle de vie</strong></p>
         * Lorsqu'une nouvelle instance d'un widget est créée deux fonctions
         * sont automatiquement appelées:
         * <p>1. <strong>_buildWidget()</strong></p>
         * (utilisée pour créer le template du widget)
         * <p>2. <strong>_init()</strong><br/></p>
         * (utilisée pour paramétrer le widget)
         *

         *
         * <p>4. <strong>Paramètres inline</strong></p>
         * Pour tous les paramètres de type Booléen, chaîne de caractères, ou entier, il est possible de les ajouter en 'ligne' grâce
         * à un attribut 'inlineOptions' de l'élément principal du widget. Il est à noter que les paramètres <strong>inline</strong>
         * ont la priorité sur les paramètres définis lors de l'initialisation du widget en javascript.
         * Le format est le suivant:
         *
         * <pre name="code" class="html">
         * <!--Exemple provenant d'un slide widget-->
         *  <div id="elementId" inlineOptions="showNav::true, showNavBtn::false, title::the title, selectedClass::.selected"></div>
         * </pre>
         *
         *<p>5.<strong>Exemple d'utilisation</strong></p>
         *<pre name="code" class="js">
         * var aSpinBoxWidget = new PV.widgetManager.ui({},"elementId");
         * aSpinBoxWidget.on("spinBoxWidgetInit",function() {
         *     console.log(" spinbox initialisé");
         * });
         *</pre>
         */
        initialize: function(settings,element) {
            /** L'élément sur lequel s'applique le widget */
            this.element = $(element) || false;
            if (!this.element) throw new Error("An element or an element id must be provided.");
            this.id = this._generateID();
            /** Les paramètres du widget */
            settings = this._parseInlineOptions(settings); //prise en compte des options en ligne
            this.settings = Object.extend(Object.clone(this.settings), settings);
            this._buildWidget();
            this._handleListeners();
            this._fireEvent("create", this.widget());
            this._init();
            this._fireEvent("init", this.widget());
        },

        /** @ignore */
        _handleListeners: function() {
            var listeners = this.settings.listeners;
            if (!listeners || !listeners instanceof Array) return;
            if (listeners.length === 0) return;
            var self = this;
            $(listeners).each(function(eventData) {
                if (! (typeof eventData.event === "string" && typeof eventData.eventHandler === "function"))
                    return;
                self.settings[eventData.event] = eventData.eventHandler;
                var completeEventName = self.widgetName+":"+eventData.event;
                var obv = new Event.observe( self.element, completeEventName, eventData.eventHandler);
            });
        },

        /** @ignore */
        _isEvent: function(optionName) {
            var pattern = /Event$/;
            return pattern.test(optionName);
        },

        /** @ignore */
        _generateID: function() {
            var currentTime = new Date().getTime();
            var randomNumber = Math.ceil(Math.random()*1420);
            currentId = "pvWidget_"+currentTime+"_"+randomNumber+"_"+this.widgetName;
            return currentId;
        },

        /**
         * Permet de construire le squelette du widget. Cette fonction est automatiquement<br/>
         * appelée lorsque de la création d'une nouvelle instance du widget
         */
        _buildWidget: function() {
        /*construction */

        },

        /** Permet d'initialiser le widget. Cette fonction est appelée automatiquement après _buildWidget(). */
        _init: function() {

        },

        /**
         * Mettre a  jour les paramètres du widget
         * @param {String} key Le paramètre à mettre à  jour
         * @param {String} value La nouvelle 	valeur
         */
        setOption: function( key, value ) {
            this.settings[key] = value;
            if (key !== "disabled") return this;
            this.widget()[value ? "addClassName": "removeClassName"](this.widgetName + "-disabled" + " " +"pv-ui-state-disabled" ).writeAttribute( "pv-ui-disabled", value );
        },

        /** Supprimer tous les événements attachés au widget */
        destroy: function() {
            Event.stopObserving(this.element);
            $(this.widget()).writeAttribute( "pv-ui-disabled", false ).removeClassName(this.widgetName + "-disabled " +"ui-state-disabled" );
        },

        /**
         * Récupérer la valeur du paramètre
         * @param {String} key .Le paramètre à récupérer
         */
        getOption: function(key) {
            return this.settings[key];
        },

        /**@ignore*/
        _parseInlineOptions : function(settings){
            var params = settings;
            var inlineOptions = ($(this.element).readAttribute("inlineOptions")) || false;
            if(!inlineOptions){
                return settings;
            }
            inlineOptions = inlineOptions.strip();
            var paramsPattern = /\w+:{2}[a-zA-Z0-9_.\s]+/;
            var allOptions = [];
            var inlineSettings = {};
            inlineOptions.scan(paramsPattern, function(occ){
                var options = occ[0];
                if(options.length!==0){
                    options = options.split('::');
                    var key = options[0];
                    var value = options[1];
                    //try to preserve settings' type
                    var oldType = typeof(settings[key]);
                    switch (oldType){
                        case 'boolean':
                            inlineSettings[key] = (value == "false") ? false : true;
                            break;

                        case 'string':
                            inlineSettings[key] = value;
                            break;

                        case 'number':
                            inlineSettings[key] = parseInt(value);
                            break;

                        default: //undefined case
                            inlineSettings[key] = value;
                            break;
                    }
                }
            });
            //update settings here
            var overrideSettings = Object.extend(settings,inlineSettings);
            //remove inlineOptions
            $(this.element).removeAttribute("inlineOptions");
            return overrideSettings;
        },

        /**
     * Lancer un événement
     * @param {String} eventType le nom de l'événement à lancer
     * @param {Mixin} data Données à  transmettre aux écouteurs de l'événement.
     */
        _fireEvent: function(eventType,data) {
            var callback = this.settings[eventType];
            if (typeof callback !== "function") return;
            var completeEventName = this.widgetName+":"+eventType;
            Event.fire( this.element, completeEventName, data );
        },

        /**
     * Attacher des écouteurs aux événements lancés par le widget
     * @param {String}  eventName Le nom de l'événement a  écouter.
     * @param {Function} callback la fonction à executer lorsque
     * l'événement se produit. Les paramètres de callback dependent du
     * type d'événement
     */
        on: function(eventName, callback) {
            if (!(typeof eventName ==="string" && typeof callback==="function"))
                throw new Error("Event's name must be a String and Callback must be a function");
            this.settings[eventName] = callback;
            var completeEventName = this.widgetName+":"+eventName;
            var obvs = new Event.observe( this.element, completeEventName, callback);
        },

        /** Récupérer l'élément sur lequel s'applique le widget. */
        widget: function() {
            // Expose public functions too
            return this.element;
        },
        /** Activer le widget. lance l'événement <strong>enableEvent</strong> */
        enable: function() {
            this.setOption("disabled",false);
            this._fireEvent("enableEvent");
        },

        /** Désactiver le widget. lance l'événement <strong>disableEvent</strong> */
        disable: function() {
            this.setOption("disabled",true);
            this._fireEvent("disableEvent");
        }
    });

    /** @ignore */

    var registerWidget = function(widgetName, widgetPrototype) {
        if (typeof widgetName !== "string")
            throw new Error("You must provide a name for the widget");
        //update widgetName
        widgetPrototype.widgetName = widgetName;
        //extend prototype settings with base prototype Settings
        widgetPrototype.settings = Object.extend({
            disable:  false
        },widgetPrototype.settings);
        widgetsHandler[widgetName] = Class.create(PVBaseWidget, widgetPrototype);
    };

    /** @ignore */
    var loadWidget = function(widgetName, callback) {
        /*var widgetLoadingStatus = PV.widgetsQueueManager.getLoadingStatus(widgetName);
        var widgetQueue = PV.widgetsQueueManager.createOrRetrieveQueue(widgetName);
        switch(widgetLoadingStatus){

            case "unloaded":
                var WIDGET_PATH = PV.settings.WIDGET_PATH;
                var params = {};
                params.base = WIDGET_PATH;
                params.script = widgetName;

                var customCallback = function(){
                    PV.widgetsQueueManager.setLoadingStatus(widgetName,'loaded');
                    callback();
                    var completeQueue = PV.widgetsQueueManager.createOrRetrieveQueue(widgetName);
                    completeQueue.runTasks();
                };

                params.callback = customCallback;
                PV.widgetsQueueManager.setLoadingStatus(widgetName,'loading');
                PV.scriptsManager.require(params);
                break;

            case "loading":
                widgetQueue.addTask(callback);
                break;

            case "loaded":
                callback(); //widget is loaded, then we can execute directly the callback
                break;
        }*/
        var WIDGET_PATH = PV.settings.WIDGET_PATH;
        var params = {};
        params.base = WIDGET_PATH;
        params.script = widgetName;
        params.callback = callback;
        PV.scriptsManager.require(params);
        return this;
    };

    /*Charger components*/
    var _loadComponent = function(componentName, callback){

        if(typeof componentName != "string") throw new Error("RequireComponent : a componentName must be provided");
        if(typeof callback != "function") throw new Error("RequireComponent : callback must be a function");
        var COMPONENT_PATH = PV.settings.COMPONENT_PATH;
        var params = {};
        params.base = COMPONENT_PATH;
        params.script = componentName;
        params.callback = callback;
        PV.scriptsManager.require(params);
        return this;


    };

    var publicApi = {
        /** @scope PV.widgetManager */

        /**
     * @function createWidget
     *
     * @param {String} widgetName
     * @param {Object} widgetPrototype
     *
     * @desc
     * Cette fonction permet de créer un widget de <strong>nom</strong>
     * {widgetName} à  partir d'un <strong>objet prototype</strong>
     * {widgetPrototype}.
     * Le widget créé étendra {@link PVBaseWidget} et sera disponible dans
     * new PV.widgetManager.ui.{widgetName}
     *
     *<p><strong>Exemple</strong></p>
     *@example
     * <pre name="code" class="js">
     *  PV.widgetManager.createWidget('PvAccordionWidget',accordionProtoType);
     *  var oAccordionWidget = new PV.widgetManager.ui.PvAccordionWidget({},'containerId');
     * </pre>
     */
        createWidget: registerWidget,

        /**
     * @function registerWidget
     *
     * @param {String} widgetName
     * @param {Object} widgetPrototype
     *
     * @see PV.widgetManager.createWidget
     */
        registerWidget: registerWidget,

        /**@field */
        ui: widgetsHandler,

        /**
     * @function requireWidget
     * @param {String} widgetName
     * @param {Function} callback
     *
     * @desc
     * Charger un widget dans  la page avant de l'utiliser.
     * Cette fonction prend deux paramètres:<br/>
     * - le <strong>nom du widget</strong>
     * - une <strong>function callback</strong> à exécuter une fois le
     *   widget chargé.
     *<p><strong>Exemple</strong></p>
     *@example
     * <pre name="code" class="js">
     * PV.widgetManager.requireComponent("utils", function() {
     *    var el = $("myElement");
     *    var contentEl = $("myContent");
     *    new PV.utils.PvToggle(el,contentEl);
     * });
     * </pre>
     */
        requireWidget : loadWidget,

        /**
         * @function requireComponent
         * @param {String} componentName
         * @param {Function} callback
         *
         * @desc
         * Charger un component dans la page avant de l'utiliser
         * Cette fonction prend deux paramètres :<br/>
         * - Le <strong>nom du widget</strong><br/>
         * - Une <strong>function callback</strong> à  exécuter une fois le
         *   'component' chargé.
         *<p><strong>Exemple</strong></p>
         *@example
         * <pre name="code" class="js">
         * PV.widgetManager.requireWidget("PvGoogleMapWidget", function() {
         *     var settings = {zoom: 13};
         *     var gmapManager = new PV.widgetManager.ui.PvGoogleMapWidget(settings,"googleMapWidget");
         * });
         * </pre>
         *
         **/
        requireComponent : _loadComponent
    };

    return publicApi;
})();


/**
* @desc
* PV.sciptManager est un module qui permet d'inclure dynamiquement des scripts
* dans le DOM.
*
* @namespace PV.scriptsManager
*/
PV.scriptsManager = (function() {
    var loadedScripts = {};

    /** @ignore */
    
    var require = function(params) {
        if (typeof params.script !== "string")
            throw new Error("A script name must be provided");
        if (typeof params.callback !== "function")
            throw new Error("callback must be a function");
        var completeScriptPath = (typeof params.base === "string") ? params.base+params.script+".js" : params.script+".js";
        var scriptKey = params.script;
        if (loadedScripts[scriptKey] !== completeScriptPath) {
            try {
                /** @ignore */
                var s = document.createElement("script");
                s.src = completeScriptPath;
                s.type = "text/javascript";
                /** @ignore */
                s.onload = function(e) {
                    params.callback();
                };
                /** @ignore */
                s.onerror = function() {
                    throw new Error(" The widget "+completeScriptPath+ " can't be found");
                };
                if(params.head==true)
                {
                    document.getElementsByTagName("head")[0].appendChild(s);
                }
                else
                {
                    document.getElementsByTagName("body")[0].appendChild(s);
                }

                //load the script once
                loadedScripts[scriptKey] = completeScriptPath;
                //IE
                if (s.readyState){
                    /**@ignore */
                    s.onreadystatechange = function() {
                        if (s.readyState === 'complete' || s.readyState==='loaded')
                            s.onload();
                    };
                }

            } catch(e) {
                alert(e.message);
            }
        }
        else if (loadedScripts[scriptKey] === completeScriptPath) {
            alert(" the script '"+completeScriptPath+ "' is already loaded.");
            params.callback();
        }
        else{
            throw new Error(" The script "+completePath+ " can't be found");
        }

        return this;
    };


    /*require with queue*/
    var _syncRequire = function(params){
        if (typeof params.script !== "string") throw new Error("A script name must be provided");
        if (typeof params.callback !== "function") throw new Error("callback must be a function");

        /*Créer une queue pour les futurs appels*/
        var scriptKey = params.script;
        var scriptLoadingStatus = PV.widgetsQueueManager.getLoadingStatus(scriptKey);
        var scriptQueue = PV.widgetsQueueManager.createOrRetrieveQueue(scriptKey);
   
        switch(scriptLoadingStatus){
            case "unloaded":
                var completeScriptPath = (typeof params.base === "string") ? params.base+params.script+".js" : params.script+".js";
                /*callback*/
                var customCallback = function(){
                    PV.widgetsQueueManager.setLoadingStatus(scriptKey,'loaded');
                    params.callback();
                    var completeQueue = PV.widgetsQueueManager.createOrRetrieveQueue(scriptKey);
                    completeQueue.runTasks();
                };
                //Créer le script
                var scriptParam = {};
                Object.extend(scriptParam,params);
                scriptParam.completeScriptPath = completeScriptPath;
                scriptParam.callback = customCallback;
                _createScript(scriptParam);
                PV.widgetsQueueManager.setLoadingStatus(scriptKey,'loading');
                break;
                
            case "loading":
                scriptQueue.addTask(params.callback);
                break;

            case "loaded":
                params.callback(); //script déjà chargé, l'exécuter
                break;
        
        }

    };
    var _createScript = function(params){

        /** @ignore */
        try{
            var s = document.createElement("script");
            var completeScriptPath = params.completeScriptPath || "";
            s.src = completeScriptPath;
            s.type = "text/javascript";
            /** @ignore */
            s.onload = function(e) {
                params.callback();
            };
            /** @ignore */
            s.onerror = function() {
                throw new Error(" The script '"+completeScriptPath+ "' can't be found");
            };
            if(params.head==true)
            {
                document.getElementsByTagName("head")[0].appendChild(s);
            }
            else
            {
                document.getElementsByTagName("body")[0].appendChild(s);
            }
            
            //IE
            if (s.readyState){
                /**@ignore */
                s.onreadystatechange = function() {
                    if (s.readyState === 'complete' || s.readyState==='loaded')
                        s.onload();
                };
            }

        }catch(e){

        }
       

    };



    var publicApi = {
        /** @scope PV.scriptsManager */

        /**
     * @function require
     *
     * @param {Object} params
     * @param {String} params.base Le chemin du script à  charger . /path/to/scripts/
     * @param {String} params.script Nom du script à  charger sans l'extension '.js'
     * @param {String} params.callback Fonction à  executer une fois le script chargé.
     *
     * @return {Object} PV.scriptsManager
     *
     * @desc Inclure un script dans le DOM et execute une function une fois
     * le script chargé.
     * <strong>require</strong> renvoie {PV.scriptManager} ce qui permet de
     * chainer plusieurs appels à  require.
     *
     * @example
     * <pre name="code" class="js">
     * PV.scriptsManager.require({
     *     base: '/path/to/scripts/',
     *     script: 'lightView',
     *     callback: function() { console.log("lightview loaded"); }
     * });
     * </pre>
     */
        require: _syncRequire,//require,

        /**
     * @function load
     *
     * @param {Object} params
     *
     * @see PV.scriptsManager.require
     */
        load: _syncRequire,
        syncRequire : _syncRequire,
        syncLoad : _syncRequire
    };
    return publicApi;
})();

/**
* @namespace PV.lightviewManager
* @desc
* PV.lightviewManager est un module qui permet d'inclure dynamiquement la bibliothèque Lightview dans une page
*/
PV.lightviewManager = (function() {

    var isLoaded = false;
    var currentElement = null;

    /** @ignore */
    var init = function(settings) {
        var defaultSettings = {
            base: PV.settings.COMPONENT_PATH+'/lightview/',
            script: 'lightview'
        };
        var currentSettings = Object.clone(defaultSettings);
        if (typeof settings === "object"){
            currentSettings = Object.extend(currentSettings,settings) || currentSettings;
        }
        else if (typeof settings === "function"){
            currentSettings.callback = settings;
        }
        try {

            var userCallback = (typeof currentSettings.callback==='function') ? currentSettings.callback : Prototype.emptyFunction;
            /** @ignore */
            var completeCallback = function(){
                beforeUserCallBack(userCallback);
            };
            currentSettings.callback = completeCallback;
            PV.scriptsManager.require(currentSettings);
        }
        catch(e){}
    };

    /** @ignore */
    var beforeUserCallBack = function(userFunc){
        //fix navigator plugin detection
        fixLightViewInit();
        isLoaded = true;
        var simulateClick;
        if(currentElement){
            simulateClick =  function(){
                Element.triggerEvent($(currentElement),'click');
                return false;
            }
        }else{
            simulateClick =  Prototype.emptyFunction;
        }


        document.observe('lightview:loaded', function() {
            simulateClick();
            if(typeof userFunc==="function"){
                userFunc();
            }
        });

        Lightview.start.bind(Lightview)();

    };
    /** @ignore */
    var fixLightViewInit = function(){

        //from lightview unpacked line : 2670
        var c = (navigator.plugins && navigator.plugins.length);

        /** @ignore */
        var detectPlugin = function(a)
        {
            var b = false;
            if (c)
            {
                b = ($A(navigator.plugins).pluck("name").join(",").indexOf(a) >= 0);
            }
            else
            {
                try
                {
                    b = new ActiveXObject(a);
                }
                catch (e){}
            }
            return !!b;
        }
        if (c)
        {
            window.Lightview.Plugin = {
                flash: detectPlugin("Shockwave Flash"),
                quicktime: detectPlugin("QuickTime")
            };
        }
        else
        {
            window.Lightview.Plugin = {
                flash: detectPlugin("ShockwaveFlash.ShockwaveFlash"),
                quicktime: detectPlugin("QuickTime.QuickTime")
            };
        }

        //ie hack from lightview unpacked line 200
        if (document.documentMode >= 8 && !document.namespaces.ns_vml)
        {
            document.namespaces.add("ns_vml", "urn:schemas-microsoft-com:vml", "#default#VML");
        }
        else
        {
            if(document.createStyleSheet){
                var a = document.createStyleSheet();
                a.cssText = "ns_vml\\:*{behavior:url(#default#VML)}";
            }
        }
    };

    /** @ignore */
    var initLightView = function(settings){
        var lv = (typeof Lightview !="undefined") ? true : false;
        if(lv) return false;
        //load lightview on the first click. load once
        var settings = (typeof settings === 'object') ? settings : {};
        var lightviewClass =  settings.ligthviewClass || '.lightview';
        //load lightview - init lightview - then simulate click - load once
        $(document).on('click',lightviewClass, function(e){
            e.stop();
            var currentTarget = e.element();
            lightviewClass = lightviewClass.replace('.','');
            currentElement = ($(currentTarget).hasClassName(lightviewClass)) ? currentTarget : $(currentTarget).up('.'+lightviewClass) || false;
            if(isLoaded){
                return false;
            }
            if(currentElement){
                init(settings);
            }
            return false;
        });
        //Allow only one call
        publicApi.initLightview = Prototype.emptyFunction;

    };


    publicApi =  /** @scope PV.lightviewManager */{
        /**
     * @function initLightview
     * @desc Permet d'inséser la bibliothèque Lightview sur une page.<br/>
     * La bibliothèque est chargée une seule fois et lors du premier clic sur un lien ligthview <br/>
     *
     * @param {Object} settings Paramètres
     * @param {String} settings.lightviewClass Classe permettant d'identifier les éléments de la lightview. <strong>valeur par défaut : </strong>.lightview
     * @param {Function} settings.callback Fonction à executer après le chargement de la bibliothèque
     *
     *
     *<p>1. <strong>Exemple d'utilisation simple</strong></p>
     *<pre name="code" class="js">
     *<script>
     *Event.observe(window, 'load', function(){
            PV.lightviewManager.initLightviewOnclick();
          });
     *</script>
     *</pre>
     *
     *<p>2. <strong>Exemple d'utilisation avec callback et une lightviewClass </strong></p>
     *<pre name="code" class="js">
             <script>
                 Event.observe(window, 'load', function(){
                    PV.lightviewManager.initLightviewOnclick({lightviewClass:'.myLightviewClass', callback : function(){
                            console.log("test");
                    }});
                  });
            </script>
     *</pre>
     *
     *
     **/
        initLightviewOnclick : initLightView,
        /**
     * @function require requireLigthview
     * @desc Charger la bibliothèque Lightview sur une page.
     * @param {Object} settings Paramètres
     * @param {String} settings.base Chemin du dossier contenant la bibliothèque Lightview. <strong>Valeur par defaut</strong> PV.settings.COMPONENT_PATH+'/lightview/',
     * @param {String} settings.script Nom du script. <strong> Valeur par defaut:</strong> lightview
     * @param {Function} settings.callback Function à executer après le chargement de la bibliothèque
     *
     *<p><strong>Exemple d'utilisation</strong></p>
     *<pre name="code" class="js">

               var showSplash = Lightview.show({
                       href: baseLink + '/splash_pop',
                       rel: 'ajax',
                       title: '',
                       caption: '',
                       options: {
                         autosize: true,
                         topclose: false,
                         overlayClose: false,
                         menubar: false,
                         closeButton: false,
                         ajax: {
                        method: 'get',
                        evalScripts: true
                         }
                       }
                  });
                 Event.observe(window, 'load', function(){
                    PV.lightviewManager.requireLigthview({callback : showSplash});
                 });

         </pre>

     */
        requireLigthview : init
    };

    return publicApi;
})();

PV.widgetsQueueManager = (function(){
    /** @ignore */
    var queuesContainer = {};
    var widgetsLoadingStatus = {}; //unloaded - loading - loaded
    /** @ignore */
    var Queue = function(queueName){
        this.tasks = [];
        this.name = queueName || "none";

        /** @ignore */
        Queue.prototype.getLength = function(){
            return this.tasks.length;
        }
        /** @ignore */
        Queue.prototype.getTasks = function(){
            return this.tasks;
        }
        /** @ignore */
        Queue.prototype.addTask = function(task){
            if(typeof task == "function"){
                var taskLength = this.getLength();
                this.tasks[taskLength] = task;
            }
        }
        /** @ignore */
        Queue.prototype.runTasks = function(){

            var queueLength = this.getLength();
            if(queueLength == 0) return;
            var i;
            for(i=0; i< queueLength; i++){
                var task = this.tasks[i];
                if(typeof task =="function"){
                    task();
                }
            }
            /** @ignore */
            this.clear();
        }
        /** @ignore */
        Queue.prototype.clear = function(){
            this.tasks = [];
        }
    };

    /** @ignore */
    var getQueue = function(queueName){
        var queue = queuesContainer[queueName] || false;
        return queue;
    };

    /** @ignore */
    var createQueue = function(name){
        if(typeof name != 'string') return false;
        var queue = getQueue(name);
        if(!queue){
            queuesContainer[name] = new Queue(name);
            queue = queuesContainer[name];
        }
        return queue;
    };
    /** @ignore */
    var setStatus = function(widgetName,status){
        widgetsLoadingStatus[widgetName] = status;
    };
    /** @ignore */
    var getStatus = function(widgetName){
        var loadingStatus = "unloaded";
        var widgetStatus = widgetsLoadingStatus[widgetName]||false;
        if(!widgetStatus){
            setStatus(widgetName,"unloaded");
        }else{
            loadingStatus = widgetStatus;
        }
        return loadingStatus;

    };

    //Public API
    var publicApi ={
        createOrRetrieveQueue : createQueue,
        setLoadingStatus : setStatus,
        getLoadingStatus : getStatus
    };

    return publicApi;
})();

