/*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 = function () {
    var thisNamespace = de.datev || {};

    // Hilfsfunktionen
    // Entnommen aus: Crockford, David: "JavaScript: The Good Parts"
    // Sowie aus: http://javascript.crockford.com/remedial.html (ebenfalls Crockford)

    // Funktion zum Erweitern von Klassenmethoden.
    // Verwendung:
    // MeinObjektOderKlasse.method("methodenName", function(arg) { alert(arg); });
    Function.prototype.method = function (name, func) {
        this.prototype[name] = func;
        return this;
    };
    window.method = document.method = Function.prototype.method;

    // entityify() produces a string in which '<', '>', and '&' are
    // replaced with their HTML entity equivalents. This is essential
    // for placing arbitrary strings into HTML texts.
    String.prototype.entityify = function () {
        return this.replace(/&/g, "&#38;").replace(/</g, "&#60;").replace(/>/g, "&#62;");
    };

    // quote() produces a quoted string. This method returns a string that
    // is like the original string except that it is wrapped in quotes
    // and all quote and backslash characters are preceded with backslash.
    String.prototype.quote = function () {
        var c, i, l = this.length, o = '"';
        for (i = 0; i < l; i += 1) {
            c = this.charAt(i);
            if (c >= ' ') {
                if (c === '\\' || c === '"') {
                    o += '\\';
                }
                o += c;
            } else {
                switch (c) {
                case '\b':
                    o += '\\b';
                    break;
                case '\f':
                    o += '\\f';
                    break;
                case '\n':
                    o += '\\n';
                    break;
                case '\r':
                    o += '\\r';
                    break;
                case '\t':
                    o += '\\t';
                    break;
                default:
                    c = c.charCodeAt();
                    o += '\\u00' + Math.floor(c / 16).toString(16) +
                        (c % 16).toString(16);
                }
            }
        }
        return o + '"';
    };

    // supplant() does variable substitution on the string. It scans through the string looking for expressions enclosed in { } braces. If an expression is found, use it as a key on the object, and if the key has a string value or number value, it is substituted for the bracket expression and it repeats. This is useful for automatically fixing URLs. So
    //
    // param = {domain: 'valvion.com', media: 'http://media.valvion.com/'};
    // url = "{media}logo.gif".supplant(param);
    //
    // produces a url containing "http://media.valvion.com/logo.gif".
    String.prototype.supplant = function (o) {
        return this.replace(/\{([^{}]*)\}/g,
            function (a, b) {
                var r = o[b];
                return typeof r === 'string' || typeof r === 'number' ? r : a;
            }
        );
    };

    // The trim() method removes whitespace characters from the beginning and end of the string.
    String.prototype.trim = function () {
        return this.replace(/^\s+|\s+$/g, "");
    };

  	String.prototype.lastChar = function() {
  		return ( this.length > 0 ? this.charAt(this.length - 1) : null );
  	};

    // Erweiterter typeof-Ersatz. Ergaenzungen:
    //    typeOf([]) === "array" // statt "object"
    //    typeOf(null) === "null" // statt "object"
    var typeOf = function (value) {
        var s = typeof value;
        if (s === 'object') {
            if (value) {
                if (typeof value.length === 'number' &&
                        !value.propertyIsEnumerable('length') &&
                        typeof value.splice === 'function') {
                    s = 'array';
                }
            } else {
                s = 'null';
            }
        }
        return s;
    };

    // de.datev.isEmpty(v) returns true if v is an object containing no enumerable members.
    var isEmpty = function (o) {
        var i, v;
        if (typeOf(o) === 'object') {
            for (i in o) {
                if (o[i] !== undefined && typeOf(o[i]) !== 'function') {
                    return false;
                }
            }
        }
        return true;
    };

	// Verschleierte E-Mail-Adresse dekodieren
	var recodeEmail = function (encodedEmail) {
		if (encodedEmail.indexOf("@") > -1) {
			// nicht kodiert
			return encodedEmail;
		}
		var atsignIndex = parseInt(encodedEmail.substring(encodedEmail.length - 2), 16);
		var hexToDecode = encodedEmail.substring(0, encodedEmail.length - 2);
		var email = "";
		for (var i = 0; i < hexToDecode.length; i += 4) {
			var charVal = parseInt(hexToDecode.substring(i, i + 4), 16);
			email += String.fromCharCode(charVal);
		}
		if (atsignIndex >= 0) {
			email = email.substr(0, atsignIndex) + "@" + email.substr(atsignIndex);
		}
		return email;
	};

	var getUrlAnchor = function (urlString) {
		var searchParts = urlString.split("#");
		if (searchParts.length <= 1) {
			return "";
		}
		return searchParts[1];
	};


	//Url-Parameter ersetzen
	//String:url
	//Objekt mit Eigenschaften:param.url, param.thema, param.mailto
	var replaceUrlParameter = function (url, param) {

		if (url) {
			for (var p in param) {

				var value = param[p];
				if (value) {
					// Folgender Ausdruck wird von den Browsern nicht unterstützt (positiv zurückschauende Zusicherung: ?<=):
					// var regExp = "(?<=" + p + "\\=)(.*?)(?=&|$)";
					// value = encodeURIComponent(value);

					var regExp = new RegExp(p + "\=(.*?)(?=&|$)");
					value = p + "=" + encodeURIComponent(value);
					url = url.replace(regExp, value);
				}
			}
		}
		return url;
	};



    // LOGGING ////////////////////////////////////
    // Hilfskonstanten fuer Funktion de.datev.log():
    thisNamespace.ERR = 1;
    thisNamespace.WARN = 2;
    // privat: DOM-Element, in das das Log geschrieben wird
    var logDomElement = null;
    // Gibt eine Nachricht aus (nur wenn Logging aktiviert wurde)
    var log = function (aString, errorLevel) {
        if (logDomElement) {
            var outputNode = document.createElement("div");
            if (errorLevel) {
                if (errorLevel === thisNamespace.ERR) {
                    //alert(aString);
                    outputNode.style.color = "red";
                    outputNode.appendChild(document.createTextNode("Fehler: "));
                }
                else if (errorLevel === thisNamespace.WARN) {
                    outputNode.style.color = "blue";
                    outputNode.appendChild(document.createTextNode("Warnung: "));
                }
            }
            outputNode.appendChild(document.createTextNode(aString));
            logDomElement.appendChild(outputNode);
        }
    };
    // Logging wird gestartet und Log landet in angegebenem HTML-Element
    var startLogging = function (e) {
        if (e) {
            logDomElement = e;
            thisNamespace.log("LOGGING BEGONNEN");
        }
    };
    // Logging wird beendet
    var stopLogging = function () {
        thisNamespace.log("LOGGING BEENDET");
        logDomElement = null;
    };

    //////////////////////////////////////////////////////
    // PUBLIC
    //////////////////////////////////////////////////////
    thisNamespace.log = log;
    thisNamespace.startLogging = startLogging;
    thisNamespace.stopLogging = stopLogging;
    thisNamespace.typeOf = typeOf;
    thisNamespace.isEmpty = isEmpty;
    thisNamespace.recodeEmail = recodeEmail;
    thisNamespace.getUrlAnchor = getUrlAnchor;
    thisNamespace.replaceUrlParameter = replaceUrlParameter;

    return thisNamespace;
}(); /* de.datev */