(function() {
    var 
    // Will speed up references to window, and allows munging its name.
	window = this;

    jtti = {
        //initialisation automatically call
        init: function() {
            // get the url folder
            var path = location + "";
            jtti.data.url.folder = path = path.substr(0, path.lastIndexOf("/") + 1);
            jtti.data.url.commandFolder = jtti.data.url.folder;
			jtti.data.url.templateFolder = jtti.data.url.folder + jtti.template.data.config.folder;
            jtti.data.url.templateDomSelector = ".js_tWarehouse";
        },
        strings: {

    },
    // core data
    data: {
        url: {
            //folder of page
            folder: "",
			commandFolder: "",
            //folder of templates
            templateFolder: "",
            templateDomSelector: ""
        }
    },
    loading: {
        ajax: {
            data: {
                total: 0,
                complete: 0,
                fail: 0,
                callback: [],
                callbackError: [],
                unikID: 0
            },
            fn: {
                queryError: function(fnCallback) {
                    idCallback = jtti.loading.ajax.data.unikID++;
                    idCallback = jtti.loading.ajax.data.length;
                    jtti.loading.ajax.data.callbackError[idCallback] = fnCallback;
                    return idCallback;
                },
                query: function(fnCallback) {
                    idCallback = jtti.loading.ajax.data.unikID++;
                    idCallback = jtti.loading.ajax.data.length;
                    jtti.loading.ajax.data.callback[idCallback] = fnCallback;
                    return idCallback;
                },
                add: function() {
                    jtti.loading.ajax.data.total++;
                    jtti.loading.ajax.dontUse.launchCallback();
                },
                complete: function() {
                    jtti.loading.ajax.data.complete++;
                    jtti.loading.ajax.dontUse.launchCallback();
                },
                fail: function(json) {
                    jtti.loading.ajax.data.fail++;
                    jtti.loading.ajax.dontUse.launchCallbackError(json);
                    jtti.loading.ajax.dontUse.launchCallback();
                }
            },
            dontUse: {
                launchCallback: function() {
                    for (var iCallback in jtti.loading.ajax.data.callback) {
                        if (jtti.loading.ajax.data.callback[iCallback]) {
                            jtti.loading.ajax.data.callback[iCallback](jtti.loading.ajax.data.total, jtti.loading.ajax.data.complete, jtti.loading.ajax.data.fail);
                        }
                    }
                },
                launchCallbackError: function(json) {
                    for (var iCallback in jtti.loading.ajax.data.callbackError) {
                        if (jtti.loading.ajax.data.callbackError[iCallback]) {
                            jtti.loading.ajax.data.callbackError[iCallback](json);
                        }
                    }
                }
            }
        }
    },
    canvas: {
        data: {
            lib: [],
            canvaslist: []
        },
        fn: {
            // description : get a canvas structure.
            // parameter : canvasName //name of the canvas
            // return : jsonCanvasStructure (see jtti.canvas.dontUse.fn.createCanvasStructure method)
            query: function(canvasName) {
                canvas_root = jtti.canvas.data.canvaslist[canvasName];
                if (canvas_root == undefined) {
                    canvas = jtti.canvas.dontUse.fn.createCanvasStructure(canvasName);
                    return canvas;
                }
                return canvas_root.canvas;
            },
            // description : prepare a canvas to be used, bind javascript on html content
            // parameter : canvasNameOrRef // name of the canvas to prepare
            prepare: function(canvasNameOrRef) {
                var canvas_ref = jtti.canvas.dontUse.fn.find(canvasNameOrRef);
                //prepare Expander
                jtti.canvas.dontUse.fn.toPrepare.expander(canvas_ref);

                //stop plugins
                jtti.canvas.dontUse.fn.plugins.stopPlugins(canvas_ref);

            },
            complete: function(canvasNameOrRef) {
                var canvas_ref = jtti.canvas.dontUse.fn.find(canvasNameOrRef);
                //stop plugins
                jtti.canvas.dontUse.fn.plugins.stopPlugins(canvas_ref);

                //Start onLoad functionnalities
                onLoadParam = {
                    config: canvas_ref
                }
                jtti.canvas.dontUse.fn.plugins.loader.launch(canvas_ref);
                canvas_ref.event.command.onLoad(onLoadParam);

                var param = canvas_ref.update.param ? canvas_ref.update.param : canvas_ref.command.param;
                jtti.canvas.fn.update(canvas_ref.name, canvas_ref.command.name, param,
                    function(canvas_ref) {
                        //selfBind of html content
                        jtti.canvas.dontUse.fn.plugins.loader.stop(canvas_ref.config);
                        jtti.canvas.dontUse.fn.plugins.setContent.launch(canvas_ref);
                        canvas_ref.config.event.command.onSucceed(canvas_ref);
                    }, function(canvas_ref) {
                        jtti.canvas.dontUse.fn.plugins.loader.stop(canvas_ref.config);
                        jtti.canvas.dontUse.fn.plugins.setError.launch(canvas_ref.config);
                        canvas_ref.config.event.command.onFail(canvas_ref);
                    });

            },
            // description: query data, strings, template in order to update a canvas
            // parameter : canvasName //name of the canvas, must be declared with add method
            // parameter : webService //webService to query data from server
            // parameter : jsParameter //json data posted to webService
            // parameter : fnCallback(canvas) // function called when update finished his work
            // callBack parameter : canvas // json description bellow
            /*
            {
            strings: json //strings data
            template: object //preProcessed template
            data: json //data requested from webService
            html: html //processed template
            }
            */
            update: function(canvasName, webService, jsParameter, fnCallback, fnError) {
                // get informations reference
                if (typeof (canvasName) == typeof ({})) {
                    canvasName = canvasName.name;
                }




                var canvas = jtti.canvas.data.canvaslist[canvasName].canvas;


                // check if canvas is cached
                if (canvas.status.cached) {
                    jtti.ajax.fn.json(webService, jsParameter, function(data) {
                        jtti.depends.template.fn.need(canvas, function() {
                            var json = {
                                template: jtti.depends.template.data.lib[canvas.content.template.name],
                                data: data,
                                config: jtti.canvas.fn.query(canvasName)
                            };
                            jtti.template.fn.process(json, function(html) {
                                json.html = html;
                                fnCallback(json);
                            }, canvas.content.template.htmlCache);
                        });
                    }, function(data) {
                        data.config = jtti.canvas.fn.query(canvasName);
                        fnError(data);
                    }, canvas.command.keepCache);
                } else {
                    jtti.canvas.dontUse.fn.cacheUpdate(canvasName, webService, jsParameter, function(data) {
                        var json = {
                            strings: {},
                            template: data["template"],
                            data: data["data"],
                            config: jtti.canvas.fn.query(canvasName)
                        };
                        if (data["strings"]) {
                            json.strings = data["strings"];
                        }
                        jtti.template.fn.process(json, function(html) {
                            json.html = html;
                            fnCallback(json);
                        }, jtti.canvas.fn.query(canvasName).content.template.htmlCache);
                    }, function(data) {
                        data.config = jtti.canvas.fn.query(canvasName);
                        fnError(data);
                    });
                }

            },
            // description: configure a canvas
            /* parameter: json
            {
            canvas:"canvasName", //must be unique
            template:"templateName" //template name is the template file name without extension, template must be in a tpl folder
            }
            */
            add: function(json) {
                //check if canvas exist
                if (jtti.canvas.data.lib[json.canvas]) {
                    jtti.canvas.data.lib[json.canvas] = null;
                }
                //configure canvas
                json.cached = false;
                jtti.canvas.data.lib[json.canvas] = json;
            },
            // description: query all cached data of a canvas which has been configured with add
            // parameter: canvasName // name of an added canvas
            // parameter: fnCallback(canvas) // fnCallback is call when cache is done
            // callback parameter : canvas // json description bellow
            /*
            {
            strings: json //strings data
            template: object //preProcessed template
            }
            */
            cache: function(canvasName, fnCallback, fnError) {
                // get informations reference
                var canvas = jtti.canvas.data.canvaslist[canvasName].canvas
                // check if template is already cached
                if (canvas.status.cached) {
                    var json = {
                        template: jtti.depends.template.data.lib[canvas.content.template.name]
                    };
                    fnCallback(json);
                } else {
                    jtti.canvas.dontUse.fn.cacheUpdate(canvasName, "", "", function(data) {
                        var json = {
                            strings: {},
                            template: data["template"]
                        };
                        if (data["strings"]) {
                            json.strings = data["strings"];
                        }
                        fnCallback(json);
                    });
                }
            }
        },
        dontUse: {
            fn: {
                find: function(canvasNameOrRef) {
                    var canvas_ref = {};
                    if (typeof (canvasNameOrRef) == typeof ("string")) {
                        canvas_ref = jtti.canvas.fn.query(canvasNameOrRef);
                    } else {
                        canvas_ref = canvasNameOrRef;
                    }
                    return canvas_ref;
                },
                //description: group all method called by prepare function
                toPrepare: {
                    expander: function(canvas_ref) {
                        if (canvas_ref.expander.activate) {
                            //expander Activation
                            jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.triggerRef).show();
                            //Be collapsed or expended ?
                            if (canvas_ref.expander.status == "collapsed") {
                                jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.toCollapseRef).hide();
                                jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.triggerRef + " .canvasExpanderPicto").removeClass("expanded").addClass("collapsed");
                                canvas_ref.event.expander.onHide(canvas_ref);
                            } else {
                                jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.toCollapseRef).show();
                                jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.triggerRef + " .canvasExpanderPicto").removeClass("collapsed").addClass("expanded");
                                canvas_ref.event.expander.onShow(canvas_ref);
                            }
                            //Expand/Collapse event
                            jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.triggerRef).click(function() {
                                if (canvas_ref.expander.activate) {
                                    jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.toCollapseRef).toggle();
                                    if (jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.toCollapseRef).is(':visible')) {
                                        jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.triggerRef + " .canvasExpanderPicto").removeClass("collapsed").addClass("expanded");
                                        canvas_ref.event.expander.onShow(canvas_ref);
                                    } else {
                                        jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.triggerRef + " .canvasExpanderPicto").removeClass("expanded").addClass("collapsed");
                                        canvas_ref.event.expander.onHide(canvas_ref);
                                    }
                                }
                            });
                        } else {
                            jQuery("#" + canvas_ref.name + " " + canvas_ref.expander.triggerRef).hide();
                        }
                    }
                },
                plugins: {
                    setError: {
                        launch: function(canvas_ref) {
                            if (canvas_ref.setError.activate) {
                                jQuery("" + canvas_ref.setError.JQueryRef).addClass(canvas_ref.setError.addCssClass);
                                jQuery("" + canvas_ref.setError.JQueryRef).html(canvas_ref.setError.html);
                            }
                        },
                        stop: function(canvas_ref) {
                            if (canvas_ref.setError.activate) {
                                jQuery("" + canvas_ref.setError.JQueryRef).removeClass(canvas_ref.setError.addCssClass);
                                jQuery("" + canvas_ref.setError.JQueryRef).html("");
                            }
                        }
                    },
                    setContent: {
                        launch: function(canvas_ref) {
                            if (canvas_ref.config.setContent.activate) {
                                jQuery("" + canvas_ref.config.setContent.JQueryRef).html(canvas_ref.html);
                            }
                        }
                    },
                    loader: {
                        launch: function(canvas_ref) {
                            if (canvas_ref.loader.activate) {
                                //alert("loader "+canvas_ref.loader.JQueryRef);
                                jQuery(canvas_ref.loader.JQueryRef).addClass(canvas_ref.loader.addCssClass);
                                jQuery(canvas_ref.loader.JQueryRef).html(canvas_ref.loader.html)
                            }
                        },
                        stop: function(canvas_ref) {
                            if (canvas_ref.loader.activate) {
                                jQuery(canvas_ref.loader.JQueryRef).removeClass(canvas_ref.loader.addCssClass);
                                jQuery(canvas_ref.loader.JQueryRef).html("");
                            }
                        }
                    },
                    stopPlugins: function(canvas_ref) {
                        jtti.canvas.dontUse.fn.plugins.loader.stop(canvas_ref);
                        jtti.canvas.dontUse.fn.plugins.setError.stop(canvas_ref);
                    }
                },
                canvasDuplication: function(sourceName, destinationName) {
                    //créer une fonction récursive pour le clonage d'objet
                    destination = jtti.canvas.fn.query(destinationName);
                    source = jtti.canvas.fn.query(sourceName);
                    destination = jtti.plugins.fn.clone(source);
                    destination.name = destinationName;

                    return jtti.canvas.data.canvaslist[destinationName].canvas;
                },
                // description: create a canvas structure and add it into the jtti.canvas.data.canvaslist list
                // paramter : canvasName //name of the canvas
                createCanvasStructure: function(canvasName) {
                    jtti.canvas.data.canvaslist[canvasName] = new Object();
                    jtti.canvas.data.canvaslist[canvasName].canvas = {
                        "name": canvasName,
                        "command": {
                            "name": "",
                            "keepCache": true,
                            "param": {}
                        },
                        "expander": {
                            "activate": true,
                            "triggerRef": ".canvasExpander",
                            "toCollapseRef": ".display",
                            "status": "collapsed"
                        },
                        "loader": {
                            "activate": false,
                            "JQueryRef": "#" + canvasName,
                            "html": "",
                            "addCssClass": "loading"
                        },
                        "setError": {
                            "activate": false,
                            "JQueryRef": "#" + canvasName,
                            "html": "",
                            "addCssClass": "error"
                        },
                        "setContent": {
                            "activate": false,
                            "JQueryRef": "#" + canvasName
                        },
                        "event": {
                            "template": {
                                "preProcess": function(json) { return json }
                            },
                            "command": {
                                "onLoad": function(ref) { },
                                "onSucceed": function(ref) { },
                                "onFail": function(ref) { }
                            },
                            "expander": {
                                "onShow": function(ref) { },
                                "onHide": function(ref) { }
                            }
                        },
                        "status": {
                            "cached": false
                        },
                        "content": {
                            "template": {
                                "name": "",
                                "htmlCache": false
                            }
                        },
                        "update": { //not used anymore.
                            "param": null
                        }
                    };
                    return jtti.canvas.data.canvaslist[canvasName].canvas;
                },
                cacheUpdate: function(canvasName, webService, jsParameter, fnCallback, fnError) {
                    // get informations reference
                    var canvas = jtti.canvas.data.canvaslist[canvasName].canvas

                    var unikID = jtti.callback.parallel.fn.start();
                    //set up dependence
                    //DEPRECATED -- set up strings dependence
                    //jtti.callback.parallel.fn.add(unikID, "strings"); 
                    jtti.callback.parallel.fn.add(unikID, "template");
                    if (webService != "") {
                        jtti.callback.parallel.fn.add(unikID, "data");
                    }
                    jtti.callback.parallel.fn.canDone(unikID);
                    //DEPRECATED -- get strings data
                    /*jtti.strings.fn.need(canvas.strings, canvas.template, function(strings) {
                    jtti.callback.parallel.fn.complete(unikID, "strings", strings)
                    });*/
                    // get template data
                    jtti.depends.template.fn.need(canvas, function(processedTemplate) {
                        jtti.callback.parallel.fn.complete(unikID, "template", processedTemplate)
                    });
                    if (webService != "") {
                        // get information data
                        jtti.ajax.fn.json(webService, jsParameter, function(informations) {
                            jtti.callback.parallel.fn.complete(unikID, "data", informations)
                        }, fnError, canvas.command.keepCache);
                    }

                    jtti.callback.parallel.fn.done(unikID, function(data) {
                        canvas.status.cached = true;
                        fnCallback(data);
                    });
                }
            }
        }
    },
    //callback used cause ajax is asynchrone. Musn't be used by user
    callback: {
        data: {
            //reference all ajax call by a label
            requesting: [],
            //reference all callback method callbackStack[requestingLabel][n] = methodReference
            callbackStack: [],
            //if callback are launching we musn't clean it
            callbackMutex: []
        },
        fn: {
            //check if our ajax call is already running
            check: function(strLabel) {
                if (jtti.callback.data.requesting[strLabel]) {

                    return true;
                } else {
                    // Response is get so we check if all callback has been launched in order to clean it
                    if (jtti.callback.data.callbackMutex[strLabel]) {
                        jtti.callback.data.callbackStack[strLabel] = null;
                    }
                    jtti.callback.data.callbackMutex[strLabel] = false;
                    return false;
                }
            },
            //This method reference callback method and launch ajax if it's not already launched
            request: function(strLabel, fnCallback, fnError, fnRequest) {
                if (jtti.callback.fn.check(strLabel)) {
                    //add function to callback stack
                    jtti.callback.fn.addCallback(strLabel, fnCallback, fnError);
                    //skip fn request (skip ajax call)
                } else {
                    //add function to callback stack
                    jtti.callback.fn.addCallback(strLabel, fnCallback, fnError);
                    //launch request (launch ajax call)
                    jtti.callback.data.requesting[strLabel] = true;
                    fnRequest();
                }
            },
            //add a callback in stack depending of the ajax request symbolized by strLabel
            addCallback: function(strLabel, fnCallback, fnError) {
                if (!jtti.callback.data.callbackStack[strLabel]) {
                    jtti.callback.data.callbackStack[strLabel] = [];
                }
                iCallback = jtti.callback.data.callbackStack[strLabel].length;
                jtti.callback.data.callbackStack[strLabel][iCallback] = { success: fnCallback, error: fnError };
            },
            //launch all callback associated to a requestLabel(strLabel)
            launchCallback: function(strLabel, data) {
                //clean stack
                jtti.callback.data.requesting[strLabel] = false;
                for (var iCallback in jtti.callback.data.callbackStack[strLabel]) {
                    //check if callback is active
                    if (jtti.callback.data.callbackStack[strLabel][iCallback]) {
                        //get callback reference
                        refCallback = jtti.callback.data.callbackStack[strLabel][iCallback].success;
                        //unset the callback
                        jtti.callback.data.callbackStack[strLabel][iCallback] = null;
                        if (refCallback != null) {
                            refCallback(data);
                        }
                    }
                }
                jtti.callback.data.callbackMutex[strLabel] = true;
            },
            //launch all error callback associated to a requestLabel(strLabel)
            launchError: function(strLabel, data) {
                //clean stack
                jtti.callback.data.requesting[strLabel] = false;
                for (var iCallback in jtti.callback.data.callbackStack[strLabel]) {
                    //check if callback is active
                    if (jtti.callback.data.callbackStack[strLabel][iCallback]) {
                        //get callback reference
                        refCallback = jtti.callback.data.callbackStack[strLabel][iCallback].error;
                        //unset the callback
                        jtti.callback.data.callbackStack[strLabel][iCallback] = null;
                        if (refCallback != null) {
                            refCallback(data);
                        }
                    }
                }
                jtti.callback.data.callbackMutex[strLabel] = true;
            }

        },
        //this part permit user to put dependance to add dependance of a custom callback
        parallel: {
            data: {
                group: [],
                canDone: [],
                callBack: [],
                unikID: 0
            },
            fn: {
                //description: get an unique id to put in strGroup
                //return: int unikID
                //TODO rename in create
                start: function() {
                    return jtti.callback.parallel.data.unikID++;
                },
                //description: add a new depedency
                //parameter: strGroup //pass unikID to this parameter
                //parameter: strDepedency //pass a string which represent the name of the depedency like 'data' or 'myDependency' or any label you want
                add: function(strGroup, strDependency) {
                    if (!jtti.callback.parallel.data.group[strGroup]) {
                        jtti.callback.parallel.data.group[strGroup] = [];
                    }
                    jtti.callback.parallel.data.group[strGroup][strDependency] = "_Empty_";
                },
                //description: call this method when the depedency is getted
                //parameter: strGroup //pass unikID to this parameter
                //parameter: strDependency //pass the dependency
                //parameter: data //pass data you which use in done callback method
                complete: function(strGroup, strDependency, data) {
                    jtti.callback.parallel.data.group[strGroup][strDependency] = data;
                    //check if all needs are declared
                    if (jtti.callback.parallel.data.canDone[strGroup] == true) {
                        //check if all asynchronous call have finished
                        allDone = true;
                        for (var strComplete in jtti.callback.parallel.data.group[strGroup]) {
                            if (jtti.callback.parallel.data.group[strGroup][strComplete] == "_Empty_") {
                                allDone = false;
                            }
                        }
                        //launch callback
                        if (allDone) {
                            for (var iCallback in jtti.callback.parallel.data.callBack[strGroup]) {
                                jtti.callback.parallel.data.callBack[strGroup][iCallback](jtti.callback.parallel.data.group[strGroup]);
                            }
                            //clean all
                            jtti.callback.parallel.data.group[strGroup] = null;
                            jtti.callback.parallel.data.canDone[strGroup] = null;
                            jtti.callback.parallel.data.callBack[strGroup] = null;
                        }
                    }
                },
                //description: this method indicate you have declared all dependency. Call this method after all add method, but before complete method.
                //parameter: strGroup //pass unikID to this parameter
                //start
                canDone: function(strGroup) {
                    jtti.callback.parallel.data.canDone[strGroup] = true;
                },
                //description: this method call the callback function when all complete method have been called.
                //parameter: strGroup //pass unikID to this parameter
                //parameter: fnCallback(array) //callback method called when all dependency are get. see bellow for array description
                /*
                array[strDependency] = data
                */
                done: function(strGroup, fnCallback) {
                    if (!jtti.callback.parallel.data.callBack[strGroup]) {
                        jtti.callback.parallel.data.callBack[strGroup] = [];
                    }
                    nbCallback = jtti.callback.parallel.data.callBack[strGroup].length;
                    jtti.callback.parallel.data.callBack[strGroup][nbCallback] = fnCallback;

                }
            }
        }
    },
    //regroup all ajax method with depedency all callback method
    ajax: {
        data: {
            //task id, will be added to all business ajax call
            taskID: null,
            cachedCommand: []
        },
        fn: {
            url: function(url, fnCallback, fnError) {
                var identification = "jtti.ajax.fn.url." + url;
                jtti.callback.fn.request(identification, fnCallback, fnError, function() {
                    var debug = {
                        method: "jtti.ajax.fn.url.",
                        url: url
                    }
                    jtti.loading.ajax.fn.add();
                    jQuery.ajax({
                        url: url,
                        success: function(data) {
                            jtti.loading.ajax.fn.complete();
                            jtti.callback.fn.launchCallback(identification, data);
                        },
                        error: function(args) {
                            var data = {};
                            data.debug = debug;
                            data.debug.JQargs = args;
                            jtti.callback.fn.launchError(identification, data);
                            jtti.loading.ajax.fn.fail(data.debug);
                        }
                    });
                });
            },
            //description: send a json request
            //parameter ServiceDescriptor : the service type or the service key that will be used
            //to build the ICommandService with the AbstractFactory
            //parameter data : the data parameter that should be passed to the 
            //ICommandService.Execute(…) method, else ‘’ (empty string). This data parameter will 
            //be deserialized into the DataEventArgs<TData>.Data property of the ICommandService //EventArgs, if this one is of type TTI.Library.Data.IDataEventArgs
            //fnCallback(result) : callback method called when ajax response is get, the result 
            //will be the ResultEventArgs<TResult>.Result property if the ICommandService 
            //EventArgs is of type TTI.Library.Data.IResultEventArgs
            //fnError() : Not yet implemented
            json: function(serviceDescriptor, data, fnCallback, fnError, keepInCache) {
                //preprocess parameters
                var serviceDescriptor = "AjaxCommandHttpHandler.ashx?ServiceDescriptor=" + serviceDescriptor;
				serviceDescriptor = jtti.data.url.commandFolder + serviceDescriptor;
                if (jtti.ajax.data.taskID) {
                    serviceDescriptor = serviceDescriptor + "&taskId=" + jtti.ajax.data.taskID;
                }
                if (data == "") {
                    data = {};
                }
                //query identification name
                jtti.depends.js.fn.need('json2', function() {
                    var identification = "jtti.ajax.fn.json." + serviceDescriptor + JSON.stringify({ json: data });
                    if (keepInCache) {
                        if (jtti.ajax.data.cachedCommand[identification]) {
                            fnCallback(jtti.ajax.data.cachedCommand[identification]);
                        } else {
                            contactServer();
                        }
                    } else {
                        contactServer();
                    }

                    function contactServer() {
                        jtti.callback.fn.request(identification, fnCallback, fnError, function() {
                            var debug = {
                                method: "jtti.ajax.fn.json.",
                                url: serviceDescriptor,
                                data: data
                            };
                            jtti.loading.ajax.fn.add();
                            jQuery.ajax({
                                type: "POST",
                                contentType: "application/json; charset=utf-8",
                                url: serviceDescriptor,
                                data: JSON.stringify(data),
                                dataType: "json",
                                success: function(data) {
                                    jtti.loading.ajax.fn.complete();
                                    if (data == null) {
                                        data = {};
                                    }
                                    if (data.__IsServerSideException) {
                                        data.debug = debug;
                                        jtti.callback.fn.launchError(identification, data);
                                        jtti.loading.ajax.fn.fail(data.debug);
                                    } else {
                                        jtti.ajax.data.cachedCommand[identification] = data;
                                        jtti.callback.fn.launchCallback(identification, data);
                                    }
                                },
                                error: function(args) {
                                    var data = {};
                                    data.debug = debug;
                                    data.debug.JQargs = args;
                                    jtti.callback.fn.launchError(identification, data);
                                    jtti.loading.ajax.fn.fail(data.debug);
                                }
                            });
                        });
                    }
                });
            }
        }
    },
    template: {
        data: {
            config: {
                folder: "tpl"
            },
            processedTemplates: []
        },
        fn: {
            isHtmlCache: function(canvas_ref) {
                var cacheID = canvas_ref.name + canvas_ref.content.template.name + JSON.stringify({ data: canvas_ref.command.param });
                if (jtti.template.data.processedTemplates[cacheID]) {
                    return true;
                } else {
                    return false;
                }
            },
            getHtmlCache: function(canvas_ref) {
                if (jtti.template.fn.isHtmlCache(canvas_ref)) {
                    var cacheID = canvas_ref.name + canvas_ref.content.template.name + JSON.stringify({ data: canvas_ref.command.param });
                    return jtti.template.data.processedTemplates[cacheID];
                } else {
                    return false;
                }
            },
            //description: process template with data
            //parameter: template //preprocessed template
            //parameter: jsData //json data to use in template
            //parameter: fnCallback(html) //callback method called when template has processed html code
            process: function(json, fnCallback, keepCache) {
                var html = null;


                if (keepCache) {
                    jtti.depends.js.fn.need('json2', function() {
                        var html = "";
                        cacheID = json.config.name + json.config.content.template.name + JSON.stringify({ data: json.config.command.param })
                        //call method to process template
                        if (jtti.template.data.processedTemplates[cacheID]) {
                            html = jtti.template.data.processedTemplates[cacheID];
                        } else {
                            json = jtti.canvas.fn.query(json.config.name).event.template.preProcess(json);
                            html = json.template.process({ data: json.data, strings: jtti.strings, config: json.config });
                            jtti.template.data.processedTemplates[cacheID] = html;
                        }
                        fnCallback(html);
                    });
                } else {
                    json = jtti.canvas.fn.query(json.config.name).event.template.preProcess(json);
                    html = json.template.process({ data: json.data, strings: jtti.strings, config: json.config });
                    fnCallback(html);
                }
            }
        }
    },
    // JMenu intégration
    jMenu: {
        //JMenu Verions selectors
        v1: {
            data: {
            //no data
        },
        fn: {
            jMenu: function(config_ref) {
                jtti.depends.js.fn.need('jMenu', function() {
                    jMenu_TaskID = jtti.ajax.data.taskID;
                    jMenu(config_ref);
                });
            }
        }
    },
    v2: {
        data: {
        //no data
    },
    fn: {
        jMenu: function(config_ref) {
            jtti.depends.js.fn.need('jMenu-v2', function() {
                jM.data.taskID = jtti.ajax.data.taskID;
                jMenuV2(config_ref);
            });
        }
    }
},
latest: {
    data: {
    //no data
},
fn: {
    jMenu: function(config_ref) {
        jtti.jMenu.v2.fn.jMenu(config_ref);
    }
}
}
},
// plugin gesture. Use to include JS only if their used
plugins: {
    data: {

},
fn: {
    // prepare a list to query plugins
    // fnReadyCallback start when all plugins are obtained from server
    prepare: function(pluginList, fnReadyCallback) {
        var unikID = jtti.callback.parallel.fn.start();
        for (key = 0; key < pluginList.length; key++) {
            jtti.callback.parallel.fn.add(unikID, pluginList[key]);
        }
        jtti.callback.parallel.fn.canDone(unikID);
        for (key = 0; key < pluginList.length; key++) {
            jtti.depends.js.fn.need(pluginList[key], function(plugin) {
                jtti.callback.parallel.fn.complete(unikID, plugin, null);
            });
        }

        jtti.callback.parallel.fn.done(unikID, function(data) {
            fnReadyCallback(data);
        });
    },
    clone: function(obj) {
        if (obj == null || typeof (obj) != 'object')
            return obj;

        var temp = obj.constructor(); // changed

        for (var key in obj)
            temp[key] = jtti.plugins.fn.clone(obj[key]);
        return temp;
    }
}
},
// get required libs
depends: {
    // templates dependencies
    template: {
        data: {
            //contain preprocessed templates
            lib: []
        },
        fn: {
            //erase all tamplates. Used when user language is changed.
            flush: function() {
                jtti.depends.template.data.lib = [];
            },
            //description: download the template file if not exist
            //parameter: jsonCanvas //represent the canvas
            //parameter: fnCallback(template) //callback method called when template is get from server and preprocessed
            need: function(jsonCanvas, fnCallback, fnError) {
                // test if template is already loaded
                if (jtti.depends.template.data.lib[jsonCanvas.content.template.name]) {
                    fnCallback(jtti.depends.template.data.lib[jsonCanvas.content.template.name]);
                } else {
                    var tSource = "";
                    //process template classe name
                    var tClassName = jsonCanvas.content.template.name;
                    tClassName = tClassName.replace(".", "_");
                    var tSource_ref = jQuery(jtti.data.url.templateDomSelector + " .tSource_" + tClassName);
                    //check if template is embedded in page
                    if (tSource_ref.length) {
                        tSource = tSource_ref.html();
                        tSource = tSource.replace("<!--", "");
                        tSource = tSource.replace("-->", "");
                    }
                    //if template isn't embedded, try to download it
                    if (tSource == "") {
                        //todo : check if strName is absolute
                        urlTemplate = jtti.data.url.templateFolder + "/" + jsonCanvas.content.template.name;
                        var identification = "jtti.depends.template.fn.need." + jsonCanvas.content.template.name;
                        var debug = {
                            method: "jtti.depends.template.fn.need.",
                            url: urlTemplate,
                            data: jsonCanvas
                        };

                        var success = function(data) {
                            jtti.depends.js.fn.need('trimPath', function() {
                                //store the template
                                template = TrimPath.parseTemplate(data);
                                jtti.depends.template.data.lib[jsonCanvas.content.template.name] = template;
                                fnCallback(template);
                            });
                        };

                        var error = function(data) {
                            data.debug = debug;
                            fnError(data)
                        };

                        //var canvasDomReference = jQuery(jtti.data.url.templateDomSelector + " #" + jsonCanvas.name);

                        if (jtti.data.url.templateFolder != null) {
                            jtti.ajax.fn.url(urlTemplate, success, error);
                        } else {
                            error();
                        }
                    } else {
                        jtti.depends.js.fn.need('trimPath', function() {
                            template = TrimPath.parseTemplate(tSource);
                            jtti.depends.template.data.lib[jsonCanvas.content.template.name] = template;
                            fnCallback(template);
                        });
                    }
                }
            }
        }
    },
    // js dependencies
    js: {
        //data
        data: {
            //TODO : make libelle constant jtti.constant.jMenu
            lib: {
                'trimPath': { path: '/library/include/js/jquery/template.js', test: function() { return window.TrimPath } },
                'jMenu': { path: '/library/include/js/jquery/jMenu.js', test: function() { return window.jMenu } },
                'jMenu-v2': { path: '/library/include/js/jquery/jMenu_2.js', test: function() { return window.jMenuV2 } },
                'thickbox': { path: '/library/include/js/thickbox/thickbox.asp', test: function() { return window.tb_init } },
                'json2': { path: '/library/include/js/jquery/json2.js', test: function() { return window.JSON } },
                'jsonT': { path: '/library/include/js/jquery/jsont.js', test: function() { return window.jsonT } },
                'date$': { path: '/library/include/js/jquery/jttiAdds/libDate.js', test: function() { return window.date$ } },
                'number$': { path: '/library/include/js/jquery/jttiAdds/libNumber.js', test: function() { return window.number$ } }
            }
        },
        //functions
        fn: {
            //description: query javascript from server, so javascript is only downloaded when we would like to use it
            //parameter: strName //represent js file to get (trimPath, jMenu or json2)
            //parameter: fnCallback() //method called when javascript is query
            need: function(strName, fnCallback, fnError) {

                // test if lib is active
                if (jtti.depends.js.data.lib[strName].test()) {
                    jtti.depends.js.data.lib[strName].ready = true;
                } else {
                    jtti.depends.js.data.lib[strName].ready = false;
                }

                // import lib and call callback method
                if (jtti.depends.js.data.lib[strName].ready) {
                    fnCallback(strName);
                } else {
                    strPath = jtti.depends.js.data.lib[strName].path;
                    jtti.callback.fn.request("jtti.depends.js.fn.need." + strName, fnCallback, fnError, function() {
                        jtti.loading.ajax.fn.add();
                        jQuery.getScript(strPath, function() {
                            if (jtti.depends.js.data.lib[strName].test()) {
                                jtti.loading.ajax.fn.complete();
                                jtti.depends.js.data.lib[strName].ready = true;
                                jtti.callback.fn.launchCallback("jtti.depends.js.fn.need." + strName, strName);
                            } else {
                                jtti.loading.ajax.fn.fail();
                                jtti.callback.fn.launchError("jtti.depends.js.fn.need." + strName, strName);
                            }
                        });
                    });
                }
            }
        }
    }
}
};

//construct tti$ object. It will work like a singleton
window.jtti = window.tti$ = jtti;
jtti.init();
})();


