(function ($) {
	var menus = [],
	visibleMenus = [],
	activeMenu = activeItem = null,
	menuDIVElement = $('<div class="menu-div outerbox" style="position:absolute;overflow:auto;top:0;left:0;display:none;z-index:100"><div class="shadowbox1"></div><div class="shadowbox2"></div><div class="shadowbox3"></div></div>')[0],
	menuULElement = $('<ul class="menu-ul innerbox" style="overflow:hidden;"></ul>')[0],
	menuItemElement = $('<li style="position:relative;"><div class="menu-item"></div></li>')[0],
	arrowElement = $('<img class="menu-item-arrow" />')[0],
	$rootDiv = $('<div id="root-menu-div" style="position:absolute;top:0;left:0;"></div>'),
	defaults = {
		showDelay : 100,
		hideDelay : 100,
		hoverOpenDelay : 0,
		offsetTop : 0,
		offsetLeft : 0,
		minWidth : 0,
		onOpen : null,
		onClose : null,
		onClick : null,
		arrowSrc : null,
		addExpando : false,
		copyClassAttr : false
	};
	$(function () {
		$rootDiv.appendTo('body')
	});
	$.extend({
		MenuCollection : function (items) {
			this.menus = [];
			this.init(items)
		}
	});
	$.extend($.MenuCollection, {
		prototype : {
			init : function (items) {
				if (items && items.length) {
					for (var i = 0; i < items.length; i++) {
						this.addMenu(items[i]);
						items[i].menuCollection = this
					}
				}
			},
			addMenu : function (menu) {
				if (menu instanceof $.DDMenu)
					this.menus.push(menu);
				menu.menuCollection = this;
				var self = this;
				$(menu.target).hover(function () {
					if (menu.visible)
						return;
					for (var i = 0; i < self.menus.length; i++) {
						if (self.menus[i].visible) {
							self.menus[i].hide();
							menu.show();
							return
						}
					}
				}, function () {})
			}
		}
	});
	$.extend({
		DDMenu : function (target, items, options, ajaxurl) {
			this.menuItems = [];
			this.subMenus = [];
			this.visible = false;
			this.active = false;
			this.parentMenuItem = null;
			this.settings = $.extend({}, defaults, options);
			this.target = target;
			this.$eDIV = null;
			this.$eUL = null;
			this.timer = null;
			this.menuCollection = null;
			this.openTimer = null;
			this.ajaxurl = ajaxurl;
			this.init();
			if (items && items.constructor == Array)
				this.addItems(items)
		}
	});
	$.extend($.DDMenu, {
		checkMouse : function (e) {
			var t = e.target;
			if (visibleMenus.length && t == visibleMenus[0].target)
				return;
			while (t.parentNode && t.parentNode != $rootDiv[0])
				t = t.parentNode;
			if (!$(visibleMenus).filter(function () {
					return this.$eDIV[0] == t
				}).length) {
				$.DDMenu.closeAll()
			}
		},
		checkKey : function (e) {
			switch (e.keyCode) {
			case 13:
				if (activeItem)
					activeItem.click(e, activeItem.$eLI[0]);
				break;
			case 27:
				$.DDMenu.closeAll();
				break;
			case 37:
				if (!activeMenu)
					activeMenu = visibleMenus[0];
				var a = activeMenu;
				if (a && a.parentMenuItem) {
					var pmi = a.parentMenuItem;
					pmi.$eLI.unbind('mouseout').unbind('mouseover');
					a.hide();
					pmi.hoverIn(true);
					setTimeout(function () {
						pmi.bindHover()
					})
				} else if (a && a.menuCollection) {
					var pos,
					mcm = a.menuCollection.menus;
					if ((pos = $.inArray(a, mcm)) > -1) {
						if (--pos < 0)
							pos = mcm.length - 1;
						$.DDMenu.closeAll();
						mcm[pos].show();
						mcm[pos].setActive();
						if (mcm[pos].menuItems.length)
							mcm[pos].menuItems[0].hoverIn(true)
					}
				}
				break;
			case 38:
				if (activeMenu)
					activeMenu.selectNextItem(-1);
				break;
			case 39:
				if (!activeMenu)
					activeMenu = visibleMenus[0];
				var m,
				a = activeMenu,
				asm = activeItem ? activeItem.subMenu : null;
				if (a) {
					if (asm && asm.menuItems.length) {
						asm.show();
						asm.menuItems[0].hoverIn()
					} else if ((a = a.inMenuCollection())) {
						var pos,
						mcm = a.menuCollection.menus;
						if ((pos = $.inArray(a, mcm)) > -1) {
							if (++pos >= mcm.length)
								pos = 0;
							$.DDMenu.closeAll();
							mcm[pos].show();
							mcm[pos].setActive();
							if (mcm[pos].menuItems.length)
								mcm[pos].menuItems[0].hoverIn(true)
						}
					}
				}
				break;
			case 40:
				if (!activeMenu) {
					if (visibleMenus.length && visibleMenus[0].menuItems.length)
						visibleMenus[0].menuItems[0].hoverIn()
				} else
					activeMenu.selectNextItem();
				break
			}
			if (e.keyCode > 36 && e.keyCode < 41)
				return false
		},
		closeAll : function () {
			while (visibleMenus.length)
				visibleMenus[0].hide()
		},
		setDefaults : function (d) {
			$.extend(defaults, d)
		},
		prototype : {
			init : function () {
				var self = this;
                this.column = 0;
                this.column_limit = 15;
				if (!this.target)
					return;
				else if (this.target instanceof $.MenuItem) {
					this.parentMenuItem = this.target;
					this.target.addSubMenu(this);
					this.target = this.target.$eLI
				}
				menus.push(this);
				this.$eDIV = $(menuDIVElement.cloneNode(1));
				this.$eUL = $(menuULElement.cloneNode(1));
				this.$eDIV[0].appendChild(this.$eUL[0]);
				this.$eCol = [[]];
				$rootDiv[0].appendChild(this.$eDIV[0]);
				if (!this.parentMenuItem) {
					$(this.target).click(function (e) {
						self.onClick(e)
					}).hover(function (e) {
						self.setActive();
						if (self.settings.hoverOpenDelay) {
							self.openTimer = setTimeout(function () {
									if (!self.visible)
										self.onClick(e)
								}, self.settings.hoverOpenDelay)
						}
					}, function () {
						if (!self.visible)
							$(this).removeClass('activetarget');
						if (self.openTimer)
							clearTimeout(self.openTimer)
					})
				} else {
					this.$eDIV.hover(function () {
						self.setActive()
					}, function () {})
				}
			},
			setActive : function () {
				if (!this.parentMenuItem)
					$(this.target).addClass('activetarget');
				else
					this.active = true
			},
			addItem : function (item) {
				if (item instanceof $.MenuItem) {
					if ($.inArray(item, this.menuItems) == -1) {
						//this.$eUL.append(item.$eLI);
                        if (this.$eCol[this.column].length == this.column_limit) {
                            this.$eCol.push([]);
                            this.column++;
                        }
                        this.$eCol[this.column].push(item.$eLI);
						this.menuItems.push(item);
						item.parentMenu = this;
						if (item.subMenu)
							this.subMenus.push(item.subMenu)
					}
				} else {
					this.addItem(new $.MenuItem(item, this.settings))
				}
			},
			addItems : function (items) {
				if (items != null) {
                    this.column_limit = Math.floor($(window).height() / 21) - 1;
					for (var i = 0; i < items.length; i++) {
						this.addItem(items[i])
					}

                    for (var i = 0; i < this.$eCol.length; i++) {
                        var div = $('<div class="column"></div>');
                        for (var y = 0; y < this.$eCol[i].length; y++) {
                            $(div).append(this.$eCol[i][y]);
                        }
                        this.$eUL.append(div);
                    }
				}
			},
			removeItem : function (item) {
				var pos = $.inArray(item, this.menuItems);
				if (pos > -1)
					this.menuItems.splice(pos, 1);
				item.parentMenu = null
			},
			removeItems : function () {
				this.init()
			},
			hide : function () {
				if (!this.visible)
					return;
				var i,
				pos = $.inArray(this, visibleMenus);
				this.$eDIV.hide();
				if (pos >= 0)
					visibleMenus.splice(pos, 1);
				this.visible = this.active = false;
				$(this.target).removeClass('activetarget');
				for (i = 0; i < this.subMenus.length; i++) {
					this.subMenus[i].hide()
				}
				for (i = 0; i < this.menuItems.length; i++) {
					if (this.menuItems[i].active)
						this.menuItems[i].setInactive()
				}
				if (!visibleMenus.length)
					$(document).unbind('mousedown', $.DDMenu.checkMouse).unbind('keydown', $.DDMenu.checkKey);
				if (activeMenu == this)
					activeMenu = null;
				if (this.settings.onClose)
					this.settings.onClose.call(this)
			},
			show : function (e) {
				this.getAjaxSubMenu();
				if (this.visible)
					return;
				var zi,
				pmi = this.parentMenuItem;
				if (this.menuItems.length) {
                    var div_total_width = 0;
					if (pmi) {
						zi = parseInt(pmi.parentMenu.$eDIV.css('z-index'));
						this.$eDIV.css('z-index', (isNaN(zi) ? 1 : zi + 1))
					}
					this.$eDIV.css({
						visibility : 'hidden',
						display : 'block'
					});
					if (this.settings.minWidth) {
						if (this.$eDIV.width() < this.settings.minWidth)
							this.$eDIV.css('width', this.settings.minWidth)
					}
					//alert(this.$eDIV.height());
					//alert(screen.height);
					this.setPosition();
					this.$eDIV.css({
						display : 'none',
						visibility : ''
					}).show();
					if ($.browser.msie)
						this.$eUL.css('width', parseInt($.browser.version) == 6 ? this.$eDIV.width() - 7 : this.$eUL.width());
					if (this.settings.onOpen)
						this.settings.onOpen.call(this)

                    $('.column', this.$eDIV).each(function(index) {
                        div_total_width += $(this).width();
                    });
                    div_total_width += 4;
                    $(this.$eDIV).css('width', div_total_width);
				}
				if (visibleMenus.length == 0)
					$(document).bind('mousedown', $.DDMenu.checkMouse).bind('keydown', $.DDMenu.checkKey);
				this.visible = true;
				visibleMenus.push(this)
			},
			setPosition : function () {
				var $t,
				o,
				posX,
				posY,
				pmo,
				wst,
				wsl,
				ww = $(window).width(),
				wh = $(window).height(),
				pmi = this.parentMenuItem,
				height = this.$eDIV[0].clientHeight,
				width = this.$eDIV[0].clientWidth,
				pheight;
				if (pmi) {
					o = pmi.$eLI.offset();
					posX = o.left + pmi.$eLI.width();
					posY = o.top
				} else {
					$t = $(this.target);
					o = $t.offset();
					posX = o.left + this.settings.offsetLeft;
					posY = o.top + $t.height() + this.settings.offsetTop
				}
				if ($.fn.scrollTop) {
					wst = $(window).scrollTop();
					if (wh < height) {
						posY = wst
					} else if (wh + wst < posY + height) {
						if (pmi) {
							pmo = pmi.parentMenu.$eDIV.offset();
							pheight = pmi.parentMenu.$eDIV[0].clientHeight;
							if (height <= pheight) {
								posY = pmo.top + pheight - height
							} else {
								posY = pmo.top
							}
							if (wh + wst < posY + height) {
								posY -= posY + height - (wh + wst)
							}
						} else {
							posY -= posY + height - (wh + wst)
						}
					}
				}
				if ($.fn.scrollLeft) {
					wsl = $(window).scrollLeft();
					if (ww + wsl < posX + width) {
						if (pmi) {
							posX -= pmi.$eLI.width() + width;
							if (posX < wsl)
								posX = wsl
						} else {
							posX -= posX + width - (ww + wsl)
						}
					}
				}
				this.$eDIV.css({
					left : posX,
					top : posY
				})
			},
			onClick : function (e) {
				if (this.visible) {
					this.hide();
					this.setActive()
				} else {
					$.DDMenu.closeAll();
					this.show(e)
				}
			},
			addTimer : function (callback, delay) {
				var self = this;
				this.timer = setTimeout(function () {
						callback.call(self);
						self.timer = null
					}, delay)
			},
			removeTimer : function () {
				if (this.timer) {
					clearTimeout(this.timer);
					this.timer = null
				}
			},
			selectNextItem : function (offset) {
				var i,
				pos = 0,
				mil = this.menuItems.length,
				o = offset || 1;
				for (i = 0; i < mil; i++) {
					if (this.menuItems[i].active) {
						pos = i;
						break
					}
				}
				this.menuItems[pos].hoverOut();
				do {
					pos += o;
					if (pos >= mil)
						pos = 0;
					else if (pos < 0)
						pos = mil - 1
				} while (this.menuItems[pos].separator);
				this.menuItems[pos].hoverIn(true)
			},
			inMenuCollection : function () {
				var m = this;
				while (m.parentMenuItem)
					m = m.parentMenuItem.parentMenu;
				return m.menuCollection ? m : null
			},
			destroy : function () {
				var pos,
				item;
				this.hide();
				if (!this.parentMenuItem)
					$(this.target).unbind('click').unbind('mouseover').unbind('mouseout');
				else
					this.$eDIV.unbind('mouseover').unbind('mouseout');
				while (this.menuItems.length) {
					item = this.menuItems[0];
					item.destroy();
					delete item
				}
				if ((pos = $.inArray(this, menus)) > -1)
					menus.splice(pos, 1);
				if (this.menuCollection) {
					if ((pos = $.inArray(this, this.menuCollection.menus)) > -1)
						this.menuCollection.menus.splice(pos, 1)
				}
				this.$eDIV.remove()
			},
			getAjaxSubMenu : function () {
				if (this.ajaxurl != null) {
					var x;
					this.removeItems();
					$.ajax({
						url : this.ajaxurl,
						dataType : "json",
						async : false,
						success : function (json) {
							x = json
						}
					});
					this.addItems(x)
				}
			}
		}
	});
	$.extend({
		MenuItem : function (obj, options) {
			if (typeof obj == 'string')
				obj = {
					src : obj
				};
			this.src = obj.src || '';
			this.url = obj.url || null;
			this.urlTarget = obj.target || null;
			this.addClass = obj.addClass || null;
			this.datax = obj.datax || null;
			this.ajaxurl = obj.ajaxurl || null;
			this.icon = obj.icon || null;
			this.icon_over = obj.icon_over || null;
			this.$eLI = null;
			this.parentMenu = null;
			this.subMenu = null;
			this.settings = $.extend({}, defaults, options);
			this.active = false;
			this.enabled = true;
			this.separator = false;
			this.init();
			if (obj.subMenu)
				new $.DDMenu(this, obj.subMenu, options, null)
		}
	});
	$.extend($.MenuItem, {
		prototype : {
			init : function () {
				var i,
				isStr,
				src = this.src,
				self = this;
				this.$eLI = $(menuItemElement.cloneNode(1));
				if (this.addClass)
					this.$eLI[0].setAttribute('class', this.addClass);
				if (this.settings.addExpando && this.datax)
					this.$eLI[0].menuData = this.datax;
				if (src == '') {
					this.$eLI.addClass('menu-separator');
					this.separator = true
				} else {
					isStr = typeof src == 'string';
					if (isStr && this.url)
						src = $('<a href="' + this.url + '"' + (this.urlTarget ? 'target="' + this.urlTarget + '"' : '') + '>' + src + '</a>');
					else if (isStr || !src.length)
						src = [src];
					for (i = 0; i < src.length; i++) {
						if (typeof src[i] == 'string') {
							elem = document.createElement('span');
							elem.innerHTML = src[i];
							this.$eLI[0].firstChild.appendChild(elem)
						} else
							this.$eLI[0].firstChild.appendChild(src[i].cloneNode(1))
					}
				}
				this.$eLI.click(function (e) {
					self.click(e, this)
				});
				this.bindHover();
				if (this.ajaxurl != null) {
					this.showSubmenuArrow()
				}
				if (this.icon != null) {
					this.$eLI.css('background-image', 'url("' + this.icon + '")');
					this.$eLI.css('background-repeat', 'no-repeat')
				}
			},
			click : function (e, scope) {
				if (this.enabled && this.settings.onClick)
					this.settings.onClick.call(scope, e, this)
			},
			bindHover : function () {
				var self = this;
				this.$eLI.hover(function () {
					self.hoverIn()
				}, function () {
					self.hoverOut()
				})
			},
			hoverIn : function (noSubMenu) {
				this.removeTimer();
				this.getAjaxSubMenu();
				var i,
				pms = this.parentMenu.subMenus,
				pmi = this.parentMenu.menuItems,
				self = this;
				if (this.parentMenu.timer)
					this.parentMenu.removeTimer();
				if (!this.enabled)
					return;
				for (i = 0; i < pmi.length; i++) {
					if (pmi[i].active)
						pmi[i].setInactive()
				}
				this.setActive();
				activeMenu = this.parentMenu;
				for (i = 0; i < pms.length; i++) {
					if (pms[i].visible && pms[i] != this.subMenu && !pms[i].timer)
						pms[i].addTimer(function () {
							this.hide()
						}, pms[i].settings.hideDelay)
				}
				if (this.subMenu && !noSubMenu) {
					this.subMenu.addTimer(function () {
						this.show()
					}, this.subMenu.settings.showDelay)
				}
				if (this.icon != null) {
					this.$eLI.css('background-image', this.icon)
				}
			},
			hoverOut : function () {
				this.removeTimer();
				if (!this.enabled)
					return;
				if (!this.subMenu || !this.subMenu.visible)
					this.setInactive();
				if (this.icon_over != null) {
					this.$eLI.css('background-image', this.icon_over)
				}
			},
			removeTimer : function () {
				if (this.subMenu) {
					this.subMenu.removeTimer()
				}
			},
			setActive : function () {
				this.active = true;
				this.$eLI.addClass('active');
				var pmi = this.parentMenu.parentMenuItem;
				if (pmi && !pmi.active)
					pmi.setActive();
				activeItem = this
			},
			setInactive : function () {
				this.active = false;
				this.$eLI.removeClass('active');
				if (this == activeItem)
					activeItem = null
			},
			enable : function () {
				this.$eLI.removeClass('disabled');
				this.enabled = true
			},
			disable : function () {
				this.$eLI.addClass('disabled');
				this.enabled = false
			},
			destroy : function () {
				this.removeTimer();
				this.$eLI.remove();
				this.$eLI.unbind('mouseover').unbind('mouseout').unbind('click');
				if (this.subMenu) {
					this.subMenu.destroy();
					delete this.subMenu
				}
				this.parentMenu.removeItem(this)
			},
			addSubMenu : function (menu) {
				this.subMenu = menu;
				if (this.parentMenu && $.inArray(menu, this.parentMenu.subMenus) == -1)
					this.parentMenu.subMenus.push(menu);
				this.showSubmenuArrow()
			},
			getAjaxSubMenu : function () {
				if (this.ajaxurl != null) {
					var x;
					$.ajax({
						url : this.ajaxurl,
						dataType : "json",
						async : false,
						success : function (json) {
							x = json
						}
					});
					var sbm = new $.DDMenu(this, x, this.settings, null);
					this.addSubMenu(sbm)
				}
			},
			showSubmenuArrow : function () {
				if (this.settings.arrowSrc) {
					var a = arrowElement.cloneNode(0);
					a.setAttribute('src', this.settings.arrowSrc);
					this.$eLI[0].firstChild.appendChild(a)
				}
			}
		}
	});
	$.extend($.fn, {
		menuFromElement : function (options, list, bar) {
			var createItems = function (ul) {
				var menuItems = [],
				subItems,
				menuItem,
				lis,
				$li,
				i,
				subUL,
				submenu,
				target,
				classNames = null;
				lis = getAllChilds(ul, 'LI');
				for (i = 0; i < lis.length; i++) {
					subItems = [];
					if (!lis[i].childNodes.length) {
						menuItems.push(new $.MenuItem('', options));
						continue
					}
					if ((subUL = getOneChild(lis[i], 'UL'))) {
						subItems = createItems(subUL);
						$(subUL).remove()
					}
					$li = $(lis[i]);
					if ($li[0].childNodes.length == 1 && $li[0].childNodes[0].nodeType == 3)
						target = $li[0].childNodes[0].nodeValue;
					else
						target = $li[0].childNodes;
					if (options && options.copyClassAttr)
						classNames = $li.attr('class');
					menuItem = new $.MenuItem({
							src : target,
							addClass : classNames
						}, options);
					menuItems.push(menuItem);
					if (subItems.length)
						new $.DDMenu(menuItem, subItems, options, null)
				}
				return menuItems
			};
			return this.each(function () {
				var ul,
				m;
				if (list || (ul = getOneChild(this, 'UL'))) {
					ul = list ? $(list).clone(true)[0] : ul;
					menuItems = createItems(ul);
					if (menuItems.length) {
						m = new $.DDMenu(this, menuItems, options, null);
						if (bar)
							bar.addMenu(m)
					}
					$(ul).hide()
				}
			})
		},
		menuBarFromUL : function (options) {
			return this.each(function () {
				var i,
				lis = getAllChilds(this, 'LI');
				if (lis.length) {
					bar = new $.MenuCollection();
					for (i = 0; i < lis.length; i++)
						$(lis[i]).menuFromElement(options, null, bar)
				}
			})
		},
		ddmenu : function (options, items) {
			return this.each(function () {
				if (items && items.constructor == Array)
					new $.DDMenu(this, items, options, null);
				else {
					if (this.nodeName.toUpperCase() == 'UL')
						$(this).menuBarFromUL(options);
					else
						$(this).menuFromElement(options, items)
				}
			})
		},
		ajax_menu : function (options, ajaxurl) {
			return this.each(function () {
				new $.DDMenu(this, null, options, ajaxurl)
			})
		}
	});
	var getOneChild = function (elem, name) {
		if (!elem)
			return null;
		var n = elem.firstChild;
		for (; n; n = n.nextSibling) {
			if (n.nodeType == 1 && n.nodeName.toUpperCase() == name)
				return n
		}
		return null
	};
	var getAllChilds = function (elem, name) {
		if (!elem)
			return [];
		var r = [],
		n = elem.firstChild;
		for (; n; n = n.nextSibling) {
			if (n.nodeType == 1 && n.nodeName.toUpperCase() == name)
				r[r.length] = n
		}
		return r
	}
})(jQuery);

