﻿if(!dojo._hasResource["cyim.ajax"]){
    dojo._hasResource["cyim.ajax"] = true;
    dojo.provide("cyim.ajax");
    
    dojo.require('cyim.util');
    
    // Charge le contenu d'une url au sein d'un noeud HTML.
    // node: DOMNode        Le noeud dans lequel sera inséré le contenu.
    // url: String          L'URL du contenu à charger.
    // callback: Function   (optionnel) La fonction appelée à la fin du chargement.
    cyim.ajax.loadUrl = function(node, url, callback) {
        dojo.xhrGet({
            url: url,
            load: function(data) {
                cyim.ajax.getDataBack(node, callback, data);
            }
        });
    };
    
    // Poste un formulaire et charge la réponse au sein d'un noeud HTML.
    // node: DOMNode        Le noeud dans lequel sera inséré le contenu.
    // formNode: DOMNode    Le formulaire à envoyer.
    // callback: Function   (optionnel) La fonction appelée à la fin du chargement.
    cyim.ajax.loadForm = function(node, formNode, callback) {
        cyim.ajax.xhrPost({
            form: formNode,
            url: dojo.attr(formNode, 'action'),
            load: function(data) {
                cyim.ajax.getDataBack(node, callback, data);
            }
        });
    };

    // Requête asynchrone précédée d'une vérification des droits d'accès.
    // Si pas de droit d'accès, alors redirection vers la page de login.
    // Sinon, on retourne l'objet xhrPost correspondant à l'URL demandée.
    // le paramètre hasFCKWidget est un booléen qui permet de soumettre les
    //      widgets FCKEditor sinon la valeur ne sera pas soumise
    // checkAlreadyCalled: Boolean    Dit s'il faut faire le check d'appel d'url multiple ou non, si undefined, le test est fait
    cyim.ajax.xhrPost = function(object, hasFCKWidget, checkAlreadyCalled) {
        // raccourci
        var a = cyim.ajax;

        if (hasFCKWidget != undefined) {
            if ((hasFCKWidget == true) || (hasFCKWidget == 1)) {
                //soumission des widgets FCK
                a.submitFCKWidget(object.form);
            }
        }

        // Pour optimiser les appels à checkaccess, on pose créé un champ caché au premier appel
        // Pour les appels suivants, on vérifie la difference par rapport au tout premier appel, si la difference est trop grande, on refera un checkAccess
        var lastCheckAccess = document.getElementById('lastCheckAccessDate');
        var doCheckAccess = false;
        if (lastCheckAccess == undefined) {
            // création champ caché date
            var checkAccessForm = document.createElement('form');
            checkAccessForm.id = 'checkAccessForm';
            checkAccessForm.name = 'checkAccessForm';
            lastCheckAccess = document.createElement('input');
            lastCheckAccess.type = 'hidden';
            lastCheckAccess.name = 'lastCheckAccessDate';
            lastCheckAccess.id = 'lastCheckAccessDate';
            checkAccessForm.appendChild(lastCheckAccess);
            document.getElementsByTagName('body')[0].appendChild(checkAccessForm);
        } else {
            // Vérification si le dernier appel n'est pas trop vieux (5 minutes)
            if (lastCheckAccess.value != undefined && (((new Date()).getTime() - lastCheckAccess.value) < 300000))
                doCheckAccess = true;
        }

        // l'accès est autorisé si l'on a pas besoin de faire un checkaccess
        var accessGranted = !doCheckAccess;
        if (doCheckAccess) {
            // Appel de l'URL de vérification des droits d'accès à l'URL object.url
            var checkurl = object.url;

            // Création d'un formulaire "fictif", on ne soumet (évidemment) pas le formulaire object.form lors de l'appel de vérification des droits d'accès.
            var form = document.createElement('form');
            form.method = 'POST';
            form.action = checkurl; // permet d'avoir une URL absolue (et surtout complète et non pas relative à la page courante)
            form.id = 'emptyAjaxForm';
            document.getElementsByTagName('head')[0].appendChild(form);

            // Appel synchrone de vérification des droits d'accès.
            var d = dojo.xhrPost({ form: 'emptyAjaxForm', url: '/ModuleDirLoginPublic/checkAccess.json?url=' + form.action, handleAs: "text", sync: true });
            var resp = eval('(' + d.results[0] + ')');

            accessGranted = (resp.code == 1)
        }

        // accès autorisé ?
        if (accessGranted) {
            // Si une même url est en cours de traitement, on l'annule
            if (typeof (checkAlreadyCalled) == "undefined" || checkAlreadyCalled) {
                var obj = cyim.ajax._xhrAlreadyCalled(object);
                if (typeof (obj) != "undefined")
                    obj.Cancel();
            }

            var deferred = dojo.xhrPost(object);
            cyim.ajax._addCalledXhr(object, deferred);
            return deferred;
        } else {
            // redirection vers la page de login
            window.location.href = resp.loginPage;

            // retour d'un objet xhrPost non null pour éviter erreur JavaScript dans programme appelant (sur d.addCallback() etc.)
            object.url = resp.loginPage;
            return dojo.xhrPost(object);
        }
    }

    // Tableau de stockage des url appelées pour l'annulation en cas d'appel à plusieurs fois la même url
    // le tableau contiendra des objets de type 'cyim.ajax._calledXhr'
    cyim.ajax._calledXhrs = new Array();

    // Classe représentant une url associée à son objet deferred
    // object:Object      : objet passé en paramètre à la méthode xhr
    // deferred:Deferred  : objet dojo de type deferred renvoyée par la méthode xhrpost
    // arrayPosition:Int  :position dans le tableau ou sera stocké cet objet
    cyim.ajax._calledXhr = function(object, deferred, arrayPosition) {
        var urlWithoutParams = cyim.urlWithoutParams(object.url, false);
        this._url = urlWithoutParams; // url ayant donné l'appel
        this._deferred = deferred; // objet deferred retourné par
        this._arrayPosition = arrayPosition; // position dans le tableau ou sont stockés les appels d'url (optimisation de la suppression)
        this.Cancel = cyim.ajax._cancelCalledUrl; // méthode d'annulation d'appel
    }

    // Annulation de l'appel d'une url
    cyim.ajax._cancelCalledUrl = function() {
        if (typeof (this._deferred) != "undefined") {
            // appel de la méthode cancel du deferred
            this._deferred.cancel();

            // suppression dans le tableau des appels
            cyim.ajax._calledXhrs[this._arrayPosition] = null;
        }
    }

    // Dit si l'url fournie en paramètre a déjà été appelée (en cours de traitement), on suppose que object est défini et contient object.url, défini lui aussi
    // return:Boolean  vrai si l'url a déjà été
    cyim.ajax._xhrAlreadyCalled = function(object) {
        var urlWithoutParams = cyim.urlWithoutParams(object.url, false);

        // recherche dans la liste des xhr appelées
        for (var i = 0; i < cyim.ajax._calledXhrs.length; i++) {
            if (cyim.ajax._calledXhrs[i] != null)
                if (cyim.ajax._calledXhrs[i]._url == urlWithoutParams) {
                return cyim.ajax._calledXhrs[i];
            }
        }
    }

    // Ajoute un traitement d'url
    cyim.ajax._addCalledXhr = function(object, deferred) {
        var objCalledXhr = new cyim.ajax._calledXhr(object, deferred, cyim.ajax._calledXhrs.length);
        cyim.ajax._calledXhrs.push(objCalledXhr);
    }
    

    //nb de scripts externes à charger
    cyim.ajax.ScriptsCountToLoad = 0;

    //compteur des scripts externes chargés
    cyim.ajax.ScriptCounter = 0;

    //les scripts internes ont-ils déja étés chargés
    cyim.ajax.InternalScriptsLoaded = false;
    
    // Fonction de récupération des données provenant d'une requete asynchrone
    //  divElement:domNode               : objet div où sera placé le résultat de la requête asynchrone
    //  callbackCode:String (optionnel)  : code javascript à executer lorsque le HTML est placé dans le DOM et que le javascript est interprété.
    //  data:String                      : HTML provenant de la requête asynchrone
    cyim.ajax.getDataBack = function(divElement, callbackCode, data) {

        var a = cyim.ajax;

        //gestion des arguments passés en fonction de la présence ou non d'un nom de fonction de callback
        data = arguments[arguments.length - 1];
        divElement = arguments[0];
        if (arguments.length > 2) {
            callbackCode = arguments[1];
        } else {
            callbackCode = undefined;
        }
        
        // Supprime les widgets existants
        dojo.query('*[widgetid]', divElement).forEach(function(widgetNode) {
            var widget = dijit.byNode(widgetNode);
            if (widget) {
                widget.destroyRecursive();
            }
        });

        //init des compteurs
        a.ScriptsCountToLoad = 0;
        a.ScriptCounter = 0;
    		a.InternalScriptsLoaded = false;

        //fix pour Safari ne pas enlever
        divElement.innerHTML = '';

        //fix pour IE ne pas enlever
        if (dojo.isIE != undefined && dojo.isIE != 0) {
            divElement.innerHTML = '&nbsp;';
        }

        //on affiche le html asynchrone
        divElement.innerHTML = divElement.innerHTML + data;

        //gestion des styles
        //style présents dans le document
        var docStyles = document.getElementsByTagName('head')[0].getElementsByTagName('link');

        //style présents dans le html généré
        var allstyle = divElement.getElementsByTagName('link');
        for (var z = 0; z < allstyle.length; z++) {
            var lbooExist = false;
            for (var i = 0; i < docStyles.length; i++) {
                if (docStyles[i].href == allstyle[z].href) {
                    lbooExist = true;
                }
            }
            if (!lbooExist) {
                //si le lien vers la css n'existe pas déja, on l'ajout
                document.getElementsByTagName('head')[0].appendChild(allstyle[z]);
            }
        }

        //gestion du javascript
        var allscript = divElement.getElementsByTagName('script');

        //on crée un tablo contenant uniquement les scripts externes
        var srcScripts = new Array;
        for (var j = 0; j < allscript.length; j++) {
            if (allscript[j].src != "") {
                srcScripts.push(allscript[j]);
            }
        }

        //on conserve la taille du tablo des scripts externes
        mnbSrcScripts = srcScripts.length;

        if (mnbSrcScripts == 0) {
            a.externalLoadingFinished(divElement, callbackCode);
        } else {

            a.ScriptsCountToLoad = srcScripts.length;

            //utilisé pour tester si tous les scripts ont déja été chargés
            var atLeastOneScriptNotLoaded = true;

            //on charge d'abord tous les scripts externes
            for (var k = 0; k < srcScripts.length; k++) {

                //ajout du script au head
                var scriptElt = document.createElement('script');
                scriptElt.setAttribute('src', srcScripts[k].src);
                scriptElt.setAttribute('type', 'text/javascript');

                //ajout du script au début du body
                var scriptAlreadyLoaded = false;
                var tabScript = document.getElementsByTagName('head')[0].getElementsByTagName('script');
                for (var z = 0; z < tabScript.length; z++) {
                    if ((tabScript[z].src != undefined) && (tabScript[z].src == scriptElt.src)) {
                        scriptAlreadyLoaded = true;
                        atLeastOneScriptNotLoaded = false;
                    }
                }

                //si le script n'a pas été déja chargé
                if (!scriptAlreadyLoaded) {
    		
                    //ajout du script au DOM
                   // document.getElementsByTagName('head')[0].insertBefore(scriptElt, document.getElementsByTagName('head')[0].childNodes[0]);
                    
                    //si le navigateur est safari, on incrémente directement  le compteur
                    //car les evenements onload ou onreadystatechange ne sont pas déclenchés
                    if (dojo.isSafari) {
                          
                          //pour safari, on charge le script via une requête XMLHttpRequest synchrone pour éviter que les scripts se chargent dans le désordre.
                          var x=new XMLHttpRequest();
											    x.open('GET',srcScripts[k].src,false);
											    x.onreadystatechange=function(){
											        if(x.readyState!=4)return;
											        cyim.globaleval(x.responseText);
											        a.externalLoadingFinished(divElement, callbackCode);
											    }
											    x.send(null);
                        
                    } else {
		                    	                    		
		                    //ajout du script au DOM
		                    document.getElementsByTagName('head')[0].insertBefore(scriptElt, document.getElementsByTagName('head')[0].childNodes[0]);
		
		                    //on demande un callback lors de la fin du chargement
		                    //IE 
		                    var loadFunction = function() {
		                        if (this.readyState == 'loaded' || this.readyState == 'complete') {
		                            a.externalLoadingFinished(divElement, callbackCode);
		                        }
		                    };
		                    scriptElt.onreadystatechange = loadFunction;
		
		                    //FF
		                    scriptElt.onload = function() { a.externalLoadingFinished(divElement, callbackCode); }

                    }
                    	 
                } else {
                    a.ScriptCounter++;
                }
            }

            //si tous les scripts ont déja étés chargés
            if (!atLeastOneScriptNotLoaded) {
                a.ScriptCounter--;
                a.externalLoadingFinished(divElement, callbackCode);
            }
        }

    }

    // Callback de fin de chargement d'un script externe
    // divElement: domNode       Element Html dans lequel la requete a mis les données
    // callbackCode: String      code javascript à executer lorsque le HTML est placé dans le DOM et que le javascript est interprété.
    cyim.ajax.externalLoadingFinished = function(divElement, callbackCode) {
    	
        // raccourci
        var a = cyim.ajax;
        
        //si il existe des scripts externes à charger, on incrémente le compteur
        if (a.ScriptsCountToLoad != 0) {
            a.ScriptCounter++;
        }
    	
        //si le nombre de scripts chargés est égal au script qui viens de se terminer (=> tous les chargements sont faits)
        if ((a.ScriptCounter == a.ScriptsCountToLoad) && (!a.InternalScriptsLoaded)) {

            var allscript = divElement.getElementsByTagName('script');
            for (var j = 0; j < allscript.length; j++) {
                if (allscript[j].src == '') {
                    try {
                        //chargement du script interne
                        cyim.globaleval(allscript[j].text);
                    } catch (e) {
                        alert('error : ' + e.message);
                        console.log(allscript[j].text); // log du script pour le debug
                    }
                }
            }

            //fix pour IE ne pas enlever
            if (dojo.isIE != undefined && dojo.isIE != 0) {
                divElement.innerHTML = divElement.innerHTML.substring(6, divElement.innerHTML.length);
            }

            //on parse la page pour activer les composants dojo générés
            dojo.parser.parse(divElement);
			
						//on a fini de charger les scripts
						a.InternalScriptsLoaded = true;

            //appel de la fonction de callback si définie
            if (callbackCode !== undefined) {
                if (dojo.isFunction(callbackCode))
                {
                    callbackCode.call(divElement);
                }
                else
                {
                    eval(callbackCode);
                }
            }

        }
    }

    //Affiche une erreur lors d'un chargement asynchrone
    cyim.ajax.requestError = function(error) {
        if (error.message != "xhr cancelled")
            alert('error : ' + error.message);
    }

    //fonction de soumission des widgets FCKEditor
    //parcours les widgets et assigne la valeur de l'editeur à l'objet DOM
    cyim.ajax.submitFCKWidget = function(formName) {
        var firstwidget = null;
        dojo.forEach(dijit.byId(formName).getDescendants(), function(widget) {
            if (widget.declaredClass == 'cyim.dojo.widgets.FCKEditor') {
                if (document.getElementById(widget.id) != undefined) {
                    document.getElementById(widget.id).value = widget.getValue();
                }
                widget._destroy();
            }
        });
    }
    
    
    // Gestion de l'historique des états de la page.
    cyim.ajax.history = {
        add: function(key, value) {
            // summary: Ajoute ou met à jour une valeur d'état à l'historique.
            
            var hashParts = this.toObject(window.location.hash);
            hashParts[key] = value;
            this.toHash(hashParts);
        },
        remove: function(key) {
            // summary: Supprime la clef correspondant à l'état indiqué.
            
            var hashParts = this.toObject(window.location.hash);
            delete hashParts[key];
            this.toHash(hashParts);
        },
        read: function(key) {
            // summary: Retourne la valeur de la clef dans l'état actuel.
            
            var hashParts = this.toObject(window.location.hash);
            return hashParts[key] || null;
        },
        toObject: function(hash) {
            // summary: Retourne le tableau associatif des (clefs, valeurs).

            var hashParts = {};
            var history = (hash || '#').substr(1);
            if (history) {
	            var properties = history.split('&');
	            for (var p = 0; p < properties.length; p++) {
		            var component = properties[p].split('=');
		            if (component.length == 2) {
		                hashParts[decodeURIComponent(component[0])] = decodeURIComponent(component[1]);
		            }
	            }
            }
            return hashParts;
        },
        toHash: function(historyObject) {
            // summary: Convertit un tableau associatif (clefs, valeurs) en un nouvel état.

            var properties = [];
	        for (key in historyObject) {
		        if (historyObject[key]) {
			        properties.push(encodeURIComponent(key) + '=' + encodeURIComponent(historyObject[key]));
		        }
	        }
	        this._previousHash = '#' + properties.join('&');
            window.location.hash = this._previousHash;
            if (this._ieIFrame) {
                var iframe = this._ieIFrame.contentDocument || this._ieIFrame.contentWindow.document;
	            iframe.open();
	            iframe.close();
                iframe.location.hash = this._previousHash;
            }
        },
        
        // onChange: l'évènement publié lors d'un changement de l'historique.
        onChange: 'cyim.ajax.history.onChange',
        _ieIFrame: null,
        _previousHash: '',
        _check: function() {
            // summary: Vérifie que le hash de l'url a changé.
            if (this._ieIFrame) {
                var iframe = this._ieIFrame.contentDocument || this._ieIFrame.contentWindow.document;
                if (this._previousHash != (iframe.location.hash || '#')) {
                    var oldHash = this._previousHash;
                    this._previousHash = (iframe.location.hash || '#');
                    window.location.hash = this._previousHash;
                    dojo.publish(cyim.ajax.history.onChange, [this._previousHash, oldHash]);
                }
            } else if (this._previousHash != (window.location.hash || '#')) {
                var oldHash = this._previousHash;
                this._previousHash = (window.location.hash || '#');
                if (this._ieIFrame) {
                    var iframe = this._ieIFrame.contentDocument || this._ieIFrame.contentWindow.document;
                    iframe.location.hash = this._previousHash;
                }
                dojo.publish(cyim.ajax.history.onChange, [this._previousHash, oldHash]);
            }
        },
        _init: function() {
            // summary: Initialise la gestion de l'historique.
            
            this._previousHash = window.location.hash || '#';
            // adds the iframe for ie
            if (dojo.isIE) {
                this._ieIFrame = dojo.doc.createElement('iframe');
                this._ieIFrame.style.display = 'none';
                dojo.body().appendChild(this._ieIFrame);
                var iframe = this._ieIFrame.contentDocument || this._ieIFrame.contentWindow.document;
	            iframe.open();
	            iframe.close();
                iframe.location.hash = this._previousHash;
            }
            // registers the check function
            window.setInterval(dojo.hitch(this, this._check), 100);
        }
    };
    dojo.addOnLoad(function() {
        cyim.ajax.history._init();
    });

}