var RIS = RIS || {};

/**
 * Loads javascript files or CSS files into the document
 */
PWC.Loader = function () {
    'use strict';

    function loadResource(resourceUrl, resoruceType, callback, element) {
        /// <summary>
        /// Loads the specified resource into the document. Supported are
        /// CSS and javascript files
        /// </summary>
        /// <param name="resourceUrl">The URL of the script or CSS file</param>
        /// <param name="resoruceType">The mime type of the library</param>
        /// <param name="callback">The function to call on successfull load</param>
        /// <param name="element">The document in which the library is to be loaded</param>
        if (!resourceUrl) {
            throw new PWC.ApplicationError('unknow resourceUrl when load resourse.');
        }
        var theElem = element || document;
        // if this library is already loaded just call the function
        if (isResoruceLoaded(resourceUrl, theElem)) {
            if (callback) {
                callback(resourceUrl, resoruceType, false);
            }
            return;
        }

        var isDoc = theElem.nodeType === 9;
        var libElem = createResourceElement(resourceUrl, resoruceType, (isDoc ? theElem : document));
        var hd = isDoc ? theElem.getElementsByTagName("head")[0] : theElem;

        if (libElem && hd) {
            if (resoruceType === "text/javascript" || resoruceType === "text/css") {
                libElem.addEventListener("load", function () {
                    callback(resourceUrl, resoruceType, true);
                }, false);
            } else {
                callback(resourceUrl, resoruceType, true);
            }
            hd.appendChild(libElem);

            var libs = theElem.libraries;
            if (typeof (libs) === "undefined") {
                libs = theElem.libraries = {};
            }
            libs[resourceUrl] = true;
        }// if(libElem...
    }

    function isResoruceLoaded(resourceUrl, element) {
        /// <summary>
        /// Determines if the resource is successfully loaded
        /// in the given document
        /// </summary>
        /// <param name="resourceUrl">The path of the library</param>
        /// <param name="element">The document obejct</param>
        /// <returns type="bool">true if the given library has already been loaded in the document</returns>
        element = element || document;
        var libs = element.libraries;
        if (typeof (libs) === "undefined") {
            return false;
        }
        return libs[resourceUrl] === true;
    }

    function createResourceElement(resourceUrl, resourceType, elementOwner) {
        /// <summary>
        /// Creates a script or a link elementOwner.
        /// </summary>
        /// <param name="resourceUrl">The URL of the script or CSS file</param>
        /// <param name="resourceType">The resourceType of library, currently supported are "text/javascirpt", "text/css"</param>
        /// <param name="elementOwner">The DOM document in which to create the library elementOwner</param>
        /// <returns>the dom elementOwner representing the library</returns>
        var resourceElement = null;
        if (resourceType === "text/javascript") {
            resourceElement = elementOwner.createElement("script");
            resourceElement.setAttribute("resourceType", resourceType);
            if (resourceUrl) {
                resourceElement.setAttribute("src", resourceUrl);
                resourceElement.src = resourceUrl;
            }
        } else if (resourceType === "text/css") {
            resourceElement = elementOwner.createElement("link");
            resourceElement.setAttribute("rel", "stylesheet");
            resourceElement.setAttribute("resourceType", resourceType);
            if (resourceUrl) {
                resourceElement.setAttribute("href", resourceUrl);
                resourceElement.href = resourceUrl;
            }
        }

        if (resourceElement) {
            resourceElement.setAttribute("id", resourceUrl.replace("/", "_", "g"));
        }
        return resourceElement;
    }

    function doCallback(resources, callback, hasNewJsLoaded) {
        try {
            callback(hasNewJsLoaded);
        } catch (err) {
            var s = "";
            for (var k = 0, klen = resources.length; k < klen; k++) {
                s += resources[k].url + "\n";
            }
            $log.debug(err + ": In call-back function while loading:\n\n" + s);
        }
    }

    return {
        loadJs: function (jsUrl, callback, domElement) {
            /// <summary>
            /// Loads a javascript file/resource into the specified domElement
            /// </summary>
            /// <param name="jsUrl">The jsUrl of the script.</param>
            /// <param name="callback">The function to call on successfull load</param>
            /// <param name="domElement">The document or Element into which to load the resource</param>
            loadResource(jsUrl, "text/javascript", callback, domElement);
        },

        loadCss: function (cssUrl, domElement) {
            /// <summary>
            /// Loads the specified CSS stylesheet
            /// </summary>
            /// <param name="cssUrl">The url of the CSS stylesheet</param>
            /// <param name="domElement">The document or Element into which to load the resource</param>
            loadResource(cssUrl, "text/css", null, domElement);
        },

        loadResource: function (resourceUrl, resourceType, callback, domElement) {
            /// <summary>
            /// Loads a javascript or CSS into the specified document.
            /// </summary>
            /// <param name="resourceUrl">The URL of the resource</param>
            /// <param name="resourceType">The mimetype of the reource, text/css OR text/javascript</param>
            /// <param name="callback">The function to call after successfull loading of the file</param>
            /// <param name="domElement">The document or Element into which to load the resource</param>
            return loadResource(resourceUrl, resourceType, callback, domElement);
        },

        load: function (resources, callback, domElement) {
            /// <summary>
            /// Loads an array of resource into the specified dom document and calls
            /// the given function after successfully loading the scripts
            /// </summary>
            /// <param name="resources">The array of script info objects. The objects have
            /// following fields {url:"the url", type:"text/css | text/javacript"}</param>
            /// <param name="callback">The function to call after successfull loading of the file</param>
            /// <param name="domElement">The document or Element into which to load the resource</param>
            var idx = 0;
            var hasNewJsLoaded = false;
            var loadInternal = function () {
                if (resources.length > 0) {
                    var sInfo = resources[idx];
                    loadResource(sInfo.url, sInfo.type, loadCallback, domElement);
                } else {
                    doCallback(resources, callback);
                }
            };

            var loadCallback = function (resourceUrl, resoruceType, isNewLoaded) {
                if (resoruceType === "text/javascript") {
                    hasNewJsLoaded = hasNewJsLoaded | isNewLoaded;
                }
                ++idx;
                if (idx >= resources.length) {
                    doCallback(resources, callback, hasNewJsLoaded);
                } else {
                    loadInternal();
                }
            };

            loadInternal();
        },

        toString: function () {
            return "PWC.Loader";
        }
    };
}();