var WebstoreMenu = {
	baseItemIDs: [], //array containing ids of all the primary menus on the page
	baseItems: {}, //object array containing all top menu item links
	subULItems: {}, //object array containing all ULs
	lastActiveSubULItem: {}, //object object containing info for last mouse out menu item's UL
	baseItemsIndex: -1,
	ULItemIndex: -1,
	hideTimers: {}, //object array timer
	shimAdded: false,
	nonFF: !/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent), //detect non FF browsers
	GetOffset: function(el, offsetType) {
		return (el.offsetParent) ? el[offsetType] + this.GetOffset(el.offsetParent, offsetType) : el[offsetType]
	},

	GetOffsetOf: function(el) {
		el._offsets = { left: this.GetOffset(el, "offsetLeft"), top: this.GetOffset(el, "offsetTop") }
	},

	GetWindowSize: function() {
		this.docWidth = window.innerWidth ? window.innerWidth - 10 : this.docElement.clientWidth - 10
		this.docHeight = window.innerHeight ? window.innerHeight - 15 : this.docElement.clientHeight - 18
	},

	GetTopItemsDimensions: function() {
		for (var m = 0; m < this.baseItemIDs.length; m++) {
			var topMenuID = this.baseItemIDs[m]
			for (var i = 0; i < this.baseItems[topMenuID].length; i++) {
				var header = this.baseItems[topMenuID][i]
				var subMenu = document.getElementById(header.getAttribute('subMenu'))
				header._dimensions = { w: header.offsetWidth, h: header.offsetHeight, submenuw: subMenu.offsetWidth, submenuh: subMenu.offsetHeight }
			}
		}
	},

	IsContained: function(m, e) {
		var e = window.event || e
		var c = e.relatedTarget || ((e.type == "mouseover") ? e.fromElement : e.toElement)
		while (c && c != m) try { c = c.parentNode } catch (e) { c = m }
		if (c == m)
			return true
		else
			return false
	},

	CSS: function(el, targetClass, action) {
		var needle = new RegExp("(^|\\s+)" + targetClass + "($|\\s+)", "ig")
		if (action == "check")
			return needle.test(el.className)
		else if (action == "remove")
			el.className = el.className.replace(needle, "")
		else if (action == "add" && !needle.test(el.className))
			el.className += " " + targetClass
	},

	AddBGShim: function(target) {
		var bgShim = (!window.opera) ? document.createElement("iframe") : document.createElement("div") //Opera 9.24 doesnt seem to support transparent IFRAMEs
		bgShim.className = "iframeshim"
		bgShim.setAttribute("src", location.protocol == "https:" ? this.httpsIFrameSrc : "about:blank")
		bgShim.setAttribute("frameborder", "0")
		target.appendChild(bgShim)
		try {
			bgShim.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
		}
		catch (e) { }
		return bgShim
	},

	PositionShim: function(header, subMenu, scrollX, scrollY) {
		if (header._isBaseLevel) {
			var scrollY = window.pageYOffset ? window.pageYOffset : this.docElement.scrollTop
			var topGap = header._offsets.top - scrollY
			var bottomGap = scrollY + this.docHeight - header._offsets.top - header._dimensions.h
			if (topGap > 0) {
				this.bgShim.topShim.style.left = scrollX + "px"
				this.bgShim.topShim.style.top = scrollY + "px"
				this.bgShim.topShim.style.width = "99%"
				this.bgShim.topShim.style.height = topGap + "px" //distance from top window edge to top of menu item
			}
			if (bottomGap > 0) {
				this.bgShim.bottomShim.style.left = scrollX + "px"
				this.bgShim.bottomShim.style.top = header._offsets.top + header._dimensions.h + "px"
				this.bgShim.bottomShim.style.width = "99%"
				this.bgShim.bottomShim.style.height = bottomGap + "px" //distance from bottom of menu item to bottom window edge
			}
		}
	},

	HideShim: function() {
		this.bgShim.topShim.style.width = this.bgShim.bottomShim.style.width = 0
		this.bgShim.topShim.style.height = this.bgShim.bottomShim.style.height = 0
	},

	GetTarget: function(e) {
		var e = window.event || e
		if (e.target) targ = e.target
		else if (e.srcElement) targ = e.srcElement
		if (targ.nodeType == 3) // defeat Safari bug
			targ = targ.parentNode
		return targ
	},

	BuildMenu: function(mainMenuID, header, subMenu, subMenuPosition, isBaseLevel) {
		header._master = mainMenuID //Indicate which top menu this header is associated with
		header._pos = subMenuPosition //Indicate pos of sub menu this header is associated with
		header._isBaseLevel = isBaseLevel
		if (isBaseLevel) {
			this.AddEvent(header, function(e) {
				WebstoreMenu.HideMenu(WebstoreMenu.subULItems[this._master][parseInt(this._pos)])
			}, "click")
		}
		this.subULItems[mainMenuID][subMenuPosition] = subMenu
		header._dimensions = { w: header.offsetWidth, h: header.offsetHeight, submenuw: subMenu.offsetWidth, submenuh: subMenu.offsetHeight }
		this.GetOffsetOf(header)

		var menuitems = subMenu.getElementsByTagName("a");
		for (var i = 0; i < menuitems.length; i++) {
			this.AddEvent(menuitems[i], function(e) {
				var target = WebstoreMenu.GetTarget(e)
				target.className = "hoverOn";
			}, "mouseover")

			this.AddEvent(menuitems[i], function(e) {
				var target = WebstoreMenu.GetTarget(e)
				target.className = "hoverOff";
			}, "mouseout")
		}

		subMenu.style.left = 0
		subMenu.style.top = 0
		subMenu.style.visibility = "hidden"
		this.AddEvent(header, function(e) { //mouseover event
			if (!WebstoreMenu.IsContained(this, e)) {
				var subMenu = WebstoreMenu.subULItems[this._master][parseInt(this._pos)]
				if (this._isBaseLevel) {
					WebstoreMenu.CSS(this, "selected", "add")
					clearTimeout(WebstoreMenu.hideTimers[this._master][this._pos])
				}
				WebstoreMenu.GetOffsetOf(header)
				var scrollX = window.pageXOffset ? window.pageXOffset : WebstoreMenu.docElement.scrollLeft
				var scrollY = window.pageYOffset ? window.pageYOffset : WebstoreMenu.docElement.scrollTop
				var subMenuRightEdge = this._offsets.left + this._dimensions.submenuw + (this._isBaseLevel ? 0 : this._dimensions.w)
				var subMenuBottomEdge = this._offsets.top + this._dimensions.submenuh
				//Sub menu starting left position
				var menuLeft = (this._isBaseLevel ? this._offsets.left : this._dimensions.w)
				if (subMenuRightEdge - scrollX > WebstoreMenu.docWidth) {
					menuLeft += -this._dimensions.submenuw + (this._isBaseLevel ? this._dimensions.w : -this._dimensions.w)
				}

				subMenu.style.left = menuLeft + "px"

				//Sub menu starting top position
				var menuTop = (this._isBaseLevel ? this._offsets.top + this._dimensions.h : this.offsetTop)
				if (subMenuBottomEdge - scrollY > WebstoreMenu.docHeight) { //no room downwards?
					if (this._dimensions.submenuh < this._offsets.top + 0 - scrollY) { //move up?
						menuTop += -this._dimensions.submenuh + (this._isBaseLevel ? -this._dimensions.h : this._dimensions.h)
					}
					else { //top of window edge
						menuTop += -(this._offsets.top - scrollY) + (this._isBaseLevel ? -this._dimensions.h : 0)
					}
				}

				subMenu.style.top = menuTop + "px"

				if (WebstoreMenu.enableShim && (WebstoreMenu.effects.enableSwipe == false || WebstoreMenu.nonFF)) { //apply bgShim immediately only if animation is turned off, or if on, in non FF2.x browsers
					WebstoreMenu.PositionShim(header, subMenu, scrollX, scrollY)
				}
				else {
					subMenu.FFscrollInfo = { x: scrollX, y: scrollY }
				}

				WebstoreMenu.ShowMenu(header, subMenu)
			}
		}, "mouseover")
		this.AddEvent(header, function(e) { //mouseout event
			var subMenu = WebstoreMenu.subULItems[this._master][parseInt(this._pos)]
			if (this._isBaseLevel) {

				if (!WebstoreMenu.IsContained(this, e) && !WebstoreMenu.IsContained(subMenu, e)) {//hide drop down ul if mouse moves out of menu bar item but not into drop down ul itself
					WebstoreMenu.CSS(this, "selected", "remove")
					WebstoreMenu.HideMenu(subMenu)
				}
			}
			else if (!this._isBaseLevel && !WebstoreMenu.IsContained(this, e)) {
				WebstoreMenu.HideMenu(subMenu)
			}

		}, "mouseout")
	},

	SetOpacity: function(el, value) {
		el.style.opacity = value
		if (typeof el.style.opacity != "string") { //if it's not a string (ie: number instead), it means property not supported
			el.style.MozOpacity = value
			if (el.filters) {
				el.style.filter = "progid:DXImageTransform.Microsoft.alpha(opacity=" + value * 100 + ")"
			}
		}
	},

	ShowMenu: function(header, subMenu) {
		if (this.effects.enableSwipe || this.effects.enableFade) {
			if (this.effects.enableSwipe) {
				var endPoint = (header._isBaseLevel) ? header._dimensions.submenuh : header._dimensions.submenuw
				subMenu.style.width = subMenu.style.height = 0
				subMenu.style.overflow = "hidden"
			}
			if (this.effects.enableFade) {
				this.SetOpacity(subMenu, 0) //set opacity to 0 so menu appears hidden initially
			}
			subMenu._currentAnimateDegree = 0
			subMenu.style.visibility = "visible"
			clearInterval(subMenu._animateTimer)
			subMenu._startTime = new Date().getTime() //get time just before animation is run
			subMenu._animateTimer = setInterval(function() { WebstoreMenu.RevealMenu(header, subMenu, endPoint) }, 10)
		}
		else {
			subMenu.style.visibility = "visible"
		}
	},

	RevealMenu: function(header, subMenu, endPoint) {
		var elapsed = new Date().getTime() - subMenu._startTime //get time animation has run
		if (elapsed < this.effects.duration) {
			if (this.effects.enableSwipe) {
				if (subMenu._currentAnimateDegree == 0) { //reset either width or height of sub menu to "auto" when animation begins
					subMenu.style[header._isBaseLevel ? "width" : "height"] = "auto"
				}
				subMenu.style[header._isBaseLevel ? "height" : "width"] = (subMenu._currentAnimateDegree * endPoint) + "px"
			}
			if (this.effects.enableFade) {
				this.SetOpacity(subMenu, subMenu._currentAnimateDegree)
			}
		}
		else {
			clearInterval(subMenu._animateTimer)
			if (this.effects.enableSwipe) {
				subMenu.style.width = "auto"
				subMenu.style.height = "auto"
				subMenu.style.overflow = "visible"
			}
			if (this.effects.enableFade) {
				this.SetOpacity(subMenu, 1)
				subMenu.style.filter = ""
			}
			if (this.enableShim && subMenu.FFscrollInfo) //if this is FF browser (meaning bgShim hasn't been applied yet
				this.PositionShim(header, subMenu, subMenu.FFscrollInfo.x, subMenu.FFscrollInfo.y)
		}
		subMenu._currentAnimateDegree = (1 - Math.cos((elapsed / this.effects.duration) * Math.PI)) / 2
	},

	HideMenu: function(subMenu) {
		if (typeof subMenu._pos != "undefined") { //if subMenu is outermost UL drop down menu
			this.CSS(this.baseItems[subMenu._master][parseInt(subMenu._pos)], "selected", "remove")
			if (this.enableShim)
				this.HideShim()
		}
		clearInterval(subMenu._animateTimer)
		subMenu.style.left = 0
		subMenu.style.top = "-1000px"
		subMenu.style.visibility = "hidden"
	},

	AddEvent: function(target, referenceFunction, taskType) {
		if (target.addEventListener)
			target.addEventListener(taskType, referenceFunction, false);
		else if (target.attachEvent)
			target.attachEvent('on' + taskType, function() { return referenceFunction.call(target, window.event) });
	},

	Init: function(config) {

		this.enableShim = config.enableShim
		this.hideInterval = config.hideInterval
		this.effects = new Object()
		this.effects.enableSwipe = config.effects.enableSwipe
		this.effects.enableFade = config.effects.enableFade
		this.effects.duration = config.effects.duration
		this.arrowIcons = new Object()
		this.arrowIcons.rightArrow = config.arrowIcons.rightArrow
		this.arrowIcons.showArrowIcons = config.arrowIcons.showArrowIcons
		this.httpsIFrameSrc = config.httpsIFrameSrc;
		var mainMenuID = config.mainMenuID

		this.docElement = (document.compatMode == "CSS1Compat") ? document.documentElement : document.body
		this.baseItemsIndex = -1
		this.ULItemIndex = -1
		this.baseItemIDs.push(mainMenuID)
		this.baseItems[mainMenuID] = [] //declare array on object
		this.subULItems[mainMenuID] = [] //declare array on object
		this.hideTimers[mainMenuID] = [] //declare hide entire menu timer
		if (this.enableShim && !this.shimAdded) {
			this.bgShim = {}
			this.bgShim.topShim = this.AddBGShim(document.body) //create top iframe bgShim obj
			this.bgShim.bottomShim = this.AddBGShim(document.body) //create bottom iframe bgShim obj
			this.shimAdded = true
		}
		var menuBase = document.getElementById(mainMenuID)
		var linkCollection = menuBase.getElementsByTagName("a")
		this.GetWindowSize()
		for (var i = 0; i < linkCollection.length; i++) {
			if (linkCollection[i].getAttribute('subMenu')) {
				this.baseItemsIndex++
				this.ULItemIndex++
				var menuitem = linkCollection[i]
				this.baseItems[mainMenuID][this.baseItemsIndex] = menuitem //store ref to main menu links
				var dropUL = document.getElementById(menuitem.getAttribute('subMenu'))
				document.body.appendChild(dropUL) //move main ULs to end of document
				dropUL.style.zIndex = 2000 //give drop down menus a high z-index
				dropUL._master = mainMenuID  //Indicate which main menu this main UL is associated with
				dropUL._pos = this.baseItemsIndex //Indicate which main menu item this main UL is associated with
				this.AddEvent(dropUL, function() { WebstoreMenu.HideMenu(this) }, "click")
				this.BuildMenu(mainMenuID, menuitem, dropUL, this.ULItemIndex, true) //build top level menu
				dropUL.onmouseover = function() {
					clearTimeout(WebstoreMenu.hideTimers[this._master][this._pos])
				}
				this.AddEvent(dropUL, function(e) { //hide menu if mouse moves out of main UL element into open space
					if (!WebstoreMenu.IsContained(this, e) && !WebstoreMenu.IsContained(WebstoreMenu.baseItems[this._master][parseInt(this._pos)], e)) {
						var dropUL = this
						if (WebstoreMenu.enableShim)
							WebstoreMenu.HideShim()
						WebstoreMenu.hideTimers[this._master][this._pos] = setTimeout(function() {
							WebstoreMenu.HideMenu(dropUL)
						}, WebstoreMenu.hideInterval)
					}
				}, "mouseout")
				var subULItems = dropUL.getElementsByTagName("ul")
				for (var c = 0; c < subULItems.length; c++) {
					this.ULItemIndex++
					var parentLI = subULItems[c].parentNode
					this.BuildMenu(mainMenuID, parentLI, subULItems[c], this.ULItemIndex, false) //build sub level menus
				}
			}
		} //end for loop
		this.AddEvent(window, function() { WebstoreMenu.GetWindowSize(); WebstoreMenu.GetTopItemsDimensions() }, "resize")
	},

	Setup: function(mainMenuID) {
		this.AddEvent(window, function() { WebstoreMenu.Init(mainMenuID) }, "load")
	}

}