/*
 * Dependency-aware dynamic loader. Currently only loading of scripts are implemented.
 * 
 * This loader works by dynamically creating <script> tags, and attaching listeners to the scripts' "loaded" or "complete"
 * events. When a script depends on another script, that dependency is added to a list. As scripts are loaded, they are 
 * removed from the dependency lists; when a script no longer has any more dependencies, then it can be loaded.
 *
 * A higher-level interface is available, majestic.tools.loader.loadAll(). Instead of making individual calls to loader.onReady
 * and loader.loadElements, you can pass in an object/dictionary that describes what scripts depend on what other scripts:
 *
 * var scripts = {
 *     "5.js" : {
 *         "4.js" : {
 *             "3.js" : ["1or2.js", "2or1.js"]
 *         }
 *     },
 *     "someother.js" : "yetanother.js",
 *     "whenever.js" : null
 * };
 *
 * So 5 depends on 4 which depends on 3, which in turn depends on two scripts ("1or2", "2or1"); it doesn't matter which order those
 * two scripts get loaded, but "3.js" won't be loaded until they've both finished loading. The "someother.js" depends on one file,
 * "yetanother.js". Finally, "whenever.js" has no dependencies, so the decision as to when to load it is left to the browser.
 *
 * A real-world example:
 *
 * var scripts = {
 *     "test.js": {
 *         "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js" : "http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js",
 *         "http://maps.google.com/maps/api/js?sensor=false" : null
 *     }
 * };
 * majestic.tools.loader.loadAll(scripts);
 *
 * In other words, "test.js" depends on jQuery UI and Google Maps, and jQuery UI in turn depends on jQuery. Google Maps doesn't depend on
 * anything.
 *
 * loadAll can also be supplied with a prefix: 
 *
 * majestic.tools.loader.loadAll(scripts, "/js/myproject")
 *
 * This prefix will be added to the URL of any script whose URL does not start with "http://". This saves you some typing :)
 *
 */

if (typeof majestic == 'undefined') window.majestic = {}; 
window.startTime = new Date();

majestic.tools = {
    urlParams: {},
    loadable: function () {
        this.element = null;
        this.originalSrc = '';
        this.listeners = [];
        this.loaded = 0;
        this.loadStart = -1;
    },

    listener: function (f) {
        this.dependencies = {};
        this.fn = f;
    },

    scriptLoader: function () {
        this.elements = {};
        this.requiredElements = [];
        this.load = function (scripts) { var loader = this; loader.tagLoadJs(scripts); };
        this.makeElement = function (src, prefix) {
            var htmlElement = document.createElement("script");
            if (src.indexOf("http") != 0 && prefix && prefix.length > 0) {
                src = prefix + "/" + src;
            }
            htmlElement.src = src;
            htmlElement.type = 'text/javascript';
            return htmlElement;
        };
    },

    isEmpty: function (obj) {
        var name;
        for (name in obj) {
            if (obj.hasOwnProperty(name)) {
                return false;
            }
        }
        return true;
    },

    getElementsByClassName: function (oElm, strTagName, oClassNames) {
        var arrElements = (strTagName == "*" && oElm.all) ? oElm.all : oElm.getElementsByTagName(strTagName);
        var arrReturnElements = new Array();
        var arrRegExpClassNames = new Array();
        if (typeof oClassNames == "object") {
            for (var i = 0; i < oClassNames.length; i++) {
                arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames[i].replace(/\-/g, "\\-") + "(\\s|$)"));
            }
        }
        else {
            arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames.replace(/\-/g, "\\-") + "(\\s|$)"));
        }
        var oElement;
        var bMatchesAll;
        for (var j = 0; j < arrElements.length; j++) {
            oElement = arrElements[j];
            bMatchesAll = true;
            for (var k = 0; k < arrRegExpClassNames.length; k++) {
                if (!arrRegExpClassNames[k].test(oElement.className)) {
                    bMatchesAll = false;
                    break;
                }
            }
            if (bMatchesAll) {
                arrReturnElements.push(oElement);
            }
        }
        return (arrReturnElements);
    }
};
majestic.tools.listener.prototype.elementLoaded = function (loadable) {

    delete this.dependencies[loadable.originalSrc];
    if (majestic.tools.isEmpty(this.dependencies) && this.fn) {
        this.fn();
    }
};
majestic.tools.loadable.prototype.ready = function () {
    this.loaded = 1;
    for (var i in this.listeners) {
        this.listeners[i].elementLoaded(this);
    }
};

majestic.tools.scriptLoader.prototype.onReady = function (src, prefix, fn) {
    var loader = this;
    var srcs = (src instanceof Array) ? src : [src];
    var elements = loader.ensureElements(srcs, prefix);
    var unloaded = elements[0];
    var loading = elements[1];
    var allElements = elements[0].concat(elements[1].concat(elements[2]));
    var s;
    if (allElements.length > 0) {
        var listener = new majestic.tools.listener(fn);
        if (unloaded.length > 0 || loading.length > 0) {
            for (s = 0; s < allElements.length; s++) {
                var elem = allElements[s];
                elem.listeners.push(listener);
                listener.dependencies[elem.originalSrc] = elem;
            }

            if (unloaded.length > 0)
                loader.load(unloaded, prefix);
        }
        else if(fn != null) {
            fn();
        }
    }
};

majestic.tools.scriptLoader.prototype.ensureElements = function (srcs, prefix) {
    var unloaded = [];
    var loading = [];
    var loaded = [];
    if (!prefix || prefix.length == 0)
        prefix = "";

    var loader = this;
    for (var s in srcs) {
        var src = srcs[s];
        var elem = loader.elements[src];
        if (!elem) {
            var htmlElement = loader.makeElement(src, prefix);

            elem = new majestic.tools.loadable();
            elem.element = htmlElement;
            elem.originalSrc = src;
            loader.elements[src] = elem;
            unloaded.push(elem);
        }
        else if (elem.loaded == 0) {
            loading.push(elem);
        }
        else {
            loaded.push(elem);
        }
    }

    return [unloaded, loading, loaded];
};
majestic.tools.scriptLoader.prototype.loadElements = function (s, prefix) {

    var loader = this;
    var srcs = (s instanceof Array) ? s : [s];
    var elements = (typeof srcs[0] == "string") ? loader.ensureElements(srcs, prefix)[0] : srcs;
    loader.load(elements);
};
majestic.tools.scriptLoader.prototype.loadAll = function (scripts, prefix, loadFunction) {
    var loader = this;

    if (scripts && typeof scripts == "object" && !(scripts instanceof Array)) {
        for (var elemName in scripts) {
            loader.loadAll(scripts[elemName], prefix, function (fn, e) {
                return function () {
                    loader.onReady(e, prefix, fn);
                };
            } (loadFunction, elemName));
        };
    }
    else if (scripts) {
        if (loadFunction)
            loader.onReady(scripts, prefix, loadFunction);
        else
            loader.loadElements(scripts, prefix);
    }
    else if (loadFunction) {
        loadFunction();
    }
};
majestic.tools.scriptLoader.prototype.tagLoadJs = function(scripts)
{
    var s;
    for(s in scripts)
    {
        var script = scripts[s];            
        script.element.onload = (
            function(s) 
            { 
                return function()
                { 
                    s.ready();
                };
            }(script)
        );
        script.element.onreadystatechange = (
            function(s) 
            { 
                return function()
                {
                    if (this.readyState == 'loaded' || this.readyState == 'complete') {
                        s.ready();
                    }
                };
            }(script)
        );
         
        document.getElementsByTagName("head")[0].appendChild(script.element);
    }
    return;
};

majestic.tools.scriptLoader.prototype.dependencyLoadJs = function(scripts)
{
    var unloaded = [];
    for(var s in scripts)
    {
        var script = scripts[s];
        unloaded.push(script.originalSrc);
    }

    if(unloaded.length > 0)
    {    
	    var allScriptString = unloaded.join(";");
	    var encodedScriptString = window.Base64.encode(allScriptString);
	    var scriptElement = document.createElement("script");
	    var scriptSrc = "/DependencyHandler.axd?s="+encodedScriptString+"&t=JavaScript&cdv=1";
	    scriptElement.src = scriptSrc;
	    scriptElement.type = 'text/javascript';
        
	    var loadedFunc = (function(ss)
	    {
		    return function()
		    {
			    var i;
			    for(i in ss)
			    {
				    ss[i].ready();
			    }
		    };
	    }(scripts));
    	
	    scriptElement.onload = loadedFunc;	
	    scriptElement.onreadystatechange = (function() 
	    { 
		    if (this.readyState == 'loaded' || this.readyState == 'complete')
		    {
			    loadedFunc();
		    }
	    });
    	
	    document.getElementsByTagName("head")[0].appendChild(scriptElement);
	}
};
    
majestic.tools.scriptLoader.prototype.waitFor = function(target, fn)
{
    var loader = this;
    if(eval("typeof "+target) != "undefined")
    {
        fn();
    }
    else
    {
        setTimeout(function() { loader.waitFor(target, fn); }, 5);
    }
};

majestic.tools.scriptLoader.prototype.waitForSelectors = function(selectorStrings, fn)
{
    var loader = this;
    var selectors = new Array();
    for(var i=0; i < selectorStrings.length; i++)
    {
        var selector = jQuery(selectorStrings[i]);        
        if(selector.length > 0)
        {
            selectors.push(selector);
        }
    }
    
    if(selectors.length == selectorStrings.length)
        fn(selectors);
    else
        setTimeout(function() { loader.waitFor(selectorStrings, fn); }, 5);    
};
    
majestic.tools.scriptLoader.prototype.waitForjQuery = function(fn)
{    
    var loader = this;
    loader.waitFor("$", fn);
};

(function () {
    var e,
        a = /\+/g,  // Regex for replacing addition symbol with a space
        r = /([^&=]+)=?([^&]*)/g,
        d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
        q = window.location.search.substring(1);

    while (e = r.exec(q))
       majestic.tools.urlParams[d(e[1])] = d(e[2]);
})();

majestic.tools.loader = new majestic.tools.scriptLoader();
