var domReady = false;
window.addEvent('domready', function(){
	domReady = true;
	if(Browser.Engine.trident && Browser.Engine.version <= 5){ //Only run in IE6-7, adds hover compatibility on list elements
		$$('li').each(function(element){
			element.addEvent('mouseover', function() {
				$clear(this.removeClassTimer);
				this.addClassTimer = this.addClass.delay(50, this, 'sfhover'); //Delay adding to avoid toe stepping
			});
			element.addEvent('mouseout', function() {
				$clear(this.addClassTimer);
				this.removeClassTimer = this.removeClass.delay(50, this, 'sfhover'); //Delay closing to remove flicker
			});
		});
	}
});

//Gets the width of text based on a supplied CSS class.
function maxTextWidth(textOrArray, textClass, dropElements){
	if(!$chk(textClass)){ var textClass = 'GetWidth';}
	if(!$chk(dropElements)){ var dropElements = ['ul'];}
	var width = 0;
	var spanElement = new Element('span', {'class':textClass,'styles':{'display':'inline','float':'none','margin':'0','padding':'0','border':'0'}});
	spanElement.setStyle('whiteSpace', 'nowrap');
	$(document.body).adopt(spanElement);
	if(typeof(textOrArray)=='string'){
		spanElement.set('html', textOrArray);
		dropElements.each(function(elSelector){
			spanElement.getChildren(elSelector).each(function(tmpDrop){
				tmpDrop.dispose();
			}, this);
		}, this);
		width = spanElement.getSize().x;
	}else{
		$each(textOrArray, function(currentText){
			var tmpText = currentText;
			if(typeof(textOrArray)!='string'){tmpText = currentText.get('html');}
			spanElement.set('html', tmpText);
			dropElements.each(function(elSelector){
				spanElement.getChildren(elSelector).each(function(tmpDrop){
					tmpDrop.dispose();
				}, this);
			}, this);
			var tmpWidth = spanElement.getSize().x;
			if(width < tmpWidth){width=tmpWidth;}
		});
	}
	spanElement.dispose();
	return width+2; //2 pixels to allow for rounding issues.
}

function getInsideExtraWidth(element){
	return getInsideExtraLeft(element)+getInsideExtraRight(element);
}

function getOutsideExtraWidth(element){
	return parseInt(element.getStyle('margin-right'))+parseInt(element.getStyle('margin-left'));
}

function getInsideExtraLeft(element){
	return parseInt(element.getStyle('padding-left'))+parseInt(element.getStyle('border-left'));
}

function getInsideExtraRight(element){
	return parseInt(element.getStyle('padding-right'))+parseInt(element.getStyle('border-right'));
}

var MooMenuSizer = new Class({
	Implements: [Options],
	options: {
		auto:true,
		makeVertical:false,	        //Means we have a vertical root level instead of horizontal (assumes root UL has a width set)		
		applyToRootUL:'full',	    //ROOT: True: apply width of contained LIs to UL. 'full': full li width. False: no resize
		applyToRoot:'exact',        //apply width to root level LIs true, false, 'exact' (exact means size exactly to each li)
		centerRoot:false,			//Attempt to center the UL within its parent
		applyToUL:true,	            //apply width of contained LIs to UL. A number supplied will indicate false until that depth.
		exactLI:true,				//if true this resizes to the exact content size for horizontal dropdowns only.
		alignToRoot:false,	        //Makes horizontal dropdown elements align to the left right under (or above) the root ul
		dropUp:false,	            //Dropping UP!?  What madness?!
		minWidth:20,	            //widths applied will never be lower than this number
		maxWidth:false,	            //-1 or false means no max, a positive integer will limit the max width
		textClass:['GetWidth'],	    //This is a list of classes used to calculate text width for each dropdown level.
		selectors:['.navigation'],  //Should always point to the root ul itself.
		parentContainer: 'ul',
		nodeContainer: 'li',
		textContainer: 'a'
	},
	initialize: function(options){
		this.width = [];
		this.setOptions(options);
		if(this.options.applyToRootUL === true){this.options.makeVertical = true;}
		if(this.options.auto){
			this.checkFix();
		}
	},
	checkFix: function(){
		if(!domReady){
			this.checkFix.delay(100, this);
		}else{
			this.applyFix();
		}
	},
	applyFix: function(){
		this.options.selectors.each(function(SelectorString){
			$$(SelectorString).each(function(element){
				this.applyFixToNodes(element, 0, 0);
				if(this.options.applyToRootUL == 'full'){
					this.setFullULWidth(element);
				}
				if(this.options.centerRoot){
					this.centerUL(element);
				}
			}, this);
		}, this);
	},
	applyFixToNodes: function(element, depth, dropFrom){
		lis = element.getChildren(this.options.nodeContainer);
		this.setTextClass(depth);
		var width = maxTextWidth(lis, this.textClass, this.options.dropForCalculation);
		if(this.options.maxWidth !== false && this.options.maxWidth > 0 && width > this.options.maxWidth){
			width = this.options.maxWidth;
		}else if(width < this.options.minWidth){
			width = this.options.minWidth;
		}
		this.setPositionOfUL(element, depth, dropFrom, width+(getInsideExtraWidth(lis[0])+getOutsideExtraWidth(lis[0])));
		this.recursiveResizeListElements(lis, depth, width, getInsideExtraWidth(lis[0].getElement('a'))+getOutsideExtraWidth(lis[0].getElement('a')));
		if(this.options.dropUp){ //doing this requires the elements be the final sizes which is why we do it last.
			this.setDropUpPositions(element, depth, dropFrom);
		}
	},
	setPositionOfUL: function(element, depth, dropFrom, resizeWidth){
		if(depth > 0){
			if((this.options.applyToUL === true) || (this.options.applyToUL!==false && depth>=(this.options.applyToUL+1))){
				element.setStyle('width', (resizeWidth)+'px');
			}
			
			var link = dropFrom.getElement(this.options.textContainer);
			if(this.options.applyToUL===true || (this.options.applyToUL!==false && depth>=(this.options.applyToUL+1))){
				if((depth>1 || this.options.makeVertical)){
					if(this.options.applyToUL===true || (depth)!==(this.options.applyToUL+1)){
						element.setStyle('margin-left', link.getPosition(dropFrom).x+link.getSize().x+parseInt(link.getStyle('margin-right')));
						if(!this.options.dropUp){
							element.setStyle('margin-top', (link.getPosition(dropFrom).y+link.getSize().y+parseInt(link.getStyle('margin-bottom'))+parseInt(dropFrom.getStyle('margin-bottom')))*-1);
						}
					}else{
						element.setStyle('margin-left', (dropFrom.getPosition(link).x+parseInt(link.getStyle('margin-right'))));
						if(!this.options.dropUp){
							element.setStyle('margin-top', (dropFrom.getPosition(link).y+parseInt(link.getStyle('margin-bottom')))*-1);
						}
					}
				}else{
					element.setStyle('margin-left', (dropFrom.getPosition(link).x+parseInt(link.getStyle('margin-right'))));
					if(!this.options.dropUp){
						element.setStyle('margin-top', (dropFrom.getPosition(link).y+parseInt(link.getStyle('margin-bottom')))*-1);
					}
				}
			}else if(this.options.applyToUL===false || (this.options.applyToUL!==true && depth<(this.options.applyToUL+1))){
				if(this.options.alignToRoot === true){
					element.setStyle('margin-left', (dropFrom.getPosition(dropFrom.getParent()).x+getInsideExtraLeft(dropFrom))*-1);
				}else{
					element.setStyle('margin-left', (dropFrom.getPosition(link).x+parseInt(link.getStyle('margin-right'))));
				}
				if(!this.options.dropUp){
					element.setStyle('margin-top', (dropFrom.getPosition(link).y+parseInt(link.getStyle('margin-bottom')))*-1);
				}
			}
			
		}else if(this.options.applyToRootUL === true){
			element.setStyle('width', (resizeWidth)+'px');
		}
	},
	setDropUpPositions: function(element, depth, dropFrom){
		if(depth > 0){
			var link = dropFrom.getElement(this.options.textContainer);
			if(this.options.applyToUL===true || (this.options.applyToUL!==false && depth>=(this.options.applyToUL+1))){
				if((depth>1 || this.options.makeVertical)){
					if(this.options.applyToUL===true || (depth)!==(this.options.applyToUL+1)){
						if(this.options.dropUp){
							element.setStyle('margin-top', (dropFrom.getPosition(link).y+element.getSize().y+parseInt(link.getStyle('margin-top')))*-1);
						}
					}else{
						if(this.options.dropUp){
							element.setStyle('margin-top', (dropFrom.getPosition(link).y+element.getSize().y+dropFrom.getSize().y+parseInt(link.getStyle('margin-top'))-1)*-1);
						}
					}
				}else{
					if(this.options.dropUp){
						element.setStyle('margin-top', (link.getPosition(dropFrom).y+element.getSize().y+link.getSize().y+parseInt(link.getStyle('margin-top'))-1)*-1);
					}
				}
			}else if(this.options.applyToUL===false || (this.options.applyToUL!==true && depth<(this.options.applyToUL+1))){
				if(this.options.dropUp){
					element.setStyle('margin-top', (dropFrom.getPosition(link).y+element.getSize().y+dropFrom.getSize().y+parseInt(link.getStyle('margin-top'))-1)*-1);
				}
			}
		}
	},
	recursiveResizeListElements: function(lis, depth, width, paddingWidth){
		lis.each(function(liElement){
			if(depth>0||this.options.applyToRoot===true){
				if(this.options.exactLI && (this.options.applyToUL===false || (this.options.applyToUL!==true && depth<(this.options.applyToUL+1)))){
					this.setTextClass(depth);
					liElement.setStyle('width', (maxTextWidth(liElement.get('html'), this.textClass, this.options.dropForCalculation)+paddingWidth));
				}else{
					liElement.setStyle('width', (width+paddingWidth)+'px');
				}
			}else if(depth===0&&this.options.applyToRoot==='exact'){
				this.setTextClass(depth);
				liElement.setStyle('width', maxTextWidth(liElement.get('html'), this.textClass, this.options.dropForCalculation)+paddingWidth);
			}
			var ul = liElement.getElement(this.options.parentContainer);
			if($defined(ul)){
				this.applyFixToNodes(ul, depth+1, liElement);
			}
		}, this);
	},
	setFullULWidth: function(element){
		lis = element.getChildren(this.options.nodeContainer);
		var totalWidth = 0;
		lis.each(function(liElement){
			totalWidth += liElement.getSize().x + getOutsideExtraWidth(liElement);
		}, this);
		totalWidth+=getInsideExtraWidth(element);
		element.setStyle('width', (totalWidth)+'px');
	},
	centerUL: function(element){
		var side = parseInt((element.getSize().x - parseInt(element.getParent().getSize().x))/2.0);
		element.setStyle('margin-left', side);
		element.setStyle('margin-right', side);
	},
	setTextClass: function(depth){
		if($defined(this.options.textClass[depth])){
			this.textClass = this.options.textClass[depth];
		}else{
			this.textClass = this.options.textClass[this.options.textClass.length];
		}
	}
});