/**
 ** SynFlag Menu: DHTML Menu
 ** Copyright: 2007 SynFlag Online Agentur, Marcel Linnenfelser
 ** Author:    Marcel Linnenfelser
 ** License:   LGPL
 ** Version: 0.5b
 **
 ** Tested with: Internet Explorer 5, 5.5, 6, 7, Safari 3, Firefox 1.5, 2, Opera 9 
 **/

    var synflag = {};
	
	synflag.n = function (id) {
		return document.getElementById(id);
	}
	
    synflag.browser = {};
    synflag.browser.initialized = false;
    synflag.browser.sniff = function () {
    	if (synflag.browser.initialized)
    		return;
	    synflag.browser.initialized = true;
	    synflag.browser.webkit= false;
	    synflag.browser.ie50  = (navigator.userAgent.toLowerCase().indexOf('msie 5.0')>-1);
	    synflag.browser.ie55  = (navigator.userAgent.toLowerCase().indexOf('msie 5.5')>-1);
	    synflag.browser.ie5   = (synflag.browser.ie50 || synflag.browser.ie55)
	    synflag.browser.ie6   = (navigator.userAgent.toLowerCase().indexOf('msie 6.0')>-1);
	    synflag.browser.ie7   = (navigator.userAgent.toLowerCase().indexOf('msie 7.0')>-1);
	    synflag.browser.ie    = (synflag.browser.ie5 || synflag.browser.ie6 || synflag.browser.ie7)
		synflag.browser.gecko = (navigator.userAgent.toLowerCase().indexOf('gecko')>-1);
		synflag.browser.windows = (navigator.userAgent.toLowerCase().indexOf('windows')>-1);
		if ((navigator.userAgent.toLowerCase().indexOf('mac os x')>-1)) {
			synflag.browser.windows = false;
			synflag.browser.macosx  = true;
		} else {
			synflag.browser.macosx  = false;
		}
		if ((navigator.userAgent.toLowerCase().indexOf('applewebkit')>-1)) {
			synflag.browser.gecko  = false;
			synflag.browser.webkit = true;
		}
    }
    synflag.browser.sniff();
    
    synflag.browser.getViewport = function () {
		if (self.innerWidth) {
			return { width: self.innerWidth, height: self.innerHeight };
		}
		else if (document.documentElement && document.documentElement.clientWidth)
		{
			return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight };
		}
		else if (document.body)
		{
			return { width: document.body.clientWidth, height: document.body.clientHeight };
		}
		else 
			return { width: 0, height: 0 };
	}

    synflag.widget = {};
    synflag.widget.MenuItem = function (url, text) {
    	
    	this.url  = url;
    	this.text = text;
    	this.subMenu = null;
    	this.top  = 0;
    	this.left = 0;
    	this.nextSibling = null;
    	this.prevSibling = null;
    	this.root = null;
		this.itemClass = null;
		this.itemOverClass = null;
		this.isSeparator = false;
    
        this.setIsSeparator = function (bool) {
            this.isSeparator = bool;
        }

        this.setParentMenu = function (parent) {
            this.parent = parent;
        }

        this.setOver = function (bool) {
			if (bool && !this.isSeparator) {
	            this.domNode.className = ( this.itemOverClass == null ? this.parent.itemOverClass : this.itemOverClass );
			} else {
	            this.domNode.className = ( this.itemClass == null     ? this.parent.itemClass     : this.itemClass );
			}
        }

        this.setRoot = function (root) {
            this.root = root;
        	if (this.subMenu != null) {
        		this.subMenu.setRoot(root);
        	}            
        }

        this.setNextSibling = function (next) {
            this.nextSibling = next;
        }

        this.setPrevSibling = function (prev) {
            this.prevSibling = prev;
        }
        
        this.updatePosition = function () {
   			this.top = this.parent.padding.top;
   			this.left = this.parent.padding.left;
        	if (this.parent.orientation == 'vertical') {
        		if (this.prevSibling != null) {
        			if (this.parent.borderCollapse) {
        				this.top = this.prevSibling.top + this.parent.itemSpacing + this.parent.getCollapsedItemHeight(this.prevSibling);
        			} else {
        				this.top = this.prevSibling.top + this.parent.itemSpacing + this.parent.getFullItemHeight(this.prevSibling);
        			}
        		}
        	} else {
        		if (this.prevSibling != null) {
        			if (this.parent.borderCollapse) {
        				this.left = this.prevSibling.left + this.parent.itemSpacing + this.parent.getCollapsedItemWidth(this.prevSibling);
        			} else {
        				this.left = this.prevSibling.left + this.parent.itemSpacing + this.parent.getFullItemWidth(this.prevSibling);
        			}
        		}
        	}
            with (this.domNode.style) {
				position = "absolute";
            	top      = this.top+this.parent.unit;
            	left     = this.left+this.parent.unit;
			}
        }

        this.create = function () {
            this.domNode = document.createElement("div");
            var _this = this;
            this.domNode.onmouseover = function (e) {
            	// handle only once
            	if (!_this.root.eventHandled) {
	            	window.clearTimeout(_this.root.timer);
            		_this.root.eventHandled = true;
    	        	_this.parent.hideChildrensSubMenus();
	            	_this.setOver(true);
    	        	var item = _this;
    	        	while (item.parent.parent != null) {
    	        		item = item.parent.parent;
    	        		item.setOver(true);
    	        	}
        	    	if (_this.subMenu != null)
	        	    	_this.subMenu.setVisible(true);
	        	}
            };
            this.domNode.onmouseout = function (e) {
            	var _t = _this;
            	window.clearTimeout(_this.root.timer);
            	_this.root.timer = window.setTimeout(function () { _t.root.setVisible(false); }, 500);
            	// delete here, all mouseout fired in a row before next mouse over
            	delete _this.root.eventHandled;
            	_this.setOver(false);
            };
            this.domNode.innerHTML = text;
			this.updatePosition();
            if (this.url != null && !this.isSeparator)
	            this.domNode.onclick = function (e) {
    	        	window.location.href = _this.url;
        	    }
            with (this.domNode.style) {
            	if (this.parent.width > 0)
		           	width    = this.parent.width+this.parent.unit;
            	if (this.parent.height > 0)
	            	height   = this.parent.height+this.parent.unit;
            	borderWidth = this.parent.itemBorder.top+this.parent.unit+" "+this.parent.itemBorder.right+this.parent.unit+" "
            		+this.parent.itemBorder.bottom+this.parent.unit+" "+this.parent.itemBorder.left+this.parent.unit;
            	borderStyle = this.parent.itemBorder.style;
            	borderColor = this.parent.itemBorder.color;
            	padding  = this.parent.itemPadding.top+this.parent.unit+" "+this.parent.itemPadding.right+this.parent.unit+" "
            		+this.parent.itemPadding.bottom+this.parent.unit+" "+this.parent.itemPadding.left+this.parent.unit;
            	overflow = 'visible';
            	if (this.parent.orientation == 'horizontal') {
            		cssFloat = 'left';
            	}
            	if (!synflag.browser.ie5 && !this.isSeparator)
            	   cursor = 'pointer';
            }
			this.setOver(false);
          	this.parent.domNode.appendChild(this.domNode);
          	if (this.subMenu != null)
	          	this.subMenu.create();
        }
        
        this.setSubMenu = function (subMenu) {
        	this.subMenu = subMenu;
        	this.subMenu.setParent(this);
        	this.subMenu.setRoot(this.root);
        }
		
		
		if (arguments[2]) {
			this.itemClass = arguments[2];
		}
		if (arguments[3]) {
			this.itemOverClass = arguments[3];
		}
        
     };

    synflag.widget.Menu = function (config) {

        this.items  = [];
        this.parent = null;
        // top and left: relative values; if parent == null relative to page, else relative to automatic position
        this.top    = 0;
        this.left   = 0;
        this.width  = 0;
        this.height = 0;
        this.unit   = "px";
        this.alwaysVisible = false;
        this.visible = false;
        this.root   = this;
        this.itemClass     = "";
        this.itemOverClass = "";
        this.orientation = "vertical";
        this.containerClass = "";
        this.itemSpacing = 0;
		this.arrangeWidth = null;

        this.setParent = function (parent) {
            this.parent = parent;
        }

        this.setRoot = function (root) {
            this.root = root;
        	for (var i = 0; i < this.items.length; i++) {
        		this.items[i].setRoot(root);
        	}            
        }

        this.prepareBorder = function (border) {
        	if (typeof border == 'string' || typeof border == 'number') {
        		return {top: border, left: border, bottom: border, right: border, style: 'solid', color: 'black'};
        	} else if (typeof border == 'object') {
        		if (!border.top)
        			border.top    = 0;
        		if (!border.left)
        			border.left   = 0;
        		if (!border.right)
        			border.right  = 0;
        		if (!border.bottom)
        			border.bottom = 0;
        		if (!border.style)
        			border.style  = 'solid';
        		if (!border.color)
        			border.color  = 'black';
        		return border;
        	}
        	return {top: 0, left: 0, bottom: 0, right: 0, style: 'solid', color: 'black'};
        }
        
        this.getFullItemHeight = function (item) {
        	return item.domNode.offsetHeight;
        }

        this.getFullItemWidth = function (item) {
	       	return item.domNode.offsetWidth;
        }
        
        this.getCollapsedItemHeight = function (item) {
        	return this.getFullItemHeight(item) - Math.min(this.itemBorder.top, this.itemBorder.bottom);
        }

        this.getCollapsedItemWidth = function (item) {
        	return this.getFullItemWidth(item) - Math.min(this.itemBorder.left, this.itemBorder.left);
        }
        
        this.addItem = function (url, text) {
			var item;
			if (arguments[2])
				if (arguments[3])
		            item = new synflag.widget.MenuItem(url, text, arguments[2], arguments[3]);
				else
		            item = new synflag.widget.MenuItem(url, text, arguments[2]);
			else
	            item = new synflag.widget.MenuItem(url, text);
            item.setParentMenu(this);
            item.setRoot(this.root);
            // ie 5.0 does not support Array.push, wtf
            this.items[this.items.length] = item;
            if (this.items.length > 1) {
            	var item1 = this.items[this.items.length-2];
            	var item2 = this.items[this.items.length-1];
            	item2.setPrevSibling(item1);
            	item1.setNextSibling(item2);
            }
			// smalltalk style concat of method calls
            return this;
        }
		
        this.addSeparator = function (text) {
			var item;
			if (arguments[1])
	            item = new synflag.widget.MenuItem(null, text, arguments[1]);
			else
	            item = new synflag.widget.MenuItem(null, text);
            item.setParentMenu(this);
            item.setRoot(this.root);
			item.setIsSeparator(true);
            // ie 5.0 does not support Array.push, wtf
            this.items[this.items.length] = item;
            if (this.items.length > 1) {
            	var item1 = this.items[this.items.length-2];
            	var item2 = this.items[this.items.length-1];
            	item2.setPrevSibling(item1);
            	item1.setNextSibling(item2);
            }
			// smalltalk style concat of method calls
            return this;
        }		
        
        this.getOffsetTop = function (node) {
        	var offset = node.offsetTop;
        	while (node.offsetParent != null) {
        		node = node.offsetParent;
        		offset += node.offsetTop;
        	}
        	return offset;
        }

        this.getOffsetLeft = function (node) {
        	var offset = node.offsetLeft;
        	while (node.offsetParent != null) {
        		node = node.offsetParent;
        		offset += node.offsetLeft;
        	}
        	return offset;
        }
        
        this.unselectChildren = function () {
        	for (var i = 0; i < this.items.length; i++) {
        		this.items[i].setOver(false);
        	}
        }

        this.getMaxOffsetWidth = function () {
        	var max = 0;
        	for (var i = 0; i < this.items.length; i++) {
        		if (this.items[i].domNode.offsetWidth > max)
        			max = this.items[i].domNode.offsetWidth;
        	}
        	return max;
        }

        this.getMaxOffsetHeight = function () {
        	var max = 0;
        	for (var i = 0; i < this.items.length; i++) {
        		if (this.items[i].domNode.offsetHeight > max)
        			max = this.items[i].domNode.offsetHeight;
        	}
        	return max;
        }
        
        this.equalizeItems = function () {
        	if (this.orientation == 'vertical') {
        		var max = 0;
        		if (synflag.browser.ie5)
        			max = this.getMaxOffsetWidth();
        		else
        			max = this.getMaxOffsetWidth() - this.itemPadding.left - this.itemPadding.right - this.itemBorder.left - this.itemBorder.right;
        		for (var i = 0; i < this.items.length; i++) {
       				this.items[i].domNode.style.width = max + this.unit;
	        	}
        	} else {
        		var max = 0;
        		if (synflag.browser.ie5)
	        		max = this.getMaxOffsetHeight();
				else
	        		max = this.getMaxOffsetHeight() - this.itemPadding.top - this.itemPadding.bottom - this.itemBorder.top - this.itemBorder.bottom;
        		for (var i = 0; i < this.items.length; i++) {
       				this.items[i].domNode.style.height = max + this.unit;
	        	}
        	}
        }

        this.getCompleteItemHeight = function () {
        	var height = 0;
       		for (var i = 0; i < this.items.length; i++) {
   				height += this.items[i].domNode.offsetHeight;
        	}
        	height += (this.items.length - 1) * this.itemSpacing;
        	height += (synflag.browser.ie5?this.border.top + this.border.bottom:0);
        	height -= (this.skipLastItemBorder?this.itemBorder.bottom:0);
        	height += this.padding.top + this.padding.bottom;
        	height += (this.borderCollapse ? -1 * (this.items.length-1) * Math.min(this.itemBorder.top, this.itemBorder.bottom) : 0);
        	return height;
        }

        this.getCompleteItemWidth = function () {
			if (this.arrangeWidth == null)
				return this.getSummarizedItemWidth();
			else
				return this.arrangeWidth;
        }
		
		this.getSummarizedItemWidth = function () {
        	var width = 0;
       		for (var i = 0; i < this.items.length; i++) {
   				width += this.items[i].domNode.offsetWidth;
        	}
        	// spacing between items
        	width += (this.items.length - 1) * this.itemSpacing;
        	// ie5 border-box
        	width += (synflag.browser.ie5?this.border.left + this.border.right:0);
        	// 
        	width -= (this.skipLastItemBorder?this.itemBorder.right:0);
        	width += this.padding.left + this.padding.right;
           	width += (this.borderCollapse ? -1 * (this.items.length-1) * Math.min(this.itemBorder.left, this.itemBorder.right) : 0);
        	return width;
        }

		this.updateDimensions = function () {
            if (this.orientation == 'vertical') {
            	this.width  = this.items[0].domNode.offsetWidth + this.padding.left + this.padding.right + (synflag.browser.ie5?this.border.left + this.border.right:0);
	           	this.height = this.getCompleteItemHeight(); 
           	} else {
            	this.width    = this.getCompleteItemWidth();
   	        	this.height   = this.items[0].domNode.offsetHeight + this.padding.top + this.padding.bottom + (synflag.browser.ie5?this.border.top + this.border.bottom:0);
            }
		}

        this.create = function () {
            this.domNode = document.createElement("div");
            this.domNode.style.visibility = 'hidden';
			if (this.parentDomNodeId)
				synflag.n(this.parentDomNodeId).appendChild(this.domNode);
			else
	            document.body.appendChild(this.domNode);
            for (var i = 0; i < this.items.length; i++) {
                this.items[i].create();
            }
            this.equalizeItems();
			this.rearrange();
            var _this = this;
            // if root menu
            if (this.parent == null) {
            	this.alwaysVisible = true;
            }
            this.domNode.onmouseover = function (e) {
            	window.clearTimeout(_this.root.timer);
	           	_this.visible = true;
   	        	var item = _this.items[0];
   	        	while (item != null && item.parent.parent != null) {
   	        		item = item.parent.parent;
   	        		item.setOver(true);
   	        	}
            };
            this.domNode.onmouseout = function (e) {
	           	_this.visible = false;
	           	var _t = _this;
            	window.clearTimeout(_this.root.timer);
            	_this.root.timer = window.setTimeout(function () { _t.root.setVisible(false); }, 500);
            };
            if (this.containerClass)
            	this.domNode.className = this.containerClass;
            with (this.domNode.style) {
            	whiteSpace = 'nowrap';
				position = "absolute";
            	top      = (this.parent == null ? 0 : this.getOffsetTop(this.parent.domNode)) +this.top+this.unit;
            	left     = (this.parent == null ? 0 : this.getOffsetLeft(this.parent.domNode))+this.left+this.unit;
            	if (this.alwaysVisible == true) {
            		display = 'block';
            	} else {
            		display = 'none';
            	}
            	padding  = '0';
				this.updateDimensions();
	           	width       = this.width + this.unit;
   		       	height      = this.height + this.unit;
            	borderWidth = this.border.top+this.unit+" "+this.border.right+this.unit+" "
            		+this.border.bottom+this.unit+" "+this.border.left+this.unit;
            	borderStyle = this.border.style;
            	borderColor = this.border.color;
            	overflow = 'visible';
				zIndex = 900;
            }
			if (this.skipLastItemBorder) {
				if (this.orientation == 'vertical')
					this.domNode.lastChild.style.borderBottomWidth = 0;
				else
					this.domNode.lastChild.style.borderRightWidth = 0;
			}
            this.domNode.style.visibility = 'visible';
        }
        
        this.getLastItem = function () {
        	if (this.items.length > 0)
	        	return this.items[this.items.length-1];
	        else
	        	return null;
        }

        this.getFirstItem = function () {
        	if (this.items.length > 0)
	        	return this.items[0];
	        else
	        	return null;
        }

        this.getItem = function (index) {
        	if (this.items.length > index)
	        	return this.items[index];
	        else
	        	return null;
        }

        this.setVisible = function (bool) {
        	if (this.alwaysVisible && !bool) {
				this.hideChildrensSubMenus();
        		return;
        	}
			this.visible = bool;
			if (bool) {
           		with (this.domNode.style) {
            		top      = 0 + this.unit;
	            	left     = 0 + this.unit;
					display = 'block';
					visibility = 'hidden';
					// ! after setting top & left and before setting width & height
		            this.equalizeItems();
					this.updateDimensions();
	            	width  = this.width  + this.unit;
	            	height = this.height + this.unit;
					zIndex = 900;
				}

				var t = 0, l = 0;
           			t = (this.parent == null ? 0 : 
            			(this.getOffsetTop(this.parent.domNode) + (this.parent.parent.orientation == 'horizontal' ? this.parent.domNode.offsetHeight : 0))) 
            		    + this.top;
            		l = (this.parent == null ? 0 : 
	            		(this.getOffsetLeft(this.parent.domNode) + (this.parent.parent.orientation == 'vertical' ? this.parent.domNode.offsetWidth : 0)))
	            		+ this.left;


            	var size = synflag.browser.getViewport();
            	if (t + this.height > size.height - 10)
            		t  = size.height - this.height - (synflag.browser.ie?7:27);
            	if (l + this.width > size.width - 10) {
            		l = l - this.width - this.left + (this.parent!=null?this.parent.parent.padding.right:0) - (this.parent!=null?this.parent.parent.width:0)
						 - (synflag.browser.ie5 ? 0 : this.border.left + this.border.right);
            		if (l < 10)
            			l = size.width - this.width - 10;
            	}
            	this.domNode.style.top  = t + this.unit;
            	this.domNode.style.left = l + this.unit;
				if (this.skipLastItemBorder) {
					if (this.orientation == 'vertical')
						this.domNode.lastChild.style.borderBottomWidth = 0;
					else
						this.domNode.lastChild.style.borderRightWidth = 0;
				}
				this.domNode.style.visibility = 'visible';
			} else {
				this.domNode.style.display = 'none';
				this.hideChildrensSubMenus();
			}
        }
		
		this.rearrange = function () {
			if (this.arrangeWidth == null)
				return;
			var numSpaces = this.items.length-1;
			var arrangeSpace = this.arrangeWidth - this.getSummarizedItemWidth();
			var exactSpacing = arrangeSpace / numSpaces;
			var floorSpacing = Math.floor(exactSpacing);
			var e = arrangeSpace - (numSpaces * floorSpacing);
			this.itemSpacing = floorSpacing;
			for (var i = 1; i < this.items.length; i++) {
				if (i == this.items.length - e)
					this.itemSpacing++;
				this.items[i].updatePosition();
			}
		}
        
        this.hideChildrensSubMenus = function () {
        	for (var i = 0; i < this.items.length; i++) {
        		if (this.items[i].subMenu != null) {
        			this.items[i].subMenu.setVisible(false);
        		}
        		this.items[i].setOver(false);
        	}
        }
        
        this.moveTo = function (x, y) {
        	if (x != null) {
	        	this.left = x;
    	    	this.domNode.style.left = x + this.unit;
    	   	}
    	   	if (y != null) {
        		this.top  = y;
        		this.domNode.style.top  = y + this.unit;
        	}
        }
        
        if (config.top) {
            this.top = config.top;
            this.topCallback = function (page) { return this.top; };
        }
        if (config.topCallback) {
            this.topCallback = config.topCallback;
        }
        if (config.left) {
            this.left = config.left;
            this.leftCallback = function (page) { return this.left; };
        }
        if (config.orientation) {
            this.orientation = config.orientation;
        }
        if (config.leftCallback) {
            this.leftCallback = config.leftCallback;
        }
        if (config.width) {
            this.width = config.width;
        }
        if (config.height) {
            this.height = config.height;
        }
        // borders: border-width; style: border-style; color: border-color; => 4 values possible for each
        if (config.border) {
            this.border = this.prepareBorder(config.border);
        } else {
        	this.border = {top: 0, left: 0, bottom: 0, right: 0, style: 'solid', color: 'black'};
        }
        if (config.padding) {
            this.padding = this.prepareBorder(config.padding);
        } else {
        	this.padding = {top: 0, left: 0, bottom: 0, right: 0 };
        }
        if (config.itemBorder) {
            this.itemBorder = this.prepareBorder(config.itemBorder);
        } else {
        	this.itemBorder = {top: 0, left: 0, bottom: 0, right: 0, style: 'solid', color: 'black'};
        }
        if (config.itemPadding) {
            this.itemPadding = this.prepareBorder(config.itemPadding);
        } else {
        	this.itemPadding = {top: 0, left: 0, bottom: 0, right: 0 };
        }
        if (config.containerClass) {
            this.containerClass  = config.containerClass;
        }
        if (config.itemClass) {
            this.itemClass  = config.itemClass;
        }
        if (config.itemOverClass) {
            this.itemOverClass  = config.itemOverClass;
        }
        if (config.borderCollapse) {
            this.borderCollapse  = config.borderCollapse;
        } else {
            this.borderCollapse  = false;
        }
        if (config.skipLastItemBorder) {
            this.skipLastItemBorder  = config.skipLastItemBorder;
        } else {
            this.skipLastItemBorder  = false;
        }
        if (config.itemSpacing) {
            this.itemSpacing  = config.itemSpacing;
        }
        if (config.arrangeWidth) {
            this.arrangeWidth    = config.arrangeWidth;
        }
        if (config.parentDomNodeId) {
            this.parentDomNodeId    = config.parentDomNodeId;
        }
        if (config.unit) {
            this.unit = config.unit;
        } else {
            this.unit = 'px';
        }
                
    };
