(function (window) {
    "use strict";
	var $ = window.jQueryFixed ? window.jQueryFixed : window.jQuery,
		ua = window.navigator.userAgent;

	$.isIE7 = (/MSIE\s7/).test(ua);
		
	$.log = function (message) {
        if (window.console && window.console.debug) {
            console.debug(arguments);
        } else if (window.console && window.console.log) {
            console.log(arguments);
        } else {
            alert(message);
        }
    };

	$.log2 = function log2() {
		var args = arguments,
			i, // number
			l = args.length, //number
			str, // string
			hasConsole = (window.console && window.console.log),
			divider = hasConsole ? ", " : "\n";

		for (i = 0; i < l; i += 1) {
			if (!str) {
				str = args[i];
			} else {
				str += divider +  args[i];
			}
		}

		if (hasConsole) {
			window.console.log(str);
		} else {
			alert(str);
		}
	};

    $.fn.normalize = function normalize() {
        var that = this,
            i, // number
            l = that.length,
            removeEmptyTextNodes = function removeEmptyTextNodes(elem, elem2) {
                
                if (typeof elem !== "object" && elem2) {
                    elem = elem2;
                } else if (typeof elem !== "object") {
                    return;
                }

                var childNodes = elem.childNodes,
                    i, // number
                    l = childNodes.length,
                    text = elem.innerText ? elem.innerText : elem.textContent;

                if (l) {
                    for (i = (l - 1); i > -1; i -= 1) {
                        if (childNodes[i].nodeType === 3 && !childNodes[i].childNodes.length && !$.trim(text)) {
                            childNodes[i].parentNode.removeChild(childNodes[i]);
                        }
                    }
                }
            };

        for (i = 0; i < l; i += 1) {
            removeEmptyTextNodes(that[i]);

            $(that[i]).find("*").each(removeEmptyTextNodes);
        }

        return that;
    };

	 /**
    * Creates and returns a HTMLElement.
    * 
    * Has shaky or no support for <object> & <embed> (depending on browser).
    * 
    * ex: newElementObject = {tagName : "a", href : "/", innerHTML : "A link", className : "someClass"}.
    * 
    * Specials: 
    *     append: {tagName: "ul", append: [{tagName: "li"}, {tagName: "li"}]}, append takes an Array of Objects or a single Object
    *     repeat: {tagName: "p", repeat: 10} adds 10 cloned <p>
    * 
    * 
    * @param {Object|String|empty} newElementObject|tagName (if !newElementObject $.create returns an empty <div>)
    * @returns HTMLElement
    */
    $.create = function (newElementObject) {

        // custom create HTML
        var neo = newElementObject,
			neoLength = neo ? (neo.length ? neo.length : 0) : 0,
	        tagName = (neo && neo.tagName) ? neo.tagName : "div",
	        newElement = document.createElement(tagName),
	        ne = newElement,
	        p, // properties
	        i = 0,
			clone = null,
			clones = neo ? (neo.repeat ? true : false) : false,
			df = document.createDocumentFragment(),
			dynProp = null, //dynamic property
			breakLoop = false,
            loadFunctions = [],
            data;

        if (!newElementObject) {
            return ne;
        }

        if (typeof newElementObject === "string") {
            return document.createElement(newElementObject);
        }

        if (neo.type) {
            ne.setAttribute("type", neo.type);
        }

        if (neo.src) {
            ne.setAttribute("src", neo.src);
        }

        if (neo) {

            if ($.isArray(neo)) {

                df = document.createDocumentFragment();

                for (i = 0; i < neoLength; i += 1) {
                    try {
                        df.appendChild($.create(neo[i]));
                    } catch (e) {
                        alert(e + "\n\ntagName = " + tagName + "\n\n" + p + ":\n" + neo[p] + "\n\ncreate loop (isArray)");
                        break;
                    }
                }

                newElement = df;
            } else {
				
				//alert("Hej!");

                for (p in neo) {

                    if (neo.hasOwnProperty(p) && (/(string|function|object|number)/).test(typeof neo[p])) {

                        if ((/^((un)?load|(dbl)?click|change|resize|scroll|select|submit|focus(in|out)?|blur|mouse(enter|leave|over|out|move|down|up)|key(press|down|up))$/).test(p) && typeof neo[p] === "function") {
                            $(ne).bind(p, neo[p]);

                            if (p === "load") {
                                loadFunctions.push(neo[p]);
                            }

                        } else if (typeof neo[p] === "function") {
                            dynProp = neo[p]();
                            if (dynProp) {
                                if (typeof ne.style[p] === "string") {
                                    ne.style[p] = dynProp;
                                } else {
                                    ne[p] = dynProp;
                                }
                            }
                        } else if (p === "data") {
                            for (data in neo[p]) {
                                if (neo[p].hasOwnProperty(data) && (/^(object|function|number|string|boolean)$/).test(typeof neo[p][data])) {
                                    $.data(ne, data, neo[p][data]);
                                }
                            }

                        } else if (!(/(tagName|append(Child(ren)?)?|type|repeat|src)/).test(p)) {

                            if (typeof ne.style[p] === "string" && p !== "opacity") {
                                try {
                                    ne.style[p] = neo[p];
                                } catch (er) {
                                    console.log(er + ", " + neo + ", " + p + ", " + neo[p]);
                                }
                            } else if (typeof ne.style[p] === "string" && p === "opacity") {
                                $(ne).css("opacity", neo[p]);
                            } else {
                                try {
                                    /**
                                    * create does not add a class attribute if there is no value.
                                    */
                                    if (!((/^(className)$/).test(p) && !neo[p])) {
                                        ne[p] = neo[p];
                                    }

                                } catch (f) {
                                    alert(f + "\n\ntagName = " + tagName + "\n\n" + p + ":\n" + neo[p] + "\n\nattribute");
                                    breakLoop = true;
                                }
                            }
                        } else if ((/^attr$/i).test(p)) {
							
							$.log(neo[p], p);

						} else if ((/^(append)(Child(ren)?)?$/).test(p)) {
                            if (typeof neo[p] === "object" && neo[p].length) {
                                for (i = 0; i < neo[p].length; i += 1) {
                                    try {
                                        ne.appendChild($.create(neo[p][i]));
                                    } catch (g) {
                                        alert(g + "\n\ntagName = " + tagName + "\n\n" + p + ":\n" + neo[p] + "\n\ncreate loop");
                                        breakLoop = true;
                                    }
                                }
                            } else if (typeof neo[p] === "object") {
                                try {
                                    ne.appendChild($.create(neo[p]));
                                } catch (h) {
                                    alert(h + "\n\ntagName = " + tagName + "\n\n" + p + ":\n" + neo[p] + "\n\ncreate");
                                    breakLoop = true;
                                }
                            }
                        }

                        if (breakLoop) {
                            break;
                        }
                    }
                }
            }
        }

        if (clones) {
            df = document.createDocumentFragment();

            for (i = 0; i < neo.repeat; i += 1) {
                clone = newElement.cloneNode(true);
                df.appendChild(clone);
            }

            newElement = df;
        }

        if (loadFunctions.length) {
            setTimeout(function () {

                for (i = 0; i < loadFunctions.length; i += 1) {
                    loadFunctions[i].apply(newElement);
                }

            }, 10);
        }

        return newElement;
    };

	$.triggerNativeEvent = function (elem, event) {
        var target = elem,
            mEvent = null;

        if (document.dispatchEvent) { // W3C
            mEvent = document.createEvent("MouseEvents");
            mEvent.initMouseEvent(event, true, true, window, 1, 1, 1, 1, 1, false, false, false, false, 0, target);

            target.dispatchEvent(mEvent);

        } else if (document.fireEvent) { // IE
            target.fireEvent("on" + event);
        } 

    };

	$.getDimensions = function (elem, test) {
		
		if (test) {
			$.log(test);
		}
		
		if (!elem) {
			throw new Error("elem is " + elem);
		} else if (elem !== window && !elem.tagName) {
            throw new Error(elem + " is not an HTMLTagElement");
        } else if (elem === window) {

            return {
                width: (document.documentElement && document.documentElement.clientWidth) ? document.documentElement.clientWidth : window.innerWidth,
                height: (document.documentElement && document.documentElement.clientHeight) ? document.documentElement.clientHeight : window.innerHeight
            };

        } else {

            var jqElem = $(elem),
                ofs = jqElem.offset(),
                ret = {
                    width: parseFloat(jqElem.width()),
                    height: parseFloat(jqElem.height()),
                    ofs: {
                        top: elem.offsetTop,
                        left: elem.offsetLeft
                    },
                    top: ofs.top,
                    left: ofs.left,
                    padding: {
                        top: parseFloat(jqElem.css("padding-top")) ? parseFloat(jqElem.css("padding-top")) : 0,
                        right: parseFloat(jqElem.css("padding-right")) ? parseFloat(jqElem.css("padding-right")) : 0,
                        bottom: parseFloat(jqElem.css("padding-bottom")) ? parseFloat(jqElem.css("padding-bottom")) : 0,
                        left: parseFloat(jqElem.css("padding-left")) ? parseFloat(jqElem.css("padding-left")) : 0
                    },
                    margin: {
                        top: parseFloat(jqElem.css("margin-top")) ? parseFloat(jqElem.css("margin-top")) : 0,
                        right: parseFloat(jqElem.css("margin-right")) ? parseFloat(jqElem.css("margin-right")) : 0,
                        bottom: parseFloat(jqElem.css("margin-bottom")) ? parseFloat(jqElem.css("margin-bottom")) : 0,
                        left: parseFloat(jqElem.css("margin-left")) ? parseFloat(jqElem.css("margin-left")) : 0
                    }
                };

            ret.fullWidth = parseFloat(ret.width + ret.margin.left + ret.margin.right + ret.padding.left + ret.padding.right);

            ret.fullHeight = parseFloat(ret.height + ret.margin.top + ret.margin.bottom + ret.padding.top + ret.padding.bottom);

            if (elem === document.body) {
                ret.scroll = {
                    top: document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop,
                    left: document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft
                };

                ret.view = {
                    height: document.documentElement.clientHeight ? document.documentElement.clientHeight : elem.parentNode.clientHeight,
                    width: document.documentElement.clientWidth ? document.documentElement.clientWidth : elem.parentNode.clientWidth
                };
            }

            return ret;
        }
    };
	
	$.objectWalk = function (obj, func, args) {
        var i,
			ar = args ? args : [];
 
        if (typeof func !== "function") {
            throw new Error("file: custom.js, Error: " + func + " is not a function");
        }
        func.apply(obj, ar);
 
        for (i in obj) {
            if (obj.hasOwnProperty(i) && obj[i] && typeof obj[i] === "object" && (!obj[i].length && obj[i].length !== 0)) {
                $.objectWalk(obj[i], func, ar);
            }
        }
    };
   
    $.runAll = function () {
        var that = this,
			arg = arguments;
       
        $.objectWalk(that, function () {
			
			var args = arguments,
				obj,
				prop;

            if (this[args[0]]) {
                if (typeof this[args[0]] === "function") {
                    this[args[0]]();
                } else if (typeof this[args[0]] === "object" && (!this[args[0]].length && this[args[0]].length !== 0)) {

                    obj = this[args[0]];

                    for (prop in obj) {
                        if (obj.hasOwnProperty(prop) && typeof obj[prop] === "function") {
                            obj[prop]();
                        }
                    }
                }
            }
        }, [arg[0]]);
    };

    /**
     * $.runWhenExists will run a maximum of 50 times before trying to run the callback.
     * If that does not work it does nothing.
     *
     * @param {Function} exists (have to return a falsy or truthy value)
     * @param {Function} callback (will run when "exists" returns a truthy value)
     * @param {Number}
     * @param {Number}
     */
    $.runWhenExists = function runWhenExists(exists, callback, customTime, customWait) {
        
        var iv = 0,
            ivCount = 0,
            time = (customTime && typeof customTime === "number") ? customTime : 100,
            wait = (customWait && typeof customWait === "number") ? customWait : 100,
            allCount = 0,
            maxCount = 50,
            runFunc = function runFunc() {
                ivCount += 1;
                allCount += 1;

                if (allCount >= maxCount) {
                    clearInterval(iv);
                    try {
                        callback();
                    } catch (error) {
                        //throw new Error(error);
                    }
                }

                if (exists()) {
                    // wait 100 or [customWait] ms before running the callback, just in case...
                    clearInterval(iv);
                    setTimeout(callback, wait);
                }

                if (ivCount === 5) {
                    clearInterval(iv);

                    time = (time * 2);
                    ivCount = 0;

                    iv = setInterval(runFunc, time);
                }
            };

        iv = setInterval(runFunc, time);

    };

	// "runWhenTrue" better describes what it does
	$.runWhenTrue = $.runWhenExists;

   
    $.runInit = function (obj) {
        $.runAll.apply(obj, ["init"]);
    };

    $.extendView = function extendView(obj) {
        if ($.view) {
            $.extend(true, $.view, obj);
        } else {
	        $.extend({ view: obj });
        }
    };
	
}(window));
