/**
 * @author Falko Zander, www.falko-zander.de
 * 
 * contained objects:
 * - ClassnameUtils
 * - ObjectUtils
 * - ArrayUtils
 * - SelectboxUtils
 * - ViewUtils
 * - cTree
 * - cEventHandler
 * - cEvent
 */

var IE = (document.all) ? 1 : 0;

/**
 * @param msg String
 * @param doalert Boolean
 */
function log(msg, doalert) {
    if (typeof doalert == 'undefined') doalert = 0;

    if (window.console) {
        window.console.log(msg);
    } else if (typeof opera != 'undefined' && opera.postError) {
        opera.postError(msg);
    } else if (doalert != 0) {
        alert(msg);
    } /*else {
        error("utils: log error");
    }*/
}

/**
 * @param msg String
 */
function error(msg) {
    log(msg, 1);
    throw new Error(msg);
}

/**
 * @param id String
 * @return Element
 */
function $(id) {
    return document.getElementById(id);
}

/**
 * @param type String
 * @return Element
 */
function $$(type) {
    return document.createElement(type);
}

String.prototype.reverse = function() {
    return this.split('').reverse().join('');
}

/**
 * @param node Element
 * @param attr String
 * @return Object
 */
function getElementsByAttributeName(node, attr) {
    var d = [];
    for (var i = node.childNodes.length - 1; i >= 0; i--) {
        if (node.childNodes[i].nodeType == 1) {
            if (node.childNodes[i].getAttribute(attr) != null) {
               d.push(node.childNodes[i]);
            }
            d = d.concat(getElementsByAttributeName(node.childNodes[i], attr));
        }
    }
    return d;
}

/**
 * @param node Element
 * @param attr String
 * @param value String
 * @return Element
 */
function getElementByAttributeValue(node, attr, value) {
    for (var i = node.childNodes.length - 1; i >= 0; i--) {
        if (node.childNodes[i].nodeType == 1) {
            var a = node.childNodes[i].getAttribute(attr);
            if (a != null) {
                if (a == value) return node.childNodes[i];
            }
            var r = getElementByAttributeValue(node.childNodes[i], attr, value);
            if (r != null) return r;
        }
    }
    return null;
}

/**
 * @param node Element
 * @param elems Object
 * @return Object
 */
function getElementsByParamset(node, elems) {
    var d = {};
    for (var i = node.childNodes.length - 1; i >= 0; i--) {
        if (node.childNodes[i].nodeType == 1) {
            var a = node.childNodes[i].getAttribute('dgo_name');
            if (a != null) {
                for (var j = elems.length - 1; j >= 0; j--) {
                    if (a == elems[j]) {
                        if (d[elems[j]] == null) d[elems[j]] = [];
                        d[elems[j]].push(node.childNodes[i].id);
                    }
                }
            }
            var r = this.getElementsByParamset(node.childNodes[i], elems);
            for (var x in r) {
                if (d[x] == null) {
                    d[x] = r[x];
                } else {
                    d[x] = d[x].concat(r[x]);
                }
            }
        }
    }
    return d;
}

/**
 * @param node Element
 */
function removeAllChilds(node) {
    while (node.childNodes[0]) {
        node.removeChild(node.childNodes[0]);
    }
}

/**
 * @param mode Number
 */
function change_size_comment(mode) {
    var e = $('et_comment_new');
    if (e == null) return;
    
    if (mode == 1) {
        e.rows = e.rows + 3;
    } else if (e.rows > 6) {
        e.rows = e.rows - 3; 
    }
}

/**
 * @param node Element
 * @return Object
 */
function getDgoNodeParam(node) {
    if (node == null) return null;

    var params = {};
    var p = node.getAttribute('dgo_param');
    if (p == null || p == '') return null;
    
    p = p.replace(/ /g, '');

    var pl = p.split(';');
    for (var i = 0; i < pl.length; i++) {
        var d = pl[i].split(':');

        params[d[0]] = (d.length > 1) ? d[1] : 1;
    }

    return params;
}

/**
 * @param node Element
 * @param params Object
 */
function setDgoNodeParam(node, params) {
    var txt = '';
    for (var i in params) {
        txt += i + ':' + params[i] + ';';
    }
    
    node.setAttribute('dgo_param', txt);
}

/**
 * @param elem Element
 * @return Object
 */
function getAbsoluteDimensions(elem) {
    var r = {
        offsetWidth: elem.offsetWidth,
        offsetHeight: elem.offsetHeight,
        offsetLeft: elem.style.pixelLeft || elem.offsetLeft,
        rel_offsetLeft: elem.style.pixelLeft || elem.offsetLeft,
        offsetTop: elem.style.pixelTop || elem.offsetTop,
        rel_offsetTop: elem.style.pixelTop || elem.offsetTop,
        parentsLeft: 0,
        parentsTop: 0
    }
    var par = elem.offsetParent;
    while (par) {
        r.offsetLeft += parseInt(par.offsetLeft);
        r.offsetTop += parseInt(par.offsetTop);
        r.parentsLeft += parseInt(par.offsetLeft);
        r.parentsTop += parseInt(par.offsetTop);
        par = par.offsetParent;
    }
    return r;
}

var ClassnameUtils = {
    /**
     * @param obj Element
     * @param cn String
     */
    add: function(obj, cn) {
        if (obj == null || cn == '') return;

        var cns = obj.className ? obj.className.split(' ') : [];

        for (var i = cns.length - 1; i >= 0; i--) {
            if (cns[i] == cn) return;
        }

        obj.className += ((obj.className.length > 0) ? ' ' : '') + cn;
    },

    /**
     * @param obj Element
     * @param cn String
     */
    remove: function(obj, cn) {
        if (obj == null || cn == '') return;

        var cns = obj.className ? obj.className.split(' ') : [];

        var ncns = [];
        for (var i = cns.length - 1; i >= 0; i--) {
            if (cns[i] != cn) {
                ncns.push(cns[i]);
            }
        }

        if (ncns.length > 0) {
            obj.className = ncns.join(' ');
        } else {
            obj.className = '';
        }
    },
    
    /**
     * @param obj Element
     * @param cn String
     * @return Boolean
     */
    has: function(obj, cn) {
        if (obj == null || cn == '') return false;
        
        var cns = obj.className ? obj.className.split(' ') : [];
        for (var i = cns.length - 1; i >= 0; i--) {
            if (cns[i] == cn) return true;
        }
        
        return false;
    }
};

var ObjectUtils = {
    /**
     * @param object Object
     * @return Object
     */
    copy: function(object) {
        if (typeof object != 'object' || object == null) return null;
        var onew = {};
        for (var o in object) {
            onew[o] = object[o];
        }
        return onew;
    },
    
    /**
     * @param object1 Object
     * @param object2 Object
     * @return Object
     */
    concate: function(object1, object2) {
        if (typeof object1 != 'object') return null;
        if (typeof object2 != 'object' || object2 == null) return this.copy(object1);
        
        var onew = this.copy(object1);
        for (var o in object2) {
            onew[o] = object2[o];
        }
        
        return onew;
    },
    
    /**
     * @param object Object
     * @param array Array
     * @param key String
     * @param keyvalue Object
     * @return Object
     */
    update_from_array_over_key: function(object, array, key, keyvalue) {
        if (typeof array != 'object' || typeof object != 'object') return null;
        
        for (var i = array.length - 1; i >= 0; i--) { 
            if (array[i][key] == keyvalue) {
                for (var o in array[i]) {
                    if (object[o] != null) {
                        object[o] = array[i][o];
                    }
                }
            }
        }
        
        return object;
    },
    
    /**
     * @param object1 Object
     * @param object2 Object
     * @return Boolean
     */
    compare: function(object1, object2) {
        if (typeof object1 != typeof object2) return false;
        
        for (var o1 in object1) {
            if (object1[o1] != object2[o1]) return false;
        }
        for (var o2 in object2) {
            if (object1[o2] != object2[o2]) return false;
        }
        
        return true;
    }
};

var ArrayUtils = {
    /**
     * @param array Array
     * @return Number
     */    
    get_max_nbr: function(array) {
        if (typeof array != 'object') error('ArrayUtils.get_max_nbr: wrong param');
    
        var max = 0;
        for (var i = array.length - 1; i >= 0; i--) {
            max = Math.max(array[i], max);
        }
        return max;
    },

    /**
     * @param array Array
     * @param elem Object
     * @return Array
     */
    rem_elem: function(array, elem, f_compare) {
        if (typeof array != 'object') error('ArrayUtils.rem_elem: wrong param');
        
        var anew = this.copy(array);
        var pos = this.is_in(array, elem, f_compare);
        if (pos != -1) {
            anew.splice(pos, 1);
        }
        
        return anew;
    },
    
    /**
     * @param array Array
     * @return Array
     */
    copy: function(array) {
        if (typeof array != 'object') error('ArrayUtils.copy: wrong param');
        
        if (array == null) return null;
        var anew = [];
        for (var i = 0; i < array.length; i++) {
            anew.push(array[i]);
        }
        return anew;
    },
    
    /**
     * @param array Array
     * @param elem Object
     * @return Number
     */
    is_in: function(array, elem, f_compare) {
        if (typeof array != 'object') error('ArrayUtils.is_in: wrong param');
        
        var i;
        if (typeof f_compare == 'function') {
            for (i = array.length - 1; i >= 0; i--) {
                if (f_compare(array[i], elem) == 1) return i;
            }
        } else {
            for (i = array.length - 1; i >= 0; i--) {
                if (array[i] == elem) return i;
            }
        }
        return -1;
    },
    
    /**
     * @param array Array
     * @return Object
     */
    top: function(array) {
        if (typeof array != 'object') error('ArrayUtils.top: wrong param');
        
        return array[array.length - 1];
    },
    
    /**
     * @param array Array
     * @param object Object
     * @param key String
     * @param keyvalue Object
     * @return Array
     */
    update_from_object_over_key: function(array, object, key, keyvalue) {
        if (typeof array != 'object') error('ArrayUtils.update_from_object_over_key: wrong param');
        
        for (var i = array.length - 1; i >= 0; i--) {
            if (array[i][key] == keyvalue) {
                for (var o in array[i]) {
                    if (object[o] != null) {
                        array[i][o] = object[o];
                    }
                }
            }
        }
        
        return array;
    }
};

var SelectboxUtils = {
    /**
     * @param sbox Element
     * @param value String
     */
    select_option: function(sbox, value) {
        if (sbox == null) return;
    
        for (var i = sbox.length - 1; i >= 0; i--) {
            if (sbox[i].value == value) {
                sbox.selectedIndex = i;
                break;
            }
        }
    },
    
    /**
     * @param sbox Element
     * @param values Array
     * @param key String
     */
    select_options_from_array: function(sbox, values, key) {
        if (sbox == null) return;
        
        var i, j;
        
        for (i = sbox.length - 1; i >= 0; i--) { 
            sbox[i].selected = 0;
        }
        
        if (typeof key == 'string') {
            for (i = values.length - 1; i >= 0; i--) { 
                for (j = sbox.length - 1; j >= 0; j--) {
                    if (sbox[j].value == values[i][key]) {
                        sbox[j].selected = 1;
                    }
                }
            }
        } else {
            for (i = values.length - 1; i >= 0; i--) { 
                for (j = sbox.length - 1; j >= 0; j--) {
                    if (sbox[j].value == values[i]) {
                        sbox[j].selected = 1;
                    }
                }
            }
        }
    },
    
    /**
     * @param sbox Element
     * @param value String
     * @param newtext String
     */
    rename_by_value: function(sbox, value, newtext) {
        if (sbox == null || value == null || newtext == null) return;

        var selected = {}, i;
        for (i = sbox.length - 1; i >= 0; i--) {
            if (sbox[i].selected) {
                selected[sbox[i].value] = 1;
            }
        }
        
        for (i = sbox.length - 1; i >= 0; i--) {
            if (sbox[i].value == value) {
                sbox.options[i] = new Option(newtext, value);
                break;
            }
        }
        
        for (i = sbox.length - 1; i >= 0; i--) {
            if (selected[sbox[i].value] == 1) {
                sbox[i].selected = true;
            }
        }
    },
    
    /**
     * @param sbox Element
     * @param values Array
     */
    rem_by_values: function(sbox, values) {
        if (sbox == null || values == null) return;
        
        for (var i = sbox.length - 1; i >= 0; i--) {
            for (var j = values.length - 1; j >= 0; j--) {
                if (sbox[i].value == values[j]) {
                    sbox.options[i] = null;
                    break;
                }
            }
        }
    },
    
    /**
     * @param sbox Element
     */
    rem_all_options: function(sbox) {
        if (sbox == null) return;

        for (var i = sbox.length - 1; i >= 0; i--) {
            sbox.options[i] = null;
        }
    },
    
    /**
     * @param sbox Element
     * @param data Object
     * @param key String
     */
    add_from_object: function(sbox, data, key) {
        if (sbox == null || data == null) return;
        
        var d;
        if (typeof key == 'string') {
            for (d in data) {
                sbox.options[sbox.length] = new Option(data[d][key], d);
            }
        } else {
            for (d in data) {
                sbox.options[sbox.length] = new Option(data[d], d);
            }
        }
    },

    /**
     * @param sbox Element
     * @param data Object
     * @param key String
     */
    fill_from_object: function(sbox, data, key) {
        if (sbox == null || data == null) return;

        for (var i = sbox.length - 1; i >= 0; i--) {
            sbox.options[i] = null;
        }
    
        var d;
        if (typeof key == 'string') {
            for (d in data) {
                sbox.options[sbox.length] = new Option(data[d][key], d);
            }
        } else {
            for (d in data) {
                sbox.options[sbox.length] = new Option(data[d], d);
            }
        }
    },
    
    /**
     * @param sbox Element
     * @return Object 
     */
    get_selected: function(sbox) {
        if (sbox == null) return null;
    
        var values = {};
        var something_in = 0;
        for (var i = 0; i < sbox.length; i++) {
            if (sbox[i].selected) {
                values[sbox[i].value] = sbox[i].text;
                something_in = 1;
            }
        }
        
        return (something_in == 1) ? values : null;
    }
};

var ViewUtils = {
    /**
     * @return Element
     */
    show_fader: function() {
        var w, h;
        if (self.innerHeight) {
            w = self.innerWidth;
            h = self.innerHeight;
        } else if (document.documentElement && document.documentElement.clientHeight) {
            w = document.documentElement.clientWidth;
            h = document.documentElement.clientHeight;
        } else if (document.body) {
            w = document.body.clientWidth;
            h = document.body.clientHeight;
        }
    
        var fader = document.createElement('div');
        ClassnameUtils.add(fader, 'widget_fader');
        document.body.appendChild(fader);
//        fader.style.width = document.body.offsetWidth + 'px';
//        fader.style.height = document.body.offsetHeight + 10 + 'px';
        fader.style.width = w + 'px';
        fader.style.height = h + 'px';
        return fader;
    },

    /**
     * @param fader Element
     * @return Object
     */
    remove_fader: function(fader) {
        document.body.removeChild(fader);
        return null;
    },
    
    /**
     * @param fader Element
     */
    update_fader_height: function(fader) {
        fader.style.height = document.body.offsetHeight + 10 + 'px';
    },
    
    /**
     * @param text String
     * @param show_image Boolean
     * @param show_fader Boolean
     * @return Object
     */
    show_progress: function(text, show_image, show_fader) {
        var fader = null;
        var DOM_div = document.createElement('div');
        ClassnameUtils.add(DOM_div, 'widget_progress');
        
        if (show_image == 1) {
            var DOM_img = document.createElement('img');
            DOM_img.src = 'images/progress.gif';
            DOM_img.width = '32';
            DOM_img.height = '32';
            DOM_img.alt = 'Loading...';
            DOM_div.appendChild(DOM_img);
        }
        
        if (show_fader == 1) {
            fader = this.show_fader();
        }
        
        var p = document.createElement('p');
        p.appendChild(document.createTextNode(text));
        DOM_div.appendChild(p);
        
        document.body.appendChild(DOM_div);
        DOM_div.style.top = 300 + document.documentElement.scrollTop + 'px';
        DOM_div.style.left = ((document.body.offsetWidth - DOM_div.offsetWidth) >> 1) + 'px';
        
        return { progress: DOM_div, fader: fader };
    },
    
    /**
     * @param progress Element
     * @param fader Element
     * @return Object
     */
    remove_progress: function(progress, fader) {
        document.body.removeChild(progress);
        this.remove_fader(fader);
        return null;
    }
};

/*
 * begin of cTree
 */
function cTree() {
    this.tree = this.createTree(''); 
}
/**
 * @param label String
 * @return Object
 */
cTree.prototype.createTree = function(label) {
    return {
        subtree: {},
        label: label,
        data: null
    }; 
}
/**
 * @param subtree Array
 * @param ndata Object
 */
cTree.prototype.setNodeData = function(subtree, ndata) {
    this.setNodeData_(this.tree, subtree, ndata);
}
/**
 * @param subtree Array
 * @return Object
 */
cTree.prototype.getNodeData = function(subtree) {
    return this.getNode_(this.tree, subtree, 1);
}
/**
 * @param subtree Array
 * @return Object
 */
cTree.prototype.getParentNodeData = function(subtree) {
    var st = ArrayUtils.copy(subtree);
    st.pop();
    return this.getNode_(this.tree, st, 1);
}
/**
 * @param subtree Array
 * @return Object
 */
cTree.prototype.getNode = function(subtree) {
    return this.getNode_(this.tree, subtree, 0);
}
/**
 * @param subtree Array
 * @return Object
 */
cTree.prototype.getParentNode = function(subtree) {
    var st = ArrayUtils.copy(subtree);
    st.pop();
    return this.getNode_(this.tree, st, 0);
}
/**
 * @param subtree Array
 * @return Object
 */
cTree.prototype.remNode = function(subtree) {
   return this.remNode_(this.tree, subtree);
}
/**
 * @param Tree Object
 * @param subtree Array
 * @param ndata Object
// * @return Object
 */
cTree.prototype.setNodeData_ = function(tree, subtree, ndata) {
    if (subtree.length > 0) {
        if (tree.subtree[subtree[0]] == null) { tree.subtree[subtree[0]] = this.createTree(subtree[0]); }
        var st = ArrayUtils.copy(subtree);
        st.shift();
        this.setNodeData_(tree.subtree[subtree[0]], st, ndata);
    } else {
        tree.data = ndata;
    }
}
/**
 * @param tree Object
 * @param subtree Array
 * @return Object
 */
cTree.prototype.getNode_ = function(tree, subtree, mode) {
    if (subtree.length > 0) {
        if (tree.subtree[subtree[0]] != null) {
            var st = ArrayUtils.copy(subtree);
            st.shift();
            return this.getNode_(tree.subtree[subtree[0]], st, mode);
        } else {
            return null;
        }
    }
    if (mode == 1) return tree.data;
    else return tree;
}
/**
 * @param tree Object
 * @param subtree Array
 * @return Object
 */
cTree.prototype.remNode_ = function(tree, subtree) {
    if (subtree.length > 1) {
        if (tree.subtree[subtree[0]] != null) {
            var st = ArrayUtils.copy(subtree);
            st.shift();
            tree.subtree[subtree[0]] = this.remNode_(tree.subtree[subtree[0]], st);
        }
    } else if (subtree.length == 1) {
        delete tree.subtree[subtree[0]];
    } else {
        tree = this.createTree('');
    }
    return tree;
}
/*
 * end of cTree
 */

/*
 * begin of cEventHandler
 */
var EVENT_ONCHANGED = 1;
var EVENT_ONUNCHANGED = 2;

function cEventHandler() {
    this.event = {
        types: {
            onchanged: EVENT_ONCHANGED,
            onunchanged: EVENT_ONUNCHANGED
        },
        handlers: {
            onchanged: function() {},
            onunchanged: function() {}
        }
    }
}
/**
 * @param type Number
 * @param callback Function
 * @return Boolean
 */
cEventHandler.prototype.add_event = function(type, callback) {
    if (typeof callback != 'function') return false;
    
    switch (type) {
        case EVENT_ONCHANGED:
            this.event.handlers.onchanged = callback;
            break;
        case EVENT_ONUNCHANGED:
            this.event.handlers.onunchanged = callback;
            break;
        default:
            error('cEventHandler.add_event: unknown type');
            return false;
    }
    
    return true;
}
/*
 * end of cEventHandler
 */

/*
 * begin of cEvent
 */
function cEvent() {};

/**
 * @param elem Element
 * @param type String
 * @param func Function
 * @return
 */
cEvent.prototype.add_event = function(elem, type, func) {
	if (typeof func != 'function') return;
	
	var orig_func = elem[type];
	var my_func = function() {
		func(this);
		if (typeof orig_func == 'function') orig_func(this);
	}
	elem[type] = my_func;
}