# constructors/uri-load.js

    /* jshint -W002 */
    /* jshint -W084 */

    /** @module uriLoad */

    var callbackOnce = function (cb) {
    	var executed = false;
    	return function (a, b) {
    		if (executed) {
    			console.log('callbackOnce', a, b);
    			return;
    		}
    		executed = true;
    		cb(a,b);
    	};
    };

    /**
     * loadScript - is a function for adding scripts into the header
     * @alias module:uriLoad.script
     * @param  {string|string[]}   url      url/urls of scripts
     * @param  {Function} callback [description]
     * @param  {object}   opts     settings with info related to the script tags
     */

    function loadScript(url, callback, opts, document){
    	if (!document) document = window.document;
    	if (!callback) callback = function () {};
    	callback	= callbackOnce(callback); // TODO fix trick

    	if (!Array.isArray(url)) {
    		url	= [url];
    	}

    	if (!opts) {
    		opts = {
    			attr	: {
    				"type"	: "text/javascript",
    				"charset"	: "utf-8"
    			}
    		};
    	}

    	var waitScripts	= 1;
    	var waitScriptsChecker	= function () {
    		waitScripts	-= 1;
    		if (waitScripts === 0) {
    			callback();
    		}
    	};

    	url.forEach(function (source) {
    		var script;
    		if (script	= document.querySelector('script[src="'+source+'"]')) {
    			if (!script.loaded) {
    				waitScripts	+= 1;
    				if (!script.callbacks)
    					script.callbacks	= [];
    				script.callbacks.push(waitScriptsChecker);
    			}
    		} else {
    			waitScripts	+= 1;
    			script = document.createElement("script");
    			script.type = "text/javascript";
    			if (opts && "attr" in opts) {
    				var at;
    				for (at in opts.attr) {
    					script.setAttribute(at, opts.attr[at]);
    				}
    			}
    			script.callbacks	= [];

    			script.callbacks.push(callback);

    			var runCallBacks	= function () {
    				var queue	= script.callbacks;
    				script.callbacks	= [];
    				queue.forEach(function (f) {
    					var er;
    					try {
    						f();
    					} catch (er) {
    						console.error(er);
    					}
    				});
    			};

    			if (script.readyState){  //IE
    				script.onreadystatechange = function(){
    					if (script.readyState == "loaded" ||
    							script.readyState == "complete"){
    						script.onreadystatechange = null;
    						script.loaded	= true;
    						runCallBacks();
    					}
    				};
    			} else {  //Others
    				script.onload = function(){
    					script.loaded	= true;
    					runCallBacks();
    				};
    			}

    			script.src = source;
    			document.getElementsByTagName("head")[0].appendChild(script);
    		}
    	});
    	waitScriptsChecker();
    }

    /**
     * loadLink - is a function for adding link tags into the header
     * @alias module:uriLoad.link
     * @param  {string|string[]}   url      url/urls of link tags
     * @param  {Function} callback [description]
     * @param  {object}   opts     settings with info related to the link tags
     */
    function loadLink(url, callback, opts, document){
    	if (!document) document = window.document;
    	if (!callback) callback = function () {};
    	callback	= callbackOnce(callback); // TODO fix trick

    	if (!opts) {
    		opts = {
    			attr	: {
    				"rel"	: "stylesheet",
    				"type"	: "text/css"
    			}
    		};
    	}

    	if (!Array.isArray(url)) {
    		url	= [url];
    	}

    	var waitLinks	= 1;
    	var waitLinksChecker	= function () {
    		waitLinks	-= 1;
    		if (waitLinks === 0) {
    			callback();
    		}
    	};

    	url.forEach(function (source) {
    		var link;
    		if (link	= document.querySelector('link[href="'+source+'"]')) {
    			if (!link.loaded) {
    				waitLinks	+= 1;
    				if (!link.callbacks)
    					link.callbacks	= [];
    				link.callbacks.push(waitLinksChecker);
    			}
    		} else {
    			waitLinks	+= 1;
    			link = document.createElement("link");
    			if (opts && "attr" in opts) {
    				var at;
    				for (at in opts.attr) {
    					link.setAttribute(at, opts.attr[at]);
    				}
    			}
    			link.callbacks	= [];

    			link.callbacks.push(callback);

    			var runCallBacks	= function () {
    				var queue	= link.callbacks;
    				link.callbacks	= [];
    				queue.forEach(function (f) {
    					var er;
    					try {
    						f();
    					} catch (er) {
    						console.error(er);
    					}
    				});
    			};
    			var userAgent = navigator.userAgent,
    				iChromeBrowser = /CriOS|Chrome/.test(userAgent),
    				isAndroidBrowser = /Mozilla\/5.0/.test(userAgent) && /Android/.test(userAgent) && /AppleWebKit/.test(userAgent) && !iChromeBrowser;

    			if (link.readyState){  //IE
    				link.onreadystatechange = function(){
    					if (link.readyState == "loaded" ||
    							link.readyState == "complete"){
    						link.onreadystatechange = null;
    						if (!link.loaded) {
    							link.loaded	= true;
    							runCallBacks();
    						}
    					}
    				};
    			} else if (isAndroidBrowser || !("onload" in link)) {
    				if (!link.loaded) {
    					link.loaded	= true;
    					runCallBacks();
    				}
    			} else {
    				link.onload = function() {
    					if (!link.loaded) {
    						link.loaded	= true;
    						runCallBacks();
    					}
    				};
    			}

    			link.setAttribute("href", source);
    			document.getElementsByTagName("head")[0].appendChild(link);

    			setTimeout(function () {
    				if (!link.loaded) {
    					link.loaded	= true;
    					runCallBacks();
    				}
    			}, 1000);
    		}
    	});
    	waitLinksChecker();
    }

    module.exports = {
    	script	: loadScript,
    	link	: loadLink
    };