/*
 * Browser: (extends java.Browser)
 *   engine: Contains the engine. DEPRECATED: Add your browser dependent function to the Browser class.
 *   findPostion(node): returns the position of the node in the record { left, top }
 *   getStyle(node, parameter): returns the style of the parameter
 *   body: the body element
 *
 * scrollToMe():
 *   --> scrolls to this component (within scrollable divs)
 *
 * openMenu(parent, href):
 *   --> opens a menu at the position of parent, the returned value by href should be a javascript window containing a IGMenu
 *
 * closeMenu()
 *   --> must be called in IGMenu to close the menu
 *
 * selectAndCloseMenu(href)
 *   --> executes the href and close the menu
 *
 */
Dbg.debugPopups = false;

/**
 * Set up the right browser engine.
 */
function ClientBrowser() {
    var vUserAgent = navigator.userAgent;
    var vVendor = navigator.vendor;
    var vProduct = navigator.product;

    if (window.opera && vUserAgent.indexOf("Opera") >= 0) {
        Browser.engine = "opera";
    } else if (vVendor == "KDE" && vUserAgent.indexOf("KHTML") >= 0) {
        Browser.engine = "khtml";
    } else if (vUserAgent.indexOf("AppleWebKit") >= 0) {
        Browser.engine = "webkit";
    } else if (window.controllers && vProduct == "Gecko") {
        Browser.engine = "gecko";
    } else if (vUserAgent.indexOf("MSIE") >= 0) {
        Browser.engine = "mshtml";
    } else if (vUserAgent.indexOf("NekoFwUnitTests") >= 0) {
        Browser.engine = "nekofw";
    } else {
        Browser.engine = "default";
    }

    // getPosition
    switch (Browser.engine) {
    case "mshtml":
        Browser.getPosition = function(node) {
            var rect = node.getBoundingClientRect();
            return {
                left : rect.left,
                top : rect.top
            };
        };
        break;
    case "opera":
        Browser.getPosition = function(node) {
            var mytop = node.offsetTop;
            var myleft = node.offsetLeft;
            var mynode = node.offsetParent;
            while (mynode) {
                mytop += mynode.offsetTop;
                myleft += mynode.offsetLeft;
                mytop -= mynode.scrollTop;
                myleft -= mynode.scrollLeft;
                mynode = mynode.offsetParent;
            }
            return {
                left : myleft,
                top : mytop
            };
        };
        break;
    default:
        Browser.getPosition = function(node) {
            var mytop = node.offsetTop;
            var myleft = node.offsetLeft;
            var mynode = node.offsetParent;
            while (mynode) {
                mytop += mynode.offsetTop;
                myleft += mynode.offsetLeft;
                mynode = mynode.offsetParent;
            }
            // in ff and chrome (not gecko) scroll attributes are not always in
            // offsetParent, must not be done in opera
            var mynode = node.parentNode;
            if (mynode) {
	            while (mynode.parentNode) {
	                mytop -= mynode.scrollTop;
	                myleft -= mynode.scrollLeft;
	                mynode = mynode.parentNode;
	            }
            }
            return {
                left : myleft,
                top : mytop
            };
        };
    }

    // caret position
    Browser.caretPosition = function(node) {
    	var selectionEnd = -1;
    	try
    	{
    	  if(node.value) {
    		  if(node.createTextRange) {
    			  var range = document.selection.createRange().duplicate();
    			  range.moveStart('character', -node.value.length);
    			  selectionEnd = range.text.length;
    		  } else if(node.selectionEnd) {
    			  selectionEnd = node.selectionEnd;
    		  }

    		  if(selectionEnd<0) {
    			  selectionEnd = node.value.length;
    		  }
    	  }
    	}catch(exception) {
    		logger.trace(exception);
    		logger.error(exception);
    	}
    	return selectionEnd<0 ? 0 : selectionEnd;
    }

    // Body
    if (window.document.body) {
        Browser.body = window.document.body;
    } else {
        Browser.body = window.document.getElementsByTagName("BODY")[0];
    }

}
ClientBrowser();

/**
 * Console adaptor for logging. Uses Dbg from ajax.js Also prepares the
 * window.console object if not available.
 */
function Logger() {
    var debugConsole = null;
    switch (Browser.engine) {
    case "webkit":
        if (!window.console) {
            throw new Error("There is no window.console");
        }
        debugConsole = {
            pi : function(msg) {
                window.console.info(msg);
            },
            pw : function(msg) {
                window.console.warn(msg);
            },
            pd : function(msg) {
                window.console.debug(msg);
            },
            pe : function(msg) {
                window.console.error(msg);
            }
        };
        break;
    case "nekofw":
        if (!window.console) {
            var logging = function(type, msg) {
                // ignore
            };
            window.console = {
                info : function(msg) {
                    logging("INFO", msg)
                },
                warn : function(msg) {
                    logging("WARN", msg)
                },
                debug : function(msg) {
                    logging("DEBUG", msg)
                },
                error : function(msg) {
                    logging("ERROR", msg)
                },
                trace : function(msg) {
                    logging("TRACE", msg)
                },
                logging : logging
            };
        }
        debugConsole = Dbg;
        break;
    case "opera":
        if (!window.console) {
            var logging = function(type, msg) {
                opera.postError("[" + type + "] " + msg);
            };
            window.console = {
                info : function(msg) {
                    logging("INFO", msg)
                },
                warn : function(msg) {
                    logging("WARN", msg)
                },
                debug : function(msg) {
                    logging("DEBUG", msg)
                },
                error : function(msg) {
                    logging("ERROR", msg)
                },
                trace : function(msg) {
                    logging("TRACE", msg)
                },
                logging : logging
            };
        }
        debugConsole = Dbg;
        break;
    default:
        debugConsole = Dbg;
    }

    /*
	 * if (!window.console) { // if still no console, we define our own: var
	 * divNode = document.createElement("div"); divNode.style.display = "none";
	 * divNode.style.position = "absolute"; divNode.style.width = "500px";
	 * divNode.style.width = "300px"; divNode.style.overflow = "auto";
	 * divNode.id = "console";
	 *
	 * var body = Browser.body; body.appendChild(divNode);
	 *
	 * var logging = function(type, msg) { var lineNode =
	 * document.createElement("div"); lineNode.innerHTML = "[" + type + "] " +
	 * msg; divNode.appendChild(lineNode); };
	 *
	 * window.console = { info : function(msg) { logging("INFO", msg) }, warn :
	 * function(msg) { logging("WARN", msg) }, debug : function(msg) {
	 * logging("DEBUG", msg) }, error : function(msg) { logging("ERROR", msg) },
	 * trace : function(msg) { logging("TRACE", msg) }, logging :logging }; }
	 */

    if (window.console && !window.console.trace) { // some browsers do not have
        // all console
        // hooks, add more here
        window.console.trace = function(msg) {
            window.console.info(arguments + " +++ " + msg);
        };
    }

    this.info = function(msg) {
        debugConsole.pi(msg);
    };
    this.warn = function(msg) {
        debugConsole.pw(msg);
    };
    this.trace = function(msg) {
        debugConsole.pi(msg);
    };
    this.error = function(msg) {
        debugConsole.pe(msg);
    };
    this.debug = function(msg) {
        debugConsole.pd(msg);
    };
}

var logger = new Logger();
logger.info("Started Logger");

/**
 * common javascript methods
 */
function string_endswith(s, what) {
    var i = s.lastIndexOf(what);
    return i >= 0 && i == s.length - what.length;
}

function fail(msg) {
    throw new Error(msg);
}

function inputFieldFocus(id) {
	var node = getElementById(id);
	if(node) {
		if (node.nodeName.toLowerCase()=="input") {
			node.focus();
		}else{
			logger.error("cannot handle nodes of type: " + node.nodeName);
		}
	}else{
		logger.error("could not find element with id: " + id);
	}

}

var getElementById = document.getElementById ? function(id) {
    return document.getElementById(id)
} : document.all ? function(id) {
    return document.all[id]
} : fail("cannot get elements from DOM");

function getMousePosition(ev) {
    var x = ev.clientX
            + (window.scrollX ? window.scrollX
                    : document.documentElement.scrollLeft);
    var y = ev.clientY
            + (window.scrollY ? window.scrollY
                    : document.documentElement.scrollTop);
    return [ x, y ];
}



/**
 * sum up the scroll top/left positions of the rootpath for the given node.
 *
 * @param {Object}
 *            node
 */
function getScrollSum(node) {
    var left = 0;
    var top = 0;
    var node = node.parentNode;

    while (node.nodeType == 1) {
        left += node.scrollLeft;
        top += node.scrollTop;
        node = node.parentNode;
    }

    return {
        "left" : left,
        "top" : top
    };
}

/**
 * get the left and top border width of the node
 *
 * @param {Object}
 *            node
 */
function getBorderTopLeft(node) {
    var top = 0;
    var left = 0;

    switch (Browser.engine) {
    case "mshtml":
        top = node.currentStyle["borderTopStyle"] == "none" ? 0
                : (parseInt(node.style["borderTopWidth"]) || 0);
        left = node.currentStyle["borderLeftStyle"] == "none" ? 0
                : (parseInt(node.style["borderLeftWidth"]) || 0);
        break;
    default:
        top = node.style["borderTopStyle"] == "none" ? 0
                : (parseInt(node.style["borderTopWidth"]) || 0);
        left = node.style["borderLeftStyle"] == "none" ? 0
                : (parseInt(node.style["borderLeftWidth"]) || 0);
    }
    return {
        top : top,
        left : left
    };
}

/**
 *
 * @param {Object}
 *            el
 * @param {Object}
 *            styleProp
 */
Browser.getStyle=function getStyle(node, styleProp) {
    if (node.currentStyle) {
        var y = node.currentStyle[styleProp];
    } else if (window.getComputedStyle) {
        var y = document.defaultView.getComputedStyle(node, null)
                .getPropertyValue(styleProp);
    }
    return y;
}

function addEventListener(node, eventType, listener) {
    if (node.attachEvent)
        return node.attachEvent("on" + eventType, listener);
    else if (node.addEventListener) {
        node.addEventListener(eventType, listener, false);
        /*
		 * always add events in bubbling (:=false) phase: same behavior as in IE
		 */
        return true;
    } else {
        throw new Error("could not attach event: " + eventType);
    }
}

function removeEventListener(node, eventType, listener) {
    if (node.detachEvent)
        return node.detachEvent("on" + eventType, listener);
    else if (node.removeEventListener) {
        node.removeEventListener(eventType, listener, false);
        /*
		 * always remove events in bubbling (:=false) phase: same behavior as in
		 * IE
		 */
        return true;
    } else {
        logger.error("could not remove event: " + eventType);
        throw new Error("could not remove event: " + eventType);
    }
}

/**
 * Given a node, get the next node in the same hierarchie with the given name,
 * e.g. get the next DIV-node, etc.
 *
 * @param {Object}
 *            node a dom node
 * @param {Object}
 *            nodeName
 */
function nextSibling(node, nodeName) {
    do {
        node = node.nextSibling;
        if (node.nodeName == nodeName) {
            return node;
        }
    } while (node);
    return false;
}
/**
 * Give a node, get the first child node with the given name, e.g. get the first
 * DIV-node below. Does NOT descend recursively.
 *
 * @param {Object}
 *            node
 * @param {Object}
 *            nodeName
 */
function firstChild(mynode, nodeName) {
    var mychild = mynode.firstChild;
    while (mychild) {
        if (mychild.nodeName == nodeName) {
            return mychild;
        }
        mychild = nextSibling(mychild, nodeName);
    }
    return false;
}

/**
 * Get the page coordinates of the given object.
 *
 * @param {Object}
 *            object either dom node or event
 */
function getEventPageCoordinates(event) {
    switch (Browser.engine) {
    case "mshtml":
        var doc = document;
        var scrollLeft = 0;
        if (doc.documentElement.scrollLeft) {
            scrollLeft = doc.documentElement.scrollLeft;
        } else if (doc.body.scrollLeft) {
            scrollLeft = doc.body.scrollLeft;
        }
        var scrollTop = 0;
        if (doc.documentElement.scrollTop) {
            scrollTop = doc.documentElement.scrollTop;
        } else if (doc.body.scrollTop) {
            scrollTop = doc.body.scrollTop;
        }

        return {
            pageX : event.clientX + scrollLeft,
            pageY : event.clientY + scrollTop
        };
    default:
        return {
            pageX : event.pageX,
            pageY : event.pageY
        };
    }
}

/**
 * Get the location of a Dom node w.r.t. whole document.
 *
 * @param {Object}
 *            node
 */
function getNodePageCoordinates(node) {
    var offsetX = 0;
    var offsetY = 0;
    while (node) {
        offsetX += node.offsetLeft;
        offsetY += node.offsetTop;
        node = node.offsetParent;
    }

    return {
        pageX : offsetX,
        pageY : offsetY
    };
}

function isInside(innerNode, outerNode) {
    var body = Browser.body;
    while (innerNode !== outerNode && innerNode !== body) {
        innerNode = innerNode.parentNode;
    }
    return innerNode == outerNode;
}

function stopEventPropagation(event) {
    if (document.all) {
        event.cancelBubble = true;
    } else {
        event.stopPropagation();
    }
}

/**
 * Check whether a given event is a mouse event with the given parameters.
 *
 * @param {Object}
 *            event
 * @param {Object}
 *            type type of event, as in eventhandler names, ie 'click',
 *            'dblclick', 'mousedown', etc.
 * @param {Object}
 *            buttonName name of button, one of 'left','middle','right'
 */
function checkMouseEvent(event, pType, pButtonName) {
    var buttonName = null;
    switch (event.type) {
    case "click":
    case "dblclick":
        buttonName = "left";
        break;
    case "contextmenu":
        buttonName = "right";
        break;
    }

    switch (Browser.engine) {
    case "khtml":
    case "mshtml":
        switch (event.button) {
        case 1:
            buttonName = "left";
            break;
        case 2:
            buttonName = "right";
            break;
        case 4:
            buttonName = "middle";
            break;
        }
        break;
    default:
        switch (event.button) {
        case 0:
            buttonName = "left";
            break;
        case 2:
            buttonName = "right";
            break;
        case 1:
            buttonName = "middle";
            break;
        }
    }

    return event.type == pType && pButtonName == buttonName;
}

/**
 * Get the event position w.r.t. the given target node. ie. get the difference
 * of page coordinates of both: event and target
 *
 * @param {Object}
 *            event
 * @param {Object}
 *            target
 */
function getOffsetPosition(event, target) {
    var targetPageOffset = getNodePageCoordinates(target);
    // logger.info("[SplitPane] targetPageOffset: [" + targetPageOffset.pageX +
    // "," + targetPageOffset.pageY + "]");

    var pageCoord = getEventPageCoordinates(event);
    // logger.info("[SplitPane] pageCoord: [" + pageCoord.pageX + "," +
    // pageCoord.pageY + "]");
    return {
        x : pageCoord.pageX - targetPageOffset.pageX,
        y : pageCoord.pageY - targetPageOffset.pageY
    };
}

var re_backslash = /\\/g;
var re_quot = /\"/g;
function renderJson(obj) {
    if (null == obj)
        return "null";
    switch (typeof obj) {
    case "undefined":
        return "null";
    case "number":
        return "" + obj;
    case "string":
        return '"' + obj.replace(re_backslash, '\\\\').replace(re_quot, '\\"') + '"';
    case "boolean":
        return obj ? "true" : "false";
    case "object":
        if (obj instanceof Array) {
            var tmp = [];
            for ( var i in obj)
                tmp[tmp.length] = renderJson(obj[i]);
            return "[" + tmp.join(',') + "]";
        } else {
            var tmp = [];
            for ( var i in obj)
                if (!obj[i]
                        || ("function" != typeof obj[i] && !(obj[i] instanceof Function)))
                    tmp[tmp.length] = renderJson(i) + ':' + renderJson(obj[i]);
            return "{" + tmp.join(',') + "}";
        }
    case "function":
    default:
        return "0";
    }
}



/**
 * SplitPaneMovable. This object handles the mouse move events on the split
 * panel.
 *
 * @param {DivNode}
 *            id
 * @param {Integer}
 *            position
 * @param {String}
 *            direction one of ["horz","vert"]
 */
function SplitPaneMovable(splitpane, position, direction, splitterCallbackHref) {
    if (splitpane.className != "gui_splitpane") {
        throw new Error(
                "Unknown SplitPane Element: class='gui_splitpane' required!");
    }

    var self = this;

    this.splitpane = splitpane;

    this.offset = position; // offset of mouse w.r.t. splitter
    this.id = this.splitpane.id;

    this.first = this.splitpane.firstChild;
    this.separator = this.first.nextSibling;
    this.second = this.separator.nextSibling;

    this.splitterPosition = null;
    this.splitterPositionHref = splitterCallbackHref;

    this.splitpane.splitPaneObject = this;

    this.handleMove = SplitPaneMovable_handleMove;
    this.moveTo = (direction == "horz" ? SplitPaneMovable_moveToHorz
            : SplitPaneMovable_moveToVert);
    this.storeSplitterPosition = SplitPaneMovable_storeSplitterPosition;
    this.release = SplitPaneMovable_release;

    this.mouseMoveHandler = function(event) {
        self.handleMove(event);
        return false;
    };
    this.releaseHandler = function(event) {
    	self.storeSplitterPosition();

    	self.release();
    }

    addEventListener(this.splitpane, "mousemove", this.mouseMoveHandler);
    switch (Browser.engine) {
    case "mshtml":
    case "webkit":
    case "opera":
    case "gecko":
        addEventListener(Browser.body, "mouseup", this.releaseHandler);
        break;
    default:
        addEventListener(this.splitpane, "mouseup", this.releaseHandler);
    }

}

/**
 * Release the mouse event handlers from the splitpane DIV.
 */
function SplitPaneMovable_release() {
    var x = removeEventListener(this.splitpane, "mousemove",
            this.mouseMoveHandler);
    switch (Browser.engine) {
    case "mshtml":
    case "webkit":
    case "opera":
    case "gecko":
        x = removeEventListener(Browser.body, "mouseup", this.releaseHandler);
        break;
    default:
        x = removeEventListener(this.splitpane, "mouseup", this.releaseHandler);

    }
    this.splitpane.splitPaneObject = null;
}

/**
 * Make horizontal move.
 *
 * @param {Object}
 *            offsetX horizontal coordinate (mouse coordinate w.r.t. the
 *            splitpane DIV)
 * @param {Object}
 *            offsetY vertical coordinate (mouse coordinate w.r.t. the splitpane
 *            DIV)
 */
function SplitPaneMovable_moveToHorz(offsetX, offsetY) {
    var max = this.splitpane.offsetWidth;
    var mouseOffset = this.offset.x;

    var first = this.first.style;
    var sep = this.separator.style;
    var second = this.second.style;

    var sepWidth = this.separator.offsetWidth;

    var x1 = offsetX - mouseOffset;

    x1 = Math.max(0, Math.min(x1, max - sepWidth - 1));
    this.splitterPosition = x1;

    first.width = x1 + "px";
    sep.left = x1 + "px";
    second.left = x1 + sepWidth + "px";
}

/**
 * Make horizontal move.
 *
 * @param {Object}
 *            offsetX horizontal coordinate (mouse coordinate w.r.t. the
 *            splitpane DIV)
 * @param {Object}
 *            offsetY vertical coordinate (mouse coordinate w.r.t. the splitpane
 *            DIV)
 */
function SplitPaneMovable_moveToVert(offsetX, offsetY) {
    var max = this.splitpane.offsetHeight;
    var mouseOffset = this.offset.y;

    var first = this.first.style;
    var sep = this.separator.style;
    var second = this.second.style;

    var sepHeight = this.separator.offsetHeight;

    var y1 = offsetY - mouseOffset;

    y1 = Math.max(0, Math.min(y1, max - sepHeight - 1));
    this.splitterPosition = y1;

    first.height = y1 + "px";
    sep.top = y1 + "px";
    second.top = y1 + sepHeight + "px";
}

function SplitPaneMovable_handleMove(event) {

    // logger.info("[Splitpane] handleMove: " + (this.splitpane ?
    // this.splitpane.className : "null"));
    var p = getOffsetPosition(event, this.splitpane);
    var x = p.x;
    var y = p.y;

    this.moveTo(x, y);
}

function SplitPaneMovable_storeSplitterPosition() {
	var self = this;
	var splitterPos = this.splitterPosition;
	if(splitterPos!==null) {
		var href = this.splitterPositionHref;
		if(href) {
			var open = function() {
				var http_request = makeRequestChecked(href + "&sp", createPost( {
					'pos' : splitterPos
			    }, "--"), "--");
			    if (!http_request) {
			    	return;
			    } else {
			    	http_request.onreadystatechange = function() {
			    		self.separator.splitterStoring = null;
			    		gotit(http_request, "ignore");
	                };
			    }
		     };
			 if(this.separator.splitterStoring) {
				 window.clearTimeout(self.separator.splitterStoring);
			 }
			 this.separator.splitterStoring = window.setTimeout(open, 1000);
		}
	}
}

/**
 * Onmousemove handler for the separator div of the split panel. It starts
 * resizing through the instanciation of a SplitPaneMovable object.
 *
 * @param {Object}
 *            event
 * @param {Object}
 *            splitter
 */
function SplitPaneSeparator_mouseDownHandler(event, splitter, direction, splitterCallbackHref) {
    // logger.info("[SplitPane] mouse down on splitter" + event);
    var splitpane = splitter.parentNode;
    if (!splitpane.splitPaneObject) {
        if (checkMouseEvent(event, "mousedown", "left")) {
            var p = getOffsetPosition(event, splitter); // offset position
            // within the splitter
            var sp = new SplitPaneMovable(splitpane, p, direction, splitterCallbackHref);
        }
    }
    stopEventPropagation(event);
    return false;
}

/**
 * Handle double click on a splitter: i.e. collapse and expand.
 *
 * @param {Object}
 *            event
 * @param {Object}
 *            splitter
 */
function SplitPaneSeparator_dblClickHandler(event, splitter, direction,
        hideable) {
    // logger.warn("splitpane dblclick");
    var splitpane = splitter.parentNode;
    if (!splitpane.splitPaneObject) {
        var p = getOffsetPosition(event, splitter); // offset position within
        // the splitter
        var sp = new SplitPaneMovable(splitpane, p, direction);
    }

    var lastPos = splitter.splitPaneClosed;
    if (!lastPos) {
        lastPos = {
            x : splitter.offsetLeft,
            y : splitter.offsetTop
        };

        if (hideable == "second") {
            // lower right
            sp.moveTo(splitpane.offsetWidth, splitpane.offsetHeight);
        } else {
            // upperleft
            sp.moveTo(splitpane.offsetLeft, splitpane.offsetTop);
        }
        firstChild(splitter, "DIV").className = "gui_splitpane_splitter_"
                + hideable + "_closed";
        splitter.splitPaneClosed = lastPos;
    } else {
        sp.moveTo(lastPos.x, lastPos.y);
        firstChild(splitter, "DIV").className = "gui_splitpane_splitter_"
                + hideable + "_open";
        splitter.splitPaneClosed = null;
    }
    sp.release();
}

/**
 * Enters the mouse over region
 *
 * @param self
 *            this div element
 * @param time
 *            time to wait before the request
 * @param url
 *            the url
 */
function MouseOver_enter_real(popupElement, registerElement, time, href) {
   if (!popupElement.open)
        popupElement.open = new Array();
    var exists = false;
    for ( var i = 0; i < popupElement.open.length; i++)
        if (popupElement.open[i] == registerElement)
            exists = true;
    if (!exists)
        popupElement.open[popupElement.open.length] = registerElement;
    var pos = Browser.getPosition(popupElement);
    var callback = function() {
        popupElement.timeout = null;
        if (popupElement.open.length > 0 && !popupElement.isopen) {
            if (popupElement.id == null)
                popupElement.id = "u" + createUID();
            if (!popupElement.loaded) {
                if (popupElement.loading)
                    return;
                if (!href)
                    return;
                var http_request = makeRequest(href + "&moc");
                if (!http_request) {
                    window.location = href;
                    return;
                } else {
                    http_request.placeJavascriptWindow = function(span, exist) {
                        span.className = "gui_mouseover_t";
                        popupElement.ajaxchild = span;
                        // popupElement.appendChild(span);
                        popupElement.loaded = true;
                        popupElement.loading = false;
                        callback();
                    };
                    http_request.onreadystatechange = function() {
                        gotit(http_request, "ignore");
                    };
                    popupElement.loading = true;
                }
                return;
            }
            var parentTooltip = popupElement.parentNode;
            while (parentTooltip && !parentTooltip.keepOpen)
                parentTooltip = parentTooltip.parentNode;
            if (parentTooltip)
                parentTooltip.keepOpen(true);
            var tooltips = getNamedAbsoluteRootDiv('allTooltips');
            var destpos = Browser.getPosition(tooltips);
            var my = popupElement.ajaxchild;
            // popupElement.removeChild(my);
            my.className = "gui_mouseover_v";
            if (!my.id)
                my.id = popupElement.id + "_t";
            popupElement.childid = my.id;
            my.popupElement = popupElement;
            var y = pos.top + popupElement.offsetHeight - 2 - destpos.top;
            var x = pos.left - destpos.left;
            // if (Browser.engine=="MSIE")
            // y=y-popupElement.offsetTop/2;
            // alert(y+" "+popupElement.offsetTop+" "+
            // popupElement.offsetHeight+"
            // "+popupElement.offsetParent.offsetTop);
            my.style.top = y + "px";
            my.style.left = x + "px";
            my.keepOpen = function(open) {
                if (open)
                    MouseOver_enter_real(popupElement, popupElement, 0, null);
                else
                    MouseOver_leave_real(popupElement, popupElement, false);
            };
            tooltips.appendChild(my);
            popupElement.isopen = true;
            MouseOver_checkSize(popupElement.id);
        }
    };
    if (popupElement.open.length == 1) {
        if (time)
            popupElement.timeout = window.setTimeout(callback, time);
        else
            callback();
    }
}

function MouseOver_enter(self, time, href) {
    if (self.destroyed)
        return;
    if (!self.mouseoutregistered) {
        addEventListener(self, "mouseout", function() {
            MouseOver_leave(self);
        });
        self.mouseoutregistered = true;
    }
    registerRemoveHook(self, MouseOver_leaveI);
    MouseOver_enter_real(self, self, time, href);
}

function gui_moe(self, time, href) {
    MouseOver_enter(self, time, href);
}

function MouseOver_enterTooltip(self) {
    if (self.destroyed)
        return;
    if (!self.mouseoutregistered) {
        addEventListener(self, "mouseout", function() {
            MouseOver_leaveTooltip(self);
        });
        self.mouseoutregistered = true;
    }
    registerRemoveHook(self, MouseOver_leaveTooltipI);
    while (!self.popupElement)
        self = self.parentNode;
    MouseOver_enter_real(self.popupElement, self, 0, null);
}

function gui_mot(self) {
    MouseOver_enterTooltip(self);
}

/**
 * Mouse leaves the mouse over region
 *
 * @param self
 *            this div element
 */
function MouseOver_leave_real(popupElement, registerElement, immediatelly) {
    if (!popupElement.open)
        return;
    var newArray = new Array();
    for ( var i = 0; i < popupElement.open.length; i++)
        if (popupElement.open[i] != registerElement)
            newArray[newArray.length] = popupElement.open[i];
    if (popupElement.open.length == newArray.length)
        return;
    popupElement.open = newArray;
    if (popupElement.open.length == 0) {
        if (popupElement.timeout) {
            window.clearTimeout(popupElement.timeout);
            popupElement.timeout = null;
        }
        var func = function() {
            if (!(popupElement.open) || popupElement.open.length == 0) {
                if (!popupElement.isopen)
                    return;
                popupElement.isopen = false;
                var tooltips = getElementById('allTooltips');
                var my = getElementById(popupElement.childid);
                my.className = "gui_mouseover_t";
                // notifyRemoveNode(my);
                tooltips.removeChild(my);
                // if (!popupElement.destroyed)
                // popupElement.appendChild(my);
                var parentTooltip = popupElement.parentNode;
                while (parentTooltip && !parentTooltip.keepOpen)
                    parentTooltip = parentTooltip.parentNode;
                if (parentTooltip)
                    parentTooltip.keepOpen(false);
            }
        };
        if (immediatelly)
            func();
        else
            window.setTimeout(func, 30);
    }
}

function MouseOver_leave(self) {
    if (self.destroyed)
        return;
    unregisterRemoveHook(self);
    MouseOver_leave_real(self, self, false);
}

function MouseOver_leaveI(self) {
    self.destroyed = true;
    unregisterRemoveHook(self);
    MouseOver_leave_real(self, self, true);
}

function gui_mol(self) {
    MouseOver_leave(self);
}

function MouseOver_leaveTooltip(self) {
    if (self.destroyed)
        return;
    unregisterRemoveHook(self);
    while (!self.popupElement)
        self = self.parentNode;
    MouseOver_leave_real(self.popupElement, self, false);
}

function MouseOver_leaveTooltipI(self) {
    self.destroyed = true;
    unregisterRemoveHook(self);
    while (!self.popupElement)
        self = self.parentNode;
    MouseOver_leave_real(self.popupElement, self, true);
}

function gui_molt(self) {
    MouseOver_leaveTooltip(self);
}

function MouseOver_checkSize() {
    var parent = getElementById('allTooltips');
    for ( var i = 0; i < parent.childNodes.length; i++) {
        var me = parent.childNodes[i];
        if (me.offsetLeft + me.offsetWidth > document.body.offsetWidth) {
            var newx = document.body.offsetWidth - me.offsetWidth;
            if (newx < 0)
                newx = 0;
            me.style.left = newx + "px";
        }
        if (me.offsetTop + me.offsetHeight > document.body.offsetHeight) {
            var newy = document.body.offsetHeight - me.offsetHeight;
            if (newy < 0)
                newy = 0;
            me.style.top = newy + "px";
        }
    }
}

function gui_cs() {
    MouseOver_checkSize();
}

/**
 * Returns a root div object which is positioned at 0,0
 *
 * @param name
 *            the name of the root
 * @return the root div, if it not exist its created
 */
function getNamedAbsoluteRootDiv(name) {
    var rootdiv = getElementById(name);
    if (!rootdiv) {
        var body = Browser.body; /* IE makes a white site afterwards ??? */
        rootdiv = document.createElement("div");
        rootdiv.style.position = "absolute";
        rootdiv.style.display = "none";
        rootdiv.id = name;
        rootdiv.style.top = "0px";
        rootdiv.style.left = "0px";
        body.appendChild(rootdiv);
        rootdiv.style.display = "block";
    }
    return rootdiv;
}

/**
 * Marks this div as a breakout div.
 *
 * @param self
 *            The div to check for a breakout
 */
function MouseOver_BreakOut(self) {
    if (self.breakout || self.destroyed)
        return;

    var pos = Browser.getPosition(self);
    var parent = self.parentNode;
    var parentStyle = Browser.getStyle(parent, "overflow");

    while (parent != null && parentStyle != "auto" && parentStyle != "hidden"
            && parentStyle != "scroll") {
        var currentParent = parent.parentNode;
        if (currentParent != null) {
            parentStyle = Browser.getStyle(currentParent, "overflow");
        } else {
            parentStyle = null;
        }
        parent = currentParent;
    }

    if (parent == null)
        fail("No auto or hidden-overflow parent found");
    var parentPos = Browser.getPosition(parent);
    var parentWidth = parent.clientWidth ? parent.clientWidth
            : parent.offsetWidth;
    var parentScrollX = parent.scrollLeft ? parent.scrollLeft : 0;
    if (pos.left + self.offsetWidth > parentPos.left + parentWidth) {
        if (!self.mouseoutregistered) {
            addEventListener(self, "mouseout", function() {
                MouseOver_BreakOutLeave(self);
            });
            self.mouseoutregistered = true;
        }
        registerRemoveHook(self, MouseOver_BreakOutLeaveAndDestroy);
        var breakouts = getNamedAbsoluteRootDiv('breakouts');
        var destpos = Browser.getPosition(breakouts);
        // while (breakouts.childNodes.length)
        // MouseOver_BreakOutLeave(breakouts.childNodes[0]);
        var breakout = document.createElement("div");
        var innerhtml = self.innerHTML;
        // IE replace the dom and don't use " in innerhtml
        innerhtml = innerhtml.replace(/ id=/g, " oldid=");
        innerhtml = innerhtml.replace(/ onmouseover=/g, " oldonmouseover=");
        innerhtml = innerhtml.replace(/ onmouseout=/g, " oldonmouseout=");
        innerhtml = "<nobr>" + innerhtml + "</nobr>";
        var clipleft = parentPos.left + parentWidth - pos.left;
        var x = pos.left + clipleft - destpos.left;
        var y = pos.top - destpos.top;
        breakout.style.left = x + "px";
        breakout.style.top = y + "px";
        var mywidth = self.offsetWidth;
        var myheight = self.offsetHeight;
        var cheigth = self.offsetHeight;
        var cwidth = self.offsetWidth;
        var breakout2 = document.createElement("div");
        self.className = self.className.replace(/gui_breakout_no/,
                "gui_breakout_yes");
        breakout2.style.position = "relative";
        var mclipleft = -clipleft;
        breakout2.style.left = mclipleft + "px";
        breakout2.style.top = "0px";
        breakout2.className = self.className+" gui_breakout_ext";
        breakout2.innerHTML = innerhtml;
        breakout.style.position = "absolute";
        breakout.style.overflow = "hidden";
        breakout.style.width = cwidth + "px";
        breakout.style.height = cheigth + "px";
        breakout.appendChild(breakout2);
        breakouts.appendChild(breakout);
        self.breakout = breakout;
    }
}

function gui_bo(self) {
    MouseOver_BreakOut(self);
}

function MouseOver_BreakOutLeave(self) {
    if (self.breakout) {
        var breakouts = getElementById('breakouts');
        if (!self.destroyed)
            self.className = self.className.replace(/gui_breakout_yes/,
                    "gui_breakout_no");
        unregisterRemoveHook(self);
        breakouts.removeChild(self.breakout);
        self.breakout = false;
    }
}

function gui_bol(self) {
    MouseOver_BreakOutLeave(self);
}

function MouseOver_BreakOutLeaveAndDestroy(self) {
    self.destroyed = true;
    MouseOver_BreakOutLeave(self);
}

/**
 * Given a list of ids of input fields. When calling this function all given
 * fields are cleared. I.e. the value attribute is set to "".
 */
function Fields_clear() {
    for ( var i = 0, len = arguments.length; i < len; ++i) {
        var argI = arguments[i];
        var node = document.getElementById(argI);
        node.value = "";
    }
}

/**
 * Ask the user for some input.
 *
 * @param {Object}
 *            message
 * @param {Object}
 *            presetInput
 * @param {Object}
 *            setterCallback
 */
function UserInput_prompt(message, presetInput, setterCallback) {
    var value = prompt(message, presetInput ? presetInput : "");
    if (value && (!presetInput || presetInput != value)) {
        setterCallback(value);
    }
}

function gui_kus(event, self, href) {
    KeyUpSuggest(event, self, href);
}

function KeyUpSuggest(event, self, href) {
    if (Browser.getKeyCode(event) != 13)
        OnQuerySuggest(self, href);
    else
        LeaveQuerySuggestImmediate(self);
}

function gui_lqs(self) {
    self.gui_hasFocus = false;
    LeaveQuerySuggest(self);
}

function OpenQuerySuggest(event, self) {
    self.immediate = true;
    Browser.invokeEventHandler(self, 'keyup', event);
    self.immediate = false;
}

function OnQuerySuggest(self, href) {
    if (self.value == self.oldvalue && !self.immediate)
        return;
    self.gui_hasFocus = true;
    self.oldvalue = self.value;
    if (self.timer) {
        window.clearTimeout(self.timer);
        self.timer = null;
    }
    var open = function() {
        closeQuerySuggest(self);
        if (!self.id)
            self.id = "u" + createUID();
        if (!(self.loading)) {
            var http_request = makeRequestChecked(href + "&qs", createPost( {
                v : self.value,
                c : Browser.caretPosition(self),
                i : self.id
            }, "--"), "--");
            if (!http_request) {
                return;
            } else {
                http_request.placeJavascriptWindow = function(div, exist) {
                	if (exist && div.inputfield!=self) {
                        var windows = getNamedAbsoluteRootDiv('querySuggestWindows');
                   		windows.removeChild(div);
                		exist=false;
                	}
                    if (!exist) {
                        var windows = getNamedAbsoluteRootDiv('querySuggestWindows');
                        self.suggestwindow = div;
                        div.className = 'gui_querySuggestWindow';
                        div.inputfield=self;
                        div.onmousemove = function() {
                            self.focus();
                        };
                        var parentpos = Browser.getPosition(windows);
                        var mypos = Browser.getPosition(self);
                        var left = mypos.left - parentpos.left;
                        var top = mypos.top - parentpos.top + self.offsetHeight;
                        div.style.left = left + "px";
                        div.style.top = top + "px";
                        div.style.width = self.offsetWidth + "px";
                        self.isMouseIn = false;
                        self.isKeepOpen = false;
                        div.keepOpen = function(isOpen) {
                            self.isKeepOpen = isOpen;
                            if (!isOpen)
                                LeaveQuerySuggest(self);
                        }
                        addEventListener(div, "mouseout", function() {
                            self.isMouseIn = false;
                            LeaveQuerySuggest(self);
                        });
                        addEventListener(div, "mouseover", function() {
                            self.isMouseIn = true;
                        });
                        windows.appendChild(div);
                    }
                    self.loading = false;
                };
                var check = new Object();
                http_request.onreadystatechange = function() {
                    if (self.loading == check) {
                        gotit(http_request, "ignore");
                    }
                };
                self.loading = check;
            }
        }
    };
    if (self.immediate)
        open();
    else
        self.timer = window.setTimeout(open, 300);
}

function gui_QSC(id) {
    this.QuerySuggestClass = QuerySuggestClass;
    this.QuerySuggestClass(id);
}

function QuerySuggestClass(id) {
    var inputfield = getElementById(id);
    this.set = function(text, curor) {
        inputfield.value = text;
        inputfield.focus();
        LeaveQuerySuggestImmediate(inputfield);
    }
    this.get = function() {
        return inputfield.value;
    }
    this.getCursor = function() {
        return inputfield.value.length;
    }
}

function closeQuerySuggest(self) {
    if (!self.gui_hasFocus && !self.isKeepOpen
            && !self.isMouseIn) {
        self.loading = false;
        if (self.timer) {
            window.clearTimeout(self.timer);
            self.timer = null;
        }
        if (self.suggestwindow) {
	        notifyRemoveNode(self.suggestwindow);
	        if (self.suggestwindow) {
	            self.suggestwindow.parentNode.removeChild(self.suggestwindow);
	            self.suggestwindow = null;
	        }
        }
    }
}

function LeaveQuerySuggestImmediate(self) {
	if(Dbg.debugPopups){return;}

    self.isKeepOpen = false;
    self.isMouseIn = false;
    self.gui_hasFocus = false;
    closeQuerySuggest(self);
}

function LeaveQuerySuggest(self) {
	if(Dbg.debugPopups){return;}

    if (self.timer) {
        window.clearTimeout(self.timer);
    }
    self.timer = window.setTimeout(function() {
        closeQuerySuggest(self)
    }, 10);
}

function gui_sli(self) {
    SelectListItem(self);
}

function SelectListItem(self) {
    var siblings = self.parentNode.childNodes;
    for ( var i = 0; i < siblings.length; i++) {
        var sibling = siblings[i];
        var newname;
        if (sibling == self) {
            newname = "gui_list_selected";
            self.parentNode.selectedIndex = self.parentNode.oldSelectedIndex = i;
        } else
            newname = "gui_list";
        if (sibling.className != newname) {
            sibling.className = newname;
        }
    }
}

function gui_kpl(event, self) {
    return KeyPressedList(event, self);
}

function checkListVisible(self) {
    if (self.oldSelectedIndex >= 0)
        self.childNodes[self.oldSelectedIndex].className = "gui_list";
    self.oldSelectedIndex = self.selectedIndex;
    var child = self.childNodes[self.oldSelectedIndex];
    child.className = "gui_list_selected";
    var parent = child.offsetParent;
    if (child.offsetTop < parent.scrollTop)
        parent.scrollTop = child.offsetTop;
    if (child.offsetTop + child.offsetHeight > parent.scrollTop
            + parent.offsetHeight)
        parent.scrollTop = child.offsetTop + child.offsetHeight
                - parent.offsetHeight;
}

function KeyPressedList(event, self) {
    if (!self.selectedIndex && self.selectedIndex != 0)
        self.selectedIndex = self.oldSelectedIndex = -1;
    if (Browser.getKeyCode(event) == 38) {
        /* up */
        self.selectedIndex--;
        if (self.selectedIndex < 0)
            self.selectedIndex = self.childNodes.length - 1;
        checkListVisible(self);
        return false;
    }
    if (Browser.getKeyCode(event) == 40) {
        /* up */
        self.selectedIndex++;
        if (self.selectedIndex >= self.childNodes.length)
            self.selectedIndex = 0;
        checkListVisible(self);
        return false;
    }
    if (Browser.getKeyCode(event) == 33) {
        /* pgup */
        var minHeight = self.parentNode.offsetHeight;
        for ( var p = self.parentNode.offsetParent; p; p = p.offsetParent)
            if (p.offsetHeight > 1)
                minHeight = Math.min(p.offsetHeight, minHeight);
        self.selectedIndex -= Math.floor(1 + (minHeight - 1)
                / self.childNodes[0].offsetHeight);
        if (self.selectedIndex < 0)
            self.selectedIndex = 0;
        checkListVisible(self);
        return false;
    }
    if (Browser.getKeyCode(event) == 34) {
        /* pgdw */
        var minHeight = self.parentNode.offsetHeight;
        for ( var p = self.parentNode.offsetParent; p; p = p.offsetParent)
            if (p.offsetHeight > 1)
                minHeight = Math.min(p.offsetHeight, minHeight);
        self.selectedIndex += Math.floor(1 + (minHeight - 1)
                / self.childNodes[0].offsetHeight);
        if (self.selectedIndex >= self.childNodes.length)
            self.selectedIndex = self.childNodes.length - 1;
        checkListVisible(self);
        return false;
    }
    if (Browser.getKeyCode(event) == 27) {
        /* esc */
        if (self.onblur)
            self.onblur();
        return false;
    }
    if (Browser.getKeyCode(event) == ' ' || Browser.getKeyCode(event) == 13) {
        var children = self.childNodes;
        for ( var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child.className == "gui_list_selected") {
                child.onmousedown();
                return false;
            }
        }
        return true;
    }
    return true;
}

function gui_kps(event, self) {
    return KeyPressedStringInput(event, self);
}

function propagateQSKeyPress(event, self) {
    if (self.onkeydown) {
        return Browser.invokeEventHandler(self, 'keydown', event);
    } else {
        var children = self.childNodes;
        for ( var i = 0; i < children.length; i++)
            if (!propagateQSKeyPress(event, children[i]))
                return false;
    }
    return true;
}

function KeyPressedStringInput(event, self) {
    if (self.suggestwindow) {
        if (Browser.getKeyCode(event) == 27) {
            LeaveQuerySuggestImmediate(self);
            return false;
        } else if ((Browser.getKeyCode(event) >= 13 && Browser
                .getKeyCode(event) <= 40)
                || Browser.getKeyCode(event) == ' ') {
            if (!propagateQSKeyPress(event, self.suggestwindow))
                return false;
            else if (Browser.getKeyCode(event)==13) {
                LeaveQuerySuggestImmediate(self);
                return true;
            }
        }
    } else {
        if (Browser.getKeyCode(event) == 40)
            OpenQuerySuggest(event, self);
    }
    return true;
}

function scrollToMe() {
    var id = createUID();
    document.write("<span id=\"a" + id + "\"></span>");
    executeAfterSwap(function() {
        var self = getElementById("a" + id);
        if (self) {
            var pos = Browser.getPosition(self);
            var parent = self.parentNode;
            var parentStyle = Browser.getStyle(parent, "overflow");

            while (parent != null && parentStyle != "auto"
                    && parentStyle != "hidden" && parentStyle != "scroll") {
                var currentParent = parent.parentNode;
                if (currentParent != null) {
                    parentStyle = Browser.getStyle(currentParent, "overflow");
                } else {
                    parentStyle = null;
                }
                parent = currentParent;
            }
            if (parent) {
                var parentpos = Browser.getPosition(parent);
                var parentHeight = parent.offsetHeight;
                if (parent.scrollLeft || parent.scrollLeft == 0)
                    parentHeight -= 20;
                if (pos.top < parentpos.top)
                    parent.scrollTop -= parentpos.top - pos.top;
                if (pos.top - parentpos.top > parentHeight
                        - self.parentNode.offsetHeight)
                    parent.scrollTop += pos.top - parentpos.top - parentHeight
                            + self.parentNode.offsetHeight;
            }
        }
    });
}

var menus=Browser.createArray();

function focusFirstChild(div) {
  if (div.onblur) {
      div.focus();
      return true;
  }
  var children = div.childNodes;
  if (children)
      for (var i = 0; i < children.length; i++)
          if (focusFirstChild(children[i]))
              return true;
  return false;
}

function openMenu(parent, href) {
    var http_request = makeRequest(href + "&menu&rnd="+Math.random());
    http_request.placeJavascriptWindow = function(div, exist) {
        if (!exist) {
            div.className = 'gui_menuWindow';
            var windows = getNamedAbsoluteRootDiv('menuWindows');
            var parentpos = Browser.getPosition(windows);
            var mypos = Browser.getPosition(parent);
            var left = mypos.left - parentpos.left;
            var top = mypos.top - parentpos.top;
            div.style.left = left + "px";
            div.style.top = top + "px";
            windows.appendChild(div);
            menus.push(div);
        }
        http_request.child=div;
    };
    http_request.onreadystatechange = function() {
       gotit(http_request, "ignore");
       if (http_request.child)
         focusFirstChild(http_request.child);
    };
}

function closeMenu() {
    var last=menus.pop();
    getNamedAbsoluteRootDiv('menuWindows').removeChild(last);
}

function executeAndCloseMenu(href) {
    closeMenu();
    var http_request = makeRequest(href);
    http_request.onreadystatechange = function() {
        gotit(http_request, "ignore");
    };
}
