/**
 * function whenDOMReady
 * Copyright (C) 2006-2007 Dao Gottwald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact information:
 *   Dao Gottwald  <dao at design-noir.de>
 *
 * @version  1.3
 * @url      http://design-noir.de/webdev/JS/whenDOMReady/
 */

function whenDOMReady(fn) {
    var f = arguments.callee;
    if ("listeners" in f) { // already initialized
        if (f.listeners) // still loading
            f.listeners.push(fn);
        else // DOM is ready
            fn();
        return;
    }
    f.listeners = [fn];
    f.callback = function() {
        removeEvent(window, "load", f.callback);
        if (document.removeEventListener)
            document.removeEventListener("DOMContentLoaded", f.callback, false);
        if (f.listeners) {
            while (f.listeners.length)
                f.listeners.shift()();
            f.listeners = null;
        }
    };
    if (document.addEventListener)
        document.addEventListener("DOMContentLoaded", f.callback, false);
    /*@cc_on @if (@_win32) else
        document.write("<script defer src=\"//:\""+
                       " onreadystatechange=\"if (this.readyState == 'complete')"+
                       " whenDOMReady.callback();\"><\/script>");
    @end @*/
    addEvent(window, "load", f.callback);
}

String.prototype.parseAsXML = window.DOMParser ? function () {
    return new DOMParser().parseFromString(this, "application/xml");
} : window.ActiveXObject ? function () {
    var parser = new ActiveXObject("Microsoft.XMLDOM");
    parser.async = "false";
    parser.loadXML(this);
    return parser;
} : function () {
   var d = document.createElement("div");
   d.innerHTML = this;
   var docFrag = document.createDocumentFragment();
   while (d.firstChild)
       docFrag.appendChild(d.firstChild);
   return docFrag;
}

if (!document.ELEMENT_NODE) {
    document.ELEMENT_NODE = 1;
    document.ATTRIBUTE_NODE = 2;
    document.TEXT_NODE = 3;
    document.CDATA_SECTION_NODE = 4;
    document.ENTITY_REFERENCE_NODE = 5;
    document.ENTITY_NODE = 6;
    document.PROCESSING_INSTRUCTION_NODE = 7
    document.COMMENT_NODE = 8;
    document.DOCUMENT_NODE = 9;
    document.DOCUMENT_TYPE_NODE = 10;
    document.DOCUMENT_FRAGMENT_NODE = 11;
    document.NOTATION_NODE = 12;
}

var importNode = (document.importNode) ? function (node, copy, doc) {
    return (doc || document).importNode(node, copy);
} : function (node, copy, doc) {
    doc = doc || document;
    switch (node.nodeType) {
        case document.ELEMENT_NODE:
            var newNode = doc.createElement(node.nodeName);
            if (node.attributes && node.attributes.length > 0)
                for (var i = 0, il = node.attributes.length; i < il;)
                    newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName));
            if (copy && node.childNodes && node.childNodes.length > 0)
                for (var i = 0, il = node.childNodes.length; i < il;)
                    newNode.appendChild(importNode(node.childNodes[i++], copy, doc));
            return newNode;
            break;
        case document.TEXT_NODE:
        case document.CDATA_SECTION_NODE:
        case document.COMMENT_NODE:
            return doc.createTextNode(node.nodeValue);
            break;
    }
    return false;
};

if (typeof Function.prototype.bind == 'undefined') {
    Function.prototype.bind = function(o) {
        var fn = this;
        var args = Array.prototype.slice.call(arguments, 1);

        return function() {
            fn.apply(o, args.concat(Array.prototype.slice.call(arguments)));
        }
    };
}

/* getElementsByClassName -- a cross-browser implementation of HTML5s document.getElementByClassName()
 *
 * Copyright (C) 2007-2009  Fabian Grutschus (f.grutschus at lubyte.de)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * USAGE: var elements = getElementsByClassName("test"); // finds all elements which contains "test" into the class attribute
 *        var elements = getElementsByClassName("test", document.getElementById("myform")); // finds all elements inside the element given by the second parameter
 *        var elements = getElementsByClassName("test myclassname", document.body); // finds elements that contains the classNames "test" and "myclassname" inside the document body
 * NOTE: getElementsByClassName() always returns a array, never a NodeList!
 * ALSO: getElementsByClassName() behaves differently in Quirks mode (case-intensive), like the standard function
 *
 * @version 1.0
 * @param   String       class names to search for (space separated list)
 * @param   HTMLElement  scope to search in (optional)
 * @returns Array        list of elements
 * @url     http://git.lubyte.de/?p=javascript-q.git;a=blob;f=snippets/getElementsByClassName.js
 */

var getElementsByClassName = document.getElementsByClassName ? function (className, scope) {
        return Array.prototype.slice.call((scope || document).getElementsByClassName(className));
    } : document.evaluate ? function (className, scope) {
        scope = scope || document;
        var re = [], xpathResult, ele;
        var scopeDocument    = !scope.ownerDocument ? scope : scope.ownerDocument;
        var searchClassNames = getElementsByClassName.__quirksCheck(className.trim(), scope).split(" ");
        var searchClassName  = searchClassNames[0];
        var searchClassNameLength = searchClassNames.length;

        if (scopeDocument.compatMode == "BackCompat") {
            xpathResult = scopeDocument.evaluate(".//*[contains(concat(' ', translate(@class, 'ABCDEFGHIJKLMNOPQRSTUVWYXZ', 'abcdefghijklmnopqrstuvwyxz'), ' '), ' " + searchClassName + " ')]", scope, null, 0, null);
        } else {
            xpathResult = scopeDocument.evaluate(".//*[contains(concat(' ', @class, ' '), ' " + searchClassName + " ')]", scope, null, 0, null);
        }

        if (searchClassNameLength > 1) {
            var eleClassNames, classNameLength;
            while ((ele = xpathResult.iterateNext())) {
                classNameLength = 1;
                eleClassNames = getElementsByClassName.__quirksCheck(ele.className, scope).split(" ");
                check: for (var i = 1; searchClassName = searchClassNames[i]; i++) {
                    if (eleClassNames.indexOf(searchClassName) > -1) {
                        classNameLength++;
                        if (classNameLength == searchClassNameLength) {
                            re.push(ele);
                            break check;
                        }
                    }
                }
            }
        } else {
            while ((ele = xpathResult.iterateNext())) {
                re.push(ele);
            }
        }

        return re;
    } : function (className, scope) {
        scope = scope || document;
        var re = [], ele, eleClassNames;
        var elements = scope.getElementsByTagName("*");
        var searchClassNames = getElementsByClassName.__quirksCheck(className.trim(), scope).split(" ");
        var searchClassName  = searchClassNames[0];
        var searchClassNameLength = searchClassNames.length;

        if (searchClassNameLength > 1) {
            var classNameLength;
            for (var i = 0; ele = elements[i]; i++) {
                eleClassNames = getElementsByClassName.__quirksCheck(ele.className, scope).split(" ");
                classNameLength = 0;
                check: for (var j = 0; searchClassName = searchClassNames[j]; j++) {
                    if (eleClassNames.indexOf(searchClassName) > -1) {
                        classNameLength++;
                        if (classNameLength == searchClassNameLength) {
                            re.push(ele);
                            break check;
                        }
                    }
                }
            }
        } else {
            for (var i = 0; ele = elements[i]; i++) {
                eleClassNames = getElementsByClassName.__quirksCheck(ele.className, scope).split(" ");
                if (eleClassNames.indexOf(searchClassName) > -1) {
                    re.push(ele);
                }
            }
        }

        return re;
    };
getElementsByClassName.__quirksCheck = function (className, scope) {
    return (!scope.ownerDocument ? scope : scope.ownerDocument).compatMode == "BackCompat" ? className.toLowerCase() : className;
}

if (typeof Array.prototype.indexOf == "undefined") {
    Array.prototype.indexOf = function (val) {
        for (var i = 0, len = this.length, ele; i < len ; i++) {
            ele = this[i];
            if (ele === val) {
                return i;
            }
        }
        return -1;
    }
}
if (typeof String.prototype.trim == "undefined") {
    String.prototype.trim = function() {
        var str = this.replace(/^\s\s*/, ''), ws = /\s/, i = str.length;
        while (ws.test(str.charAt(--i)));
        return str.slice(0, i + 1);
    }
}

function getStyle (obj, style) {
    if (document.defaultView) {
        var realStyle = style.replace(/([a-z])([A-Z])/g, function(dummy, c, c2) { return c + "-" + c2.toLowerCase(); });
        return document.defaultView.getComputedStyle(obj, null).getPropertyValue(realStyle);
    } else {
        var realStyle = style.replace(/-([a-z])/g, function(dummy, c) { return c.toUpperCase(); });
        if (obj.currentStyle) return obj.currentStyle[realStyle];
        else if (document.ids) return obj[realStyle];
        else if (document.all) return obj.style[realStyle];
    }
    return 0;
}

/**
 * xhr by Fabian Grutschus a.k.a crash
 *
 * @param string Method [get/post]
 * @param string URL
 * @param string data
 * @param string Callback-function (optional)
 * @param array Callback-function parameters (optional)
 */

/*@cc_on @if (@_win32 && @_jscript_version >= 5) if (!window.XMLHttpRequest)
window.XMLHttpRequest = function() { return new ActiveXObject('Microsoft.XMLHTTP') }
@end @*/
function xhr(method, url, data, cb, apply_para) {
    method = method.toLowerCase();
    var req;
    req = new XMLHttpRequest();
    req.open(method, url + (data && method == 'get' ? '?' + data : ''), true);
    req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    if (method == 'post') {
        req.setRequestHeader("Method", "POST " + url + " HTTP/1.1");
        req.setRequestHeader("Content-Length", data.length);
    }
    req.onreadystatechange = function() {
        if (req.readyState == 4 && req.status == 200) {
            if (cb) {
             cb.apply(null, [req].concat(apply_para));
            }
        }
    }
    req.send(data);
}

var File = {};
File.basename = function (path) { return path.replace(/.*\//, ""); }
File.dirname = function (path) { return path.match(/.*\//); }

/**
 * function loadScript
 * Copyright (C) 2006-2007 Dao Gottwald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact information:
 *   Dao Gottwald  <dao at design-noir.de>
 *
 * @version  1.6
 * @url      http://design-noir.de/webdev/JS/loadScript/
 */

function loadScript(url, callback) {
    var f = arguments.callee;
    if (!("queue" in f))
        f.queue = {};
    var queue =  f.queue;
    if (url in queue) { // script is already in the document
        if (callback) {
            if (queue[url]) // still loading
                queue[url].push(callback);
            else // loaded
                callback();
        }
        return;
    }
    queue[url] = callback ? [callback] : [];
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.onload = script.onreadystatechange = function() {
        if (script.readyState && script.readyState != "loaded" && script.readyState != "complete")
            return;
        script.onreadystatechange = script.onload = null;
        while (queue[url].length)
            queue[url].shift()();
        queue[url] = null;
    };
    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

ClassName = {};

ClassName.remove = function (className, removeClassName) {
    var classes = className.split(' ');
    var index = classes.indexOf(removeClassName);
    if (index > -1) className = classes.splice(0, index).concat(classes.splice(index, classes.length)).join(' ');
    return className;
}

ClassName.add = function (className, addClassName) {
    if (className.split(' ').indexOf(addClassName) < 0) className += ' '+addClassName;
    return className;
}

ClassName.exists = function (className, hasClassName) {
    return className.split(' ').indexOf(hasClassName) + 1;
}
