function registerNS(ns)
{
 var nsParts = ns.split(".");
 var root = window;

 for(var i=0; i<nsParts.length; i++)
 {
  if(typeof root[nsParts[i]] == "undefined")
   root[nsParts[i]] = {};

  root = root[nsParts[i]];
 }
}

/* From json_parse.js */
/*
    http://www.JSON.org/json_parse.js
    2008-09-18

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    This file creates a json_parse function.

        json_parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = json_parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

    This is a reference implementation. You are free to copy, modify, or
    redistribute.

    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.
*/

/*members "", "\"", "\/", "\\", at, b, call, charAt, f, fromCharCode,
    hasOwnProperty, message, n, name, push, r, t, text
*/

/*global json_parse */

json_parse = function () {

// This is a function that can parse a JSON text, producing a JavaScript
// data structure. It is a simple, recursive descent parser. It does not use
// eval or regular expressions, so it can be used as a model for implementing
// a JSON parser in other languages.

// We are defining the function inside of another function to avoid creating
// global variables.

    var at,     // The index of the current character
        ch,     // The current character
        escapee = {
            '"':  '"',
            '\\': '\\',
            '/':  '/',
            b:    '\b',
            f:    '\f',
            n:    '\n',
            r:    '\r',
            t:    '\t'
        },
        text,

        error = function (m) {

// Call error when something is wrong.

            throw {
                name:    'SyntaxError',
                message: m,
                at:      at,
                text:    text
            };
        },

        next = function (c) {

// If a c parameter is provided, verify that it matches the current character.

            if (c && c !== ch) {
                error("Expected '" + c + "' instead of '" + ch + "'");
            }

// Get the next character. When there are no more characters,
// return the empty string.

            ch = text.charAt(at);
            at += 1;
            return ch;
        },

        number = function () {

// Parse a number value.

            var number,
                string = '';

            if (ch === '-') {
                string = '-';
                next('-');
            }
            while (ch >= '0' && ch <= '9') {
                string += ch;
                next();
            }
            if (ch === '.') {
                string += '.';
                while (next() && ch >= '0' && ch <= '9') {
                    string += ch;
                }
            }
            if (ch === 'e' || ch === 'E') {
                string += ch;
                next();
                if (ch === '-' || ch === '+') {
                    string += ch;
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    string += ch;
                    next();
                }
            }
            number = +string;
            if (isNaN(number)) {
                error("Bad number");
            } else {
                return number;
            }
        },

        string = function () {

// Parse a string value.

            var hex,
                i,
                string = '',
                uffff;

// When parsing for string values, we must look for " and \ characters.

            if (ch === '"') {
                while (next()) {
                    if (ch === '"') {
                        next();
                        return string;
                    } else if (ch === '\\') {
                        next();
                        if (ch === 'u') {
                            uffff = 0;
                            for (i = 0; i < 4; i += 1) {
                                hex = parseInt(next(), 16);
                                if (!isFinite(hex)) {
                                    break;
                                }
                                uffff = uffff * 16 + hex;
                            }
                            string += String.fromCharCode(uffff);
                        } else if (typeof escapee[ch] === 'string') {
                            string += escapee[ch];
                        } else {
                            break;
                        }
                    } else {
                        string += ch;
                    }
                }
            }
            error("Bad string");
        },

        white = function () {

// Skip whitespace.

            while (ch && ch <= ' ') {
                next();
            }
        },

        word = function () {

// true, false, or null.

            switch (ch) {
            case 't':
                next('t');
                next('r');
                next('u');
                next('e');
                return true;
            case 'f':
                next('f');
                next('a');
                next('l');
                next('s');
                next('e');
                return false;
            case 'n':
                next('n');
                next('u');
                next('l');
                next('l');
                return null;
            }
            error("Unexpected '" + ch + "'");
        },

        value,  // Place holder for the value function.

        array = function () {

// Parse an array value.

            var array = [];

            if (ch === '[') {
                next('[');
                white();
                if (ch === ']') {
                    next(']');
                    return array;   // empty array
                }
                while (ch) {
                    array.push(value());
                    white();
                    if (ch === ']') {
                        next(']');
                        return array;
                    }
                    next(',');
                    white();
                }
            }
            error("Bad array");
        },

        object = function () {

// Parse an object value.

            var key,
                object = {};

            if (ch === '{') {
                next('{');
                white();
                if (ch === '}') {
                    next('}');
                    return object;   // empty object
                }
                while (ch) {
                    key = string();
                    white();
                    next(':');
                    if (Object.hasOwnProperty.call(object, key)) {
                        error('Duplicate key "' + key + '"');
                    }
                    object[key] = value();
                    white();
                    if (ch === '}') {
                        next('}');
                        return object;
                    }
                    next(',');
                    white();
                }
            }
            error("Bad object");
        };

    value = function () {

// Parse a JSON value. It could be an object, an array, a string, a number,
// or a word.

        white();
        switch (ch) {
        case '{':
            return object();
        case '[':
            return array();
        case '"':
            return string();
        case '-':
            return number();
        default:
            return ch >= '0' && ch <= '9' ? number() : word();
        }
    };

// Return the json_parse function. It will have access to all of the above
// functions and variables.

    return function (source, reviver) {
        var result;

        text = source;
        at = 0;
        ch = ' ';
        result = value();
        white();
        if (ch) {
            error("Syntax error");
        }

// If there is a reviver function, we recursively walk the new structure,
// passing each name/value pair to the reviver function for possible
// transformation, starting with a temporary root object that holds the result
// in an empty key. If there is not a reviver function, we simply return the
// result.

        return typeof reviver === 'function' ? function walk(holder, key) {
            var k, v, value = holder[key];
            if (value && typeof value === 'object') {
                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = walk(value, k);
                        if (v !== undefined) {
                            value[k] = v;
                        } else {
                            delete value[k];
                        }
                    }
                }
            }
            return reviver.call(holder, key, value);
        }({'': result}, '') : result;
    };
}();
/* End json_parse.js */

/* From buttons.js */
function buttonOver(elementId, height) {
    document.getElementById(elementId).style.backgroundPosition = "0px -" + height + "px";
}

function buttonOut(elementId, height) {
    document.getElementById(elementId).style.backgroundPosition = "0px 0px";
}

function buttonUp(elementId, height) {
    document.getElementById(elementId).style.backgroundPosition = "0px -" + height + "px";
}

function buttonDown(elementId, height) {
    document.getElementById(elementId).style.backgroundPosition = "0px -" + (2 * height) + "px";
}

function tabOver(elementId) {
    document.getElementById(elementId).style.backgroundPosition = "0px -21px";
}

function tabOut(elementId) {
    document.getElementById(elementId).style.backgroundPosition = "0px 0px";
}
/* End buttons.js */



/* #############################################################################
UTF-8 Decoder and Encoder
base64 Encoder and Decoder
written by Tobias Kieslich, justdreams
Contact: tobias@justdreams.de               http://www.justdreams.de/
############################################################################# */

/**
 * base64_encode
 * Usage: if (myString.base64_encode()) {
 */
String.prototype.base64_encode = function()
{
    var arr = utf8t2d(this);
    var base64encoded = b64d2t(arr);
    return base64encoded
};

String.prototype.trim = function(){
    try {
        return this.replace(/^\s+|\s+$/g, "");
    } catch(e) {
        return this;
    }
}

String.prototype.base64_decode = function()
{
    var arr = b64t2d(this);
    var base64decoded = utf8d2t(arr);
    return base64decoded
};



function utf8t2d(t) {
    t = t.replace(/\r\n/g,"\n");
    var d=new Array; var test=String.fromCharCode(237);
    if (test.charCodeAt(0) < 0) 
        for(var n=0; n<t.length; n++)
            {
            var c=t.charCodeAt(n);
            if (c>0)
                d[d.length]= c;
            else {
                d[d.length]= (((256+c)>>6)|192);
                d[d.length]= (((256+c)&63)|128);}
            }
    else
        for(var n=0; n<t.length; n++)
            {
            var c=t.charCodeAt(n);
            // all the signs of asci => 1byte
            if (c<128)
                d[d.length]= c;
            // all the signs between 127 and 2047 => 2byte
            else if((c>127) && (c<2048)) {
                d[d.length]= ((c>>6)|192);
                d[d.length]= ((c&63)|128);}
            // all the signs between 2048 and 66536 => 3byte
            else {
                d[d.length]= ((c>>12)|224);
                d[d.length]= (((c>>6)&63)|128);
                d[d.length]= ((c&63)|128);}
            }
    return d;
}
        

function utf8d2t(d)
    {
    var r=new Array; var i=0;
    while(i<d.length)
        {
        if (d[i]<128) {
            r[r.length]= String.fromCharCode(d[i]); i++;}
        else if((d[i]>191) && (d[i]<224)) {
            r[r.length]= String.fromCharCode(((d[i]&31)<<6) | (d[i+1]&63)); i+=2;}
        else {
            r[r.length]= String.fromCharCode(((d[i]&15)<<12) | ((d[i+1]&63)<<6) | (d[i+2]&63)); i+=3;}
        }
    return r.join("");
}


function b64arrays(dir) {
    var b64s='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    b64 = new Array();f64 =new Array();
    for (var i=0; i<b64s.length ;i++) {
        b64[i] = b64s.charAt(i);
        f64[b64s.charAt(i)] = i;
    }
        
    return (dir == 'b' ? b64 : f64);
}

function b64d2t(d) {
    var b64 = b64arrays('b');
    var r=new Array; var i=0; var dl=d.length;
    // this is for the padding
    if ((dl%3) == 1) {
        d[d.length] = 0; d[d.length] = 0;}
    if ((dl%3) == 2)
        d[d.length] = 0;
    // from here conversion
    while (i<d.length)
        {
        r[r.length] = b64[d[i]>>2];
        r[r.length] = b64[((d[i]&3)<<4) | (d[i+1]>>4)];
        r[r.length] = b64[((d[i+1]&15)<<2) | (d[i+2]>>6)];
        r[r.length] = b64[d[i+2]&63];
        if ((i%57)==54)
            r[r.length] = "\n";
        i+=3;
        }
    // this is again for the padding
    if ((dl%3) == 1)
        r[r.length-1] = r[r.length-2] = "=";
    if ((dl%3) == 2)
        r[r.length-1] = "=";
    // we join the array to return a textstring
    var t=r.join("");
    return t;
}


function b64t2d(t) {
    var b64 = b64arrays('f');
    var d=new Array; var i=0;
    // here we fix this CRLF sequenz created by MS-OS; arrrgh!!!
    t=t.replace(/\n|\r/g,""); t=t.replace(/=/g,"");
    while (i<t.length)
        {
        d[d.length] = (f64[t.charAt(i)]<<2) | (f64[t.charAt(i+1)]>>4);
        d[d.length] = (((f64[t.charAt(i+1)]&15)<<4) | (f64[t.charAt(i+2)]>>2));
        d[d.length] = (((f64[t.charAt(i+2)]&3)<<6) | (f64[t.charAt(i+3)]));
        i+=4;
        }
    if (t.length%4 == 2)
        d = d.slice(0, d.length-2);
    if (t.length%4 == 3)
        d = d.slice(0, d.length-1);
    return d;
}
/* end decoder / encoder */

ObjectIdGenerator = Class.create();
ObjectIdGenerator.prototype = {
    initialize: function() {
        this.id = 0;
    },
    setId: function(id) {
        this.id = id;
    },
    getId: function() {
        return ++this.id;
    }
};
ObjectIdGenerator = new ObjectIdGenerator();

CommonUtils = Class.create();
CommonUtils.showErrorMsgFromHtml = function(html) {
    html = html.slice(html.search('<p class="error">') + 17);
    html = html.slice(0, html.search('</p>'));
    if (html != '') {
        alert(html);
    }
}
CommonUtils.cursorWait = function() {
    document.body.style.cursor = "wait";
}
CommonUtils.cursorDefault = function() {
    document.body.style.cursor = "default";
}

XMLUtils = Class.create();
XMLUtils.getXMLValue = function(element) {
    if (element.firstChild != null) {
        return element.firstChild.nodeValue;
    } else {
        return '';
    }
}

URLUtils = Class.create();
URLUtils.hasParams = function(url) {
    var reg = new RegExp("\\?");
    return reg.test(url);
}
URLUtils.hasDBW = function(url) {
    var reg = new RegExp("dbw=true");
    return reg.test(url);
}
URLUtils.hasAncor = function(url) {
    var reg = new RegExp("#");
    return reg.test(url);
}

StringUtils = Class.create();
StringUtils.startsWith = function(string, pattern) {
    var reg = new RegExp("^" + pattern);
    return reg.test(string);
}
StringUtils.endsWith = function(string, pattern) {
    // prototype function
    return string.endsWith(pattern);
}
StringUtils.nl2br = function(string) {
    if (string == null) {
        return '';
    }
    var reg = new RegExp(/\n/g);
    return string.replace(reg, '<br/>');
}
StringUtils.errorObjectToString = function(object) {
    var buffer = '';
    for (var i in object) {
        buffer += object[i] + "\n";
    }
    return buffer;
}
StringUtils.isEmail = function(string) {
    var reg = new RegExp("^.*@.*$");
    return reg.test(string);
}

ObjectUtils = Class.create();
ObjectUtils.dynamicHeight = function(element, maxHeight, parent) {
	var obj = $(element);
	var tol = 15;
	var parentObj = $(parent);
	var diff = parentObj.offsetHeight - obj.offsetHeight;
	
	if ((diff+maxHeight) > 264) {
		maxHeight = (maxHeight - ((diff+maxHeight) - 264)) - tol;
	}			
		
	if (obj.offsetHeight > maxHeight) {
		obj.style.height = maxHeight + "px";
	}
}
ObjectUtils.empty = function(object) {
    if (object == null || object == 'undefined' || object == '') {
        return true;
    }
    return false;
}

FileUtils = Class.create();
FileUtils.getFileSize = function(fileSize) {
	var size = '';
	if (fileSize >= 1073741824) {
		size = Math.round(fileSize / 1024 / 1024 / 1024) + " GB";
	} else if (fileSize >= 1048576) {
		size = Math.round(fileSize / 1024 / 1024) + " MB";
	} else if (fileSize >= 1024) {
		size = Math.round(fileSize / 1024) + " KB";
	} else {
		size = fileSize + " Bytes";
	}
	return size;
}

/**
 * This Class makes a request and calls back on caller, by the given object and the function given as string.
 */
 
// @todo: CommonUtils.showErrorMsgFromHtml(text);
RequestUtils = Class.create();
RequestUtils.prototype = {
    initialize: function() {
    },
	request: function(callerObject, callbackFunction, url, params) {
	    params = params || {};
		var opt = {
		    method: 'post',
		    parameters: params,
		    onSuccess: function(t) {
		        callerObject[callbackFunction](json_parse(t.responseText));
		    }
		};
	
	    Logger.debug('request to [' + url + ']');
		new Ajax.Request(url, opt);
    }
};
RequestUtils = new RequestUtils();

Logger = Class.create();
Logger.isDebug = false;
Logger.debugType = 'alert';
Logger.enable = function(debugType) {
    Logger.isDebug = true;
    Logger.debugType = debugType || 'alert';
    Logger.debug('Logging enabled');
}
Logger.debug = function(msg) {
    if (Logger.isDebug) {
        if (Logger.debugType == 'console' && typeof console == 'object') {
            console.debug(msg);
        } else if (Logger.debugType == 'alert') {
            alert(msg);
        }
    }
}

/**
 * Function : dump()
 * Arguments: The data - array,hash(associative array),object
 *    The level - OPTIONAL
 * Returns  : The textual representation of the array.
 * This function was inspired by the print_r function of PHP.
 * This will accept some data as the argument and return a
 * text that will be a more readable version of the
 * array/hash/object that is given.
 * Docs: http://www.openjs.com/scripts/others/dump_function_php_print_r.php
 */
Logger.dump = function(arr,level) {
	var dumped_text = "";
	if(!level) level = 0;
	
	//The padding given at the beginning of the line.
	var level_padding = "";
	for(var j=0;j<level+1;j++) level_padding += "    ";
	
	if(typeof(arr) == 'object') { //Array/Hashes/Objects 
		for(var item in arr) {
			var value = arr[item];
			
			if(typeof(value) == 'object') { //If it is an array,
				dumped_text += level_padding + "'" + item + "' ...\n";
				dumped_text += dump(value,level+1);
			} else {
				dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
			}
		}
	} else { //Stings/Chars/Numbers etc.
		dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
	}
	Logger.debug(dumped_text);
}

/*
 * Element handling
 */
ElementToggler = Class.create();
ElementToggler.prototype = {
    initialize: function(elementToToggle, toggleElement, toggleElementTextVisible, toggleElementTextInvisible) {
        this.elementToToggle = $(elementToToggle);
        this.toggleElement = $(toggleElement);
        this.toggleElementTextVisible = toggleElementTextVisible ? toggleElementTextVisible : null;
        this.toggleElementTextInvisible = toggleElementTextInvisible ? toggleElementTextInvisible : null;
        this.toggleVisibile = this.elementToToggle.visible();
        
        Event.observe(this.toggleElement, "click", this.onToggle.bindAsEventListener(this), false);
    },
    
    onToggle: function() {
        if (this.toggleVisibile) {
            this.elementToToggle.style.display = 'none';
            if (this.toggleElementTextVisible != null) {
                this.toggleElement.innerHTML = this.toggleElementTextVisible;
            }
        } else {
            this.elementToToggle.style.display = '';
            if (this.toggleElementTextInvisible != null) {
                this.toggleElement.innerHTML = this.toggleElementTextInvisible;
            }
        }
        this.toggleVisibile = ! this.toggleVisibile;
    }
};

/* From document.js */
function setPageInactive() {
    var availHeight;
    var pageHeight;
    var dialogBgHeight;
    
    if (self.innerHeight) { // all except Explorer
        availHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
        // Explorer 6 Strict Mode
        availHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
        availHeight = document.body.clientHeight;
    }
    
    var test1 = document.body.scrollHeight;
    var test2 = document.body.offsetHeight
    if (test1 > test2) { // all but Explorer Mac
        pageHeight = document.body.scrollHeight;
    } else {
        // Explorer Mac;
        //would also work in Explorer 6 Strict, Mozilla and Safari
        pageHeight = document.body.offsetHeight;
    }
    
    if (availHeight > pageHeight) {
        dialogBgHeight = availHeight;
    } else {
        dialogBgHeight = pageHeight;
    }
    
    document.getElementById("hideWindowedControlsBg").style.height = dialogBgHeight + "px";
    document.getElementById("hideWindowedControls").style.height = dialogBgHeight + "px";
    
    document.getElementById("hideWindowedControlsBg").style.display = "block";
    document.getElementById("hideWindowedControls").style.display = "block";
    
    window.onresize = resizePage;
}

function setPageActive() {
    document.getElementById("hideWindowedControlsBg").style.display = "none";
    document.getElementById("hideWindowedControls").style.display = "none";
    
    window.onresize = null;
}

function resizePage() {
    if (document.getElementById("hideWindowedControlsBg").style.display == "block") {
        setPageInactive();
    }
}

function toggleDisplay(id) {
    element = document.getElementById(id);
    if (element.style.display == 'none') {
        element.style.display = 'block';
    } else {
        element.style.display = 'none';
    }
}

function toggleVisibility(id) {
    var element = document.getElementById(id);
    if (element.style.visibility == 'visible') {
        element.style.visibility = 'hidden';
    } else {
        element.style.visibility = 'visible';
    }
}
/* End document.js */
 
/*
 * HTML Output
 */
HTMLDateOutput = Class.create();
HTMLDateOutput.prototype = {
    initialize: function() {
        this.months = {
            '01': 'Jan',
            '02': 'Feb',
            '03': 'Mar',
            '04': 'Apr',
            '05': 'May',
            '06': 'Jun',
            '07': 'Jul',
            '08': 'Aug',
            '09': 'Sep',
            '10': 'Oct',
            '11': 'Nov',
            '12': 'Dec'
        };
    },
    toDate: function(value) {
        if (value == null || value == '') {
            return '';
        }
        var splitted = value.split('-');
        
        return this.months[splitted[1]] + ' ' + splitted[2] + ', ' + splitted[0];
    },
    toDateMonth: function(value) {
        if (value == null || value == '') {
            return '';
        }
        var splitted = value.split('-');
        
        return this.months[splitted[1]] + ', ' + splitted[0];
    }
}
HTMLDateOutput = new HTMLDateOutput();

/*
 * HTMLInput
 */
HTMLDateSelect = Class.create();
HTMLDateSelect.prototype = {
    initialize: function(id, type, selected) {
        this.id = id;
        this.type = type;
        this.selected = selected || '';
        
        this.yearMin = 1900;
        this.yearMax = 2020;
        this.months = {
            1: 'Jan',
            2: 'Feb',
            3: 'Mar',
            4: 'Apr',
            5: 'May',
            6: 'Jun',
            7: 'Jul',
            8: 'Aug',
            9: 'Sep',
            10: 'Oct',
            11: 'Nov',
            12: 'Dec'
        };
        
        this.dayMin = 1;
        this.dayMax = 31;
    },
    getFieldId: function(type) {
        var tpl = new Array();
        if (type == 'D') {
            return this.id + 'day';
        }
        if (type == 'M') {
            return this.id + 'month'
        }
        if (type == 'Y') {
            return this.id + 'year';
        }
        return null;
    },
    toString: function() {
        var tpl = new Array();
        if (this.type.match('D')) {
            tpl.push(this.createDay());
        }
        if (this.type.match('M')) {
            tpl.push(this.createMonth());
        }
        if (this.type.match('Y')) {
            tpl.push(this.createYear());
        }
        return tpl.join('');
    },
    createYear: function() {
        var splitted = this.selected.split('-');
        var selectedYear = '';
        if (splitted.length == 3) {
            selectedYear = splitted[0];
        }
        var tpl = '';
        tpl += '<select id="' + this.id + 'year" class="year">';
        tpl += '<option value="">----</option>';
        for (var i = this.yearMax; i >= this.yearMin; i--) {
            tpl += '<option value="' + i + '"';
            if (i == selectedYear) {
                tpl += ' SELECTED="SELECTED"';
            }
            tpl += '>' + this._get2DigetValue(i) + '</option>';
        }
        tpl += '</select>';
        return tpl;
    },
    createMonth: function() {
        var splitted = this.selected.split('-');
        var selectedMonth = '';
        if (splitted.length == 3) {
            selectedMonth = splitted[1];
        }
        var tpl = '';
        tpl += '<select id="' + this.id + 'month" class="month">';
        tpl += '<option value="">--</option>';
        for (var i in this.months) {
            var value = this.months[i];
            i = this._get2DigetValue(i);
            tpl += '<option value="' + i + '"';
            if (i == selectedMonth) {
                tpl += ' SELECTED="SELECTED"';
            }
            tpl += '>' + value + '</option>';
        }
        tpl += '</select>';
        return tpl;
    },
    createDay: function() {
        var splitted = this.selected.split('-');
        var selectedDay = '';
        if (splitted.length == 3) {
            selectedDay = splitted[2];
        }
        var tpl = '';
        tpl += '<select id="' + this.id + 'day" class="day">';
        tpl += '<option value="">--</option>';
        for (var i = this.dayMin; i <= this.dayMax; i++) {
            tpl += '<option value="' + this._get2DigetValue(i) + '"';
            if (i == selectedDay) {
                tpl += ' SELECTED="SELECTED"';
            }
            tpl += '>' + this._get2DigetValue(i) + '</option>';
        }
        tpl += '</select>';
        return tpl;
    },
    _get2DigetValue: function(val) {
        if (val > 0 && val < 10) {
            val = '0' + val;
        }
        return val;
    },
    getDateValue: function() {
        var year = '1970';
        var month = '01';
        var day = '01';
        
        if (this.type.match('D')) {
            day = $(this.id + 'day').value;
        }
        if (this.type.match('M')) {
            month = $(this.id + 'month').value;
        }
        if (this.type.match('Y')) {
            year = $(this.id + 'year').value;
        }
        
        return year + '-' + month + '-' + day;
    },
    showError: function() {
        if (this.type.match('D')) {
            $(this.id + 'day').className = $(this.id + 'day').className + ' error';
        }
        if (this.type.match('M')) {
            $(this.id + 'month').className = $(this.id + 'month').className + ' error';
        }
        if (this.type.match('Y')) {
            $(this.id + 'year').className = $(this.id + 'year').className + ' error';
        }
    }
};

HTMLDateComponent = Class.create();
HTMLDateComponent.prototype = {
    initialize: function(id, fieldName, type, selected) {
        this.id = id;
        this.selected = selected;
        this.dateSelect = new HTMLDateSelect(id, type, selected);
        this.hiddenId = this.id + 'hidden';
        this.fieldName= fieldName;
    },
    show: function() {
        $(this.id).innerHTML = '<input id="' + this.hiddenId + '" type="hidden" name="' + this.fieldName + '" value="" />' + this.dateSelect.toString();

        if ($(this.dateSelect.getFieldId('Y')) != null) {
	        Event.observe(this.dateSelect.getFieldId('Y'), "change", this.update.bindAsEventListener(this));
	    }
        if ($(this.dateSelect.getFieldId('M')) != null) {
	        Event.observe(this.dateSelect.getFieldId('M'), "change", this.update.bindAsEventListener(this));
	    }
        if ($(this.dateSelect.getFieldId('D')) != null) {
            Event.observe(this.dateSelect.getFieldId('D'), "change", this.update.bindAsEventListener(this));
        }
        
        if (this.selected != null && this.selected != undefined && this.selected != '') {
            this.update();
        }
    },
    showError: function() {
        this.dateSelect.showError();
    },
    update: function() {
        $(this.hiddenId).value = this.dateSelect.getDateValue();
    }
};

FieldMerger = Class.create();
FieldMerger.prototype = {
    initialize: function(dateId, timeId, hiddenId) {
        this.dateId = dateId;
        this.timeId = timeId;
        this.hiddenId = hiddenId;
        Event.observe(dateId, "change", this.update.bindAsEventListener(this));
        Event.observe(timeId, "change", this.update.bindAsEventListener(this));
    },
    update: function() {
        $(this.hiddenId).value = $(this.dateId).value + ' ' + $(this.timeId).value;
    }
};

/*
 * Functions
 */
function forwardToSearchAgent(queryElementId, agentElements) {

    var url = 'search.SearchAgentCreate.html';
    
    var query = $(queryElementId).value;
    
    if (query == '') {
        alert('You have to specify a search query.');
        return;
    }
    
    var params = new Array;
    for (var i = 0; i < agentElements.length; i++) {
        if ($(agentElements[i]).checked) {
            params.push('search_sources[' + $(agentElements[i]).name + ']=true');
        }
    }
    var forwardUrl = url + '?search_query=' + escape(query) + '&' + params.join('&');
//    Logger.debug(forwardUrl);

    document.location = forwardUrl;
}

function get_html_translation_table(table, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js. Meaning the constants are not
    // %          note: real constants, but strings instead. integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // %          note: Table from http://www.the-art-of-web.com/html/character-codes/
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}
    
    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    
    useTable      = (table ? table.toUpperCase() : 'HTML_SPECIALCHARS');
    useQuoteStyle = (quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT');
    
    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';
    
    // Map numbers to strings for compatibilty with PHP constants
    if (!isNaN(useTable)) {
        useTable = constMappingTable[useTable];
    }
    if (!isNaN(useQuoteStyle)) {
        useQuoteStyle = constMappingQuoteStyle[useQuoteStyle];
    }
    
    if (useQuoteStyle != 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
 
    if (useQuoteStyle == 'ENT_QUOTES') {
        entities['39'] = '&#039;';
    }
 
    if (useTable == 'HTML_SPECIALCHARS') {
        // ascii decimals for better compatibility
        entities['38'] = '&amp;';
        entities['60'] = '&lt;';
        entities['62'] = '&gt;';
    } else if (useTable == 'HTML_ENTITIES') {
        // ascii decimals for better compatibility
      entities['38']  = '&amp;';
      entities['60']  = '&lt;';
      entities['62']  = '&gt;';
      entities['160'] = '&nbsp;';
      entities['161'] = '&iexcl;';
      entities['162'] = '&cent;';
      entities['163'] = '&pound;';
      entities['164'] = '&curren;';
      entities['165'] = '&yen;';
      entities['166'] = '&brvbar;';
      entities['167'] = '&sect;';
      entities['168'] = '&uml;';
      entities['169'] = '&copy;';
      entities['170'] = '&ordf;';
      entities['171'] = '&laquo;';
      entities['172'] = '&not;';
      entities['173'] = '&shy;';
      entities['174'] = '&reg;';
      entities['175'] = '&macr;';
      entities['176'] = '&deg;';
      entities['177'] = '&plusmn;';
      entities['178'] = '&sup2;';
      entities['179'] = '&sup3;';
      entities['180'] = '&acute;';
      entities['181'] = '&micro;';
      entities['182'] = '&para;';
      entities['183'] = '&middot;';
      entities['184'] = '&cedil;';
      entities['185'] = '&sup1;';
      entities['186'] = '&ordm;';
      entities['187'] = '&raquo;';
      entities['188'] = '&frac14;';
      entities['189'] = '&frac12;';
      entities['190'] = '&frac34;';
      entities['191'] = '&iquest;';
      entities['192'] = '&Agrave;';
      entities['193'] = '&Aacute;';
      entities['194'] = '&Acirc;';
      entities['195'] = '&Atilde;';
      entities['196'] = '&Auml;';
      entities['197'] = '&Aring;';
      entities['198'] = '&AElig;';
      entities['199'] = '&Ccedil;';
      entities['200'] = '&Egrave;';
      entities['201'] = '&Eacute;';
      entities['202'] = '&Ecirc;';
      entities['203'] = '&Euml;';
      entities['204'] = '&Igrave;';
      entities['205'] = '&Iacute;';
      entities['206'] = '&Icirc;';
      entities['207'] = '&Iuml;';
      entities['208'] = '&ETH;';
      entities['209'] = '&Ntilde;';
      entities['210'] = '&Ograve;';
      entities['211'] = '&Oacute;';
      entities['212'] = '&Ocirc;';
      entities['213'] = '&Otilde;';
      entities['214'] = '&Ouml;';
      entities['215'] = '&times;';
      entities['216'] = '&Oslash;';
      entities['217'] = '&Ugrave;';
      entities['218'] = '&Uacute;';
      entities['219'] = '&Ucirc;';
      entities['220'] = '&Uuml;';
      entities['221'] = '&Yacute;';
      entities['222'] = '&THORN;';
      entities['223'] = '&szlig;';
      entities['224'] = '&agrave;';
      entities['225'] = '&aacute;';
      entities['226'] = '&acirc;';
      entities['227'] = '&atilde;';
      entities['228'] = '&auml;';
      entities['229'] = '&aring;';
      entities['230'] = '&aelig;';
      entities['231'] = '&ccedil;';
      entities['232'] = '&egrave;';
      entities['233'] = '&eacute;';
      entities['234'] = '&ecirc;';
      entities['235'] = '&euml;';
      entities['236'] = '&igrave;';
      entities['237'] = '&iacute;';
      entities['238'] = '&icirc;';
      entities['239'] = '&iuml;';
      entities['240'] = '&eth;';
      entities['241'] = '&ntilde;';
      entities['242'] = '&ograve;';
      entities['243'] = '&oacute;';
      entities['244'] = '&ocirc;';
      entities['245'] = '&otilde;';
      entities['246'] = '&ouml;';
      entities['247'] = '&divide;';
      entities['248'] = '&oslash;';
      entities['249'] = '&ugrave;';
      entities['250'] = '&uacute;';
      entities['251'] = '&ucirc;';
      entities['252'] = '&uuml;';
      entities['253'] = '&yacute;';
      entities['254'] = '&thorn;';
      entities['255'] = '&yuml;';
    } else {
        throw Error("Table: "+useTable+' not supported');
        return false;
    }
    
    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal)
        histogram[symbol] = entities[decimal];
    }
    
    return histogram;
}

function htmlentities (string) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: nobbler
    // +    tweaked by: Jack
    // +   bugfixed by: Onno Marsman
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // -    depends on: get_html_translation_table
    // *     example 1: htmlentities('Kevin & van Zonneveld');
    // *     returns 1: 'Kevin &amp; van Zonneveld'
    if (string == undefined) {
        return '';
    }
 
    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    
    quote_style = 'ENT_NOQUOTES';
    
    if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }
    
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }
    
    return tmp_str;
}

function decodeEmailAsLink(htmlId, base64String) {
    $(htmlId).href = 'mailto:' + base64String.base64_decode();
}

AjaxControl = Class.create({
    initialize: function(url, parameters){
        this.parameters = parameters ? parameters : {};
        this.url = url;
        this.lastRequest = null;
    },
    requestData: function(parameters){
        var usedParams = parameters ? parameters : this.parameters;
        this.lastRequest =
            new Ajax.Request(this.url, {
                method: 'get',
                parameters: usedParams,
                onSuccess: this.onAjaxResponse.bind(this),
                onFailure: this.onFailure.bind(this),
                onException: this.onException.bind(this)
            });
    },
    onAjaxResponse: function(transport){
        if (this.lastRequest != transport.request){
            return;
        }
        this.lastRequest = null;
        if (transport.responseJSON){
            if (transport.responseJSON.success){
                this.onDataReceived(transport.responseJSON.result);
            }else {
                this.onError(transport.responseJSON.errors);
            }
        }else {
            this.onError("Ungültige Antwort");
        }
    },
    onException: function(request, exception){
        this.onError("Fehler");
    },
    onFailure: function(message){        
        this.onError("Fehler");
    },
    onError: function(errors){
        //overwrite me
    },
    onDataReceived: function(json){
        //overwrite me
    }
});

DelayedObserver = Class.create({
    initialize: function(element, callback, delay){
        element.observe("keypress", this.onKeyPress.bind(this));
        element.observe("change", this.onChange.bind(this));
        this.delayedCallback = new DelayedCallback(callback, delay);
    },
    onKeyPress: function(){
        this.delayedCallback.call();
    },
    onChange: function(){
        this.delayedCallback.call();
    },
    reset: function(){
        this.delayedCallback.reset();
    }
});

DelayedCallback = Class.create({
    initialize: function(callback, delay){
        this.callback = callback;
        this.count = 0;
        this.ignore = 0;
        this.delay = delay ? delay * 1000 : 1000;
        this.lastArguments = null;
    },
    reset: function(){
        this.ignore = this.count;
        this.count = 0;
    },
    call: function(){
        this.count++;
        this.lastArguments = arguments;
        setTimeout(this.onTimeout.bind(this), this.delay);
    },
    onTimeout: function(){        
        if (this.ignore > 0){
            this.ignore--;
        } else {
            this.count--;
            if (this.count == 0){
                this.callback.apply(this, this.lastArguments);
            }
        }
    }
});

/*!
 * jQuery replaceText - v1.1 - 11/21/2009
 * http://benalman.com/projects/jquery-replacetext-plugin/
 * 
 * Copyright (c) 2009 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */

// Script: jQuery replaceText: String replace for your jQueries!
//
// *Version: 1.1, Last updated: 11/21/2009*
// 
// Project Home - http://benalman.com/projects/jquery-replacetext-plugin/
// GitHub       - http://github.com/cowboy/jquery-replacetext/
// Source       - http://github.com/cowboy/jquery-replacetext/raw/master/jquery.ba-replacetext.js
// (Minified)   - http://github.com/cowboy/jquery-replacetext/raw/master/jquery.ba-replacetext.min.js (0.5kb)
// 
// About: License
// 
// Copyright (c) 2009 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
// 
// About: Examples
// 
// This working example, complete with fully commented code, illustrates one way
// in which this plugin can be used.
// 
// replaceText - http://benalman.com/code/projects/jquery-replacetext/examples/replacetext/
// 
// About: Support and Testing
// 
// Information about what version or versions of jQuery this plugin has been
// tested with, and what browsers it has been tested in.
// 
// jQuery Versions - 1.3.2, 1.4.1
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome, Opera 9.6-10.1.
// 
// About: Release History
// 
// 1.1 - (11/21/2009) Simplified the code and API substantially.
// 1.0 - (11/21/2009) Initial release

(function($){
  '$:nomunge'; // Used by YUI compressor.
  
  // Method: jQuery.fn.replaceText
  // 
  // Replace text in specified elements. Note that only text content will be
  // modified, leaving all tags and attributes untouched. The new text can be
  // either text or HTML.
  // 
  // Uses the String prototype replace method, full documentation on that method
  // can be found here: 
  // 
  // https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/String/Replace
  // 
  // Usage:
  // 
  // > jQuery('selector').replaceText( search, replace [, text_only ] );
  // 
  // Arguments:
  // 
  //  search - (RegExp|String) A RegExp object or substring to be replaced.
  //    Because the String prototype replace method is used internally, this
  //    argument should be specified accordingly.
  //  replace - (String|Function) The String that replaces the substring received
  //    from the search argument, or a function to be invoked to create the new
  //    substring. Because the String prototype replace method is used internally,
  //    this argument should be specified accordingly.
  //  text_only - (Boolean) If true, any HTML will be rendered as text. Defaults
  //    to false.
  // 
  // Returns:
  // 
  //  (jQuery) The initial jQuery collection of elements.
  
  $.fn.replaceText = function( search, replace, text_only ) {
    return this.each(function(){
      var node = this.firstChild,
        val,
        new_val,
        
        // Elements to be removed at the end.
        remove = [];
      
      // Only continue if firstChild exists.
      if ( node ) {
        
        // Loop over all childNodes.
        do {
          
          // Only process text nodes.
          if ( node.nodeType === 3 ) {
            
            // The original node value.
            val = node.nodeValue;
            
            // The new value.
            new_val = val.replace( search, replace );
            
            // Only replace text if the new value is actually different!
            if ( new_val !== val ) {
              
              if ( !text_only && /</.test( new_val ) ) {
                // The new value contains HTML, set it in a slower but far more
                // robust way.
                $(node).before( new_val );
                
                // Don't remove the node yet, or the loop will lose its place.
                remove.push( node );
              } else {
                // The new value contains no HTML, so it can be set in this
                // very fast, simple way.
                node.nodeValue = new_val;
              }
            }
          }
          
        } while ( node = node.nextSibling );
      }
      
      // Time to remove those elements!
      remove.length && $(remove).remove();
    });
  };  
  
})(jQuery);

