/*jslint adsafe: false, bitwise: true, browser: true, cap: false, debug: true, eqeqeq: true, evil: false, forin: false, fragment: true, glovar: true, laxbreak: false, nomen: true, on: true, passfail: false, plusplus: false, regexp: false, rhino: false, safe: false, sidebar: false, sub: false, undef: true, white: true, widget: false */

// JSLint Options
// adsafe: true if ADsafe.org rules widget pattern should be enforced.
// bitwise: true if bitwise operators should not be allowed
// browser: true if the standard browser globals should be predefined
// cap: true if upper case HTML should be allowed
// debug: true if debugger statements should be allowed
// eqeqeq: true if === should be required
// evil: true if eval should be allowed
// forin: true if unfiltered for in statements should be allowed
// fragment: true if HTML fragments should be allowed
// glovar: true if var should not be allowed to declare global variables
// indent the number of spaces used for indentation (default is 4)
// laxbreak: true if statement breaks should not be checked
// nomen: true if names should be checked for initial underbars
// on: true if HTML event handlers should be allowed
// passfail: true if the scan should stop on first error
// plusplus: true if ++ and -- should not be allowed
// predef an array of strings, the names of predefined global variables
// regexp: true if . should not be allowed in RegExp literals
// rhino: true if the Rhino environment globals should be predefined
// safe: true if the safe subset rules are enforced.
// sidebar: true if the Windows Sidebar Gadgets globals should be predefined
// sub: true if subscript notation may be used for expressions better expressed in dot notation
// undef: true if undefined global variables are errors
// white: true if strict whitespace rules apply
// widget: true if the Yahoo Widgets globals should be predefined

/*global de*/
de = this.de || {};
de.datev = de.datev || {};
de.datev.dom = function () {
    var thisNamespace = de.datev.dom || {};

	// Prueft, ob Browser mit diesem JS zurecht kommen wird
	var browserSupportsDom = function () {
		return (document.getElementById && document.getElementsByTagName)
	};

	var getChildren = function (node, byName, recursive) {
		if (!node || !byName) return;
		var result = new Array();
		if (!node.hasChildNodes) return result;
		recursive = !recursive ? false : recursive;
		for(var i = 0; i < node.childNodes.length; i++)
		{
			var child = node.childNodes[i];
			if (child.nodeName.toLowerCase() == byName.toLowerCase())
			{
				result.push(child);
			}
			if (recursive === true && child.nodeType === 1) {
				var retVal = getChildren(child, byName, recursive);
				if (retVal && retVal.length > 0) {
					result = result.concat(retVal);
				}
			}
		}
		return result;
	};

	var getParent = function (node, byName) {
		if (!node || !byName) return;
		var parent = node.parentNode;
		if (!parent) return;
		if (parent.nodeName.toLowerCase() === byName.toLowerCase()) {
			return parent;
		}
		return getParent(parent, byName);
	};

    // Ersetzt eine Klasse im "class"-Attribut (oldClass/newClass kann false sein)
    var replaceClass = function (elem, oldClass, newClass) {
        var addMode = (newClass && !oldClass);
        if (!(oldClass || newClass)) {
            de.datev.log("[replaceClass] Leerer Parameter. Es muss mindestens einer der Bezeichner fuer die alte oder die neue Klasse angegeben werden", de.datev.ERR);
            return false;
        }
        var classTokens = elem.className && elem.className.split(/\s+/);
        var newClassTokens = [];
        var classWasChanged = false;
        if(classTokens) {
			for (var i = 0; i < classTokens.length; i++) {
				if (classTokens[i].length > 0) {
					if (addMode && classTokens[i] === newClass) {
						// entferne bereits vorh. neue Klasse
					}
					else if (classTokens[i] === oldClass) {
						if (newClass) {
							newClassTokens.push(newClass);
						}
						classWasChanged = true;
					}
					else {
						newClassTokens.push(classTokens[i]);
					}
				}
			}
		}

        if (addMode) {
            newClassTokens.push(newClass);
            classWasChanged = true;
        }
        elem.className = newClassTokens.join(" ");
        return classWasChanged;
    };

    // Fuegt eine Klasse ins "class"-Attribut ein
    var addClass = function (elem, newClass) {
        return replaceClass(elem, false, newClass);
    };

    // Entfernt eine Klasse aus dem "class"-Attribut
    var removeClass = function (elem, oldClass) {
        return replaceClass(elem, oldClass, false);
    };


    // Ueberprueft "class"-Attribut auf einen Bezeichner
    var hasClass = function (elem, className) {
        var classTokens = elem.className && elem.className.toLowerCase().split(/\s+/);
        if (!classTokens) {
            return false;
        }
        var lcClassName = className.toLowerCase();
        for (var i = 0; i < classTokens.length; i++) {
            var curr = classTokens[i];
            if (curr === lcClassName) {
                return true;
            }
        }
        return false;
    };

	var getChildrenByClassName = function (elem, cn) {
		var result = [];
		if (!elem || !(elem.childNodes) || cn == undefined || cn == "") return result;
		for (var i = 0; i < elem.childNodes.length; i++) {
			if (thisNamespace.hasClass(elem.childNodes[i], cn)) {
				result.push(elem.childNodes[i]);
			}
		}
		return result;
	};

	var getElementsByTagAndClassName = function (tagName, cn) {
		var result = [];
		if (!tagName || cn == undefined || cn == "") return result;
		var myTags = document.getElementsByTagName(tagName);
		for (var i = 0; i < myTags.length; i++) {
			if (thisNamespace.hasClass(myTags[i], cn)) {
				result.push(myTags[i]);
			}
		}
		return result;
	};

    // Umwandeln von problematischen Zeichen in Entities
    String.method("makeXmlSafe", function (stringContainingXmlSpecialChars) {
        var res = "";
        var fromchar = ["<", ">", "\n", "&"];
        var tochar = ["&lt;", "&gt;", "<br />", "&amp;"];
        var replaced = false;

        for (var i = 0; i < stringContainingXmlSpecialChars.length; i++) {
            replaced = false;
            for (var c = 0; c < fromchar.length; c++) {
                if (stringContainingXmlSpecialChars.charAt(i) === fromchar[c]) {
                    res += tochar[c];
                    replaced = true;
                    break;
                }
            }
            if (replaced === false) {
                res += stringContainingXmlSpecialChars.charAt(i);
            }
        }
        return res;
    });


    //////////////////////////////////////////////////////
    // PUBLIC
    //////////////////////////////////////////////////////
    thisNamespace.browserSupportsDom = browserSupportsDom;
    thisNamespace.getChildren = getChildren;
    thisNamespace.getChildrenByClassName = getChildrenByClassName;
    thisNamespace.getParent = getParent;
    thisNamespace.getElementsByTagAndClassName = getElementsByTagAndClassName;
    thisNamespace.replaceClass = replaceClass;
    thisNamespace.addClass = addClass;
    thisNamespace.removeClass = removeClass;
    thisNamespace.hasClass = hasClass;

    return thisNamespace;
}(); // de.datev.dom