/**
 * Menu manager class
 */

menus = {};

menus.createCallback = function(object, method, args) {
	return (function () {
		method.apply(object, args);
	});
};

menus.getOffsetTopR = function(element) {
	var accumulator = 0;
	while (element) {
		accumulator += element.offsetTop;
		element      = element.offsetParent;
	}
	return accumulator;
};

menus.getOffsetLeftR = function(element) {
	var accumulator = 0;
	while (element) {
		accumulator += element.offsetLeft;
		element      = element.offsetParent;
	}
	return accumulator;
};

menus.menus = {};

menus.handlers = {};

menus.getHandlerMethod = function(menuDef, methodName) {
	return menus.handlers[menuDef.type] && menus.handlers[menuDef.type][methodName] ? menus.handlers[menuDef.type][methodName] : menus.handlers.standard[methodName];
};

menus.callHandlerMethod = function(menuDef, methodName) {
	(menus.getHandlerMethod(menuDef, methodName))(menuDef);
};

menus.init = function(menuId, type, activatorId) {
	var menuElement = document.getElementById(menuId);
	if (this.menus[menuId] || !menuElement || !this.handlers[type]) {
		return;
	}
	menuDef = {
		id:      menuId,
		type:    type,
		width:   menuElement.offsetWidth,
		height:  menuElement.offsetHeight,
		visible: false
	};
	menuDef.init                   = this.getHandlerMethod(menuDef, 'init');
	menuDef.show                   = this.getHandlerMethod(menuDef, 'show');
	menuDef.hide                   = this.getHandlerMethod(menuDef, 'hide');
	menuDef.mouseOverTrue          = this.getHandlerMethod(menuDef, 'mouseOverTrue');
	menuDef.mouseOverFalse         = this.getHandlerMethod(menuDef, 'mouseOverFalse');
	menuDef.onMouse                = this.getHandlerMethod(menuDef, 'onMouse');
	menuDef.onMenuMouseOver        = this.getHandlerMethod(menuDef, 'onMenuMouseOver');
	menuDef.onMenuMouseOut         = this.getHandlerMethod(menuDef, 'onMenuMouseOut');
	menuDef.onActivatorMouseOver   = this.getHandlerMethod(menuDef, 'onActivatorMouseOver');
	menuDef.onActivatorMouseOut    = this.getHandlerMethod(menuDef, 'onActivatorMouseOut');
	menuDef.mouseOverTrueCallback  = this.createCallback(menuDef, menuDef.mouseOverTrue,  []);
	menuDef.mouseOverFalseCallback = this.createCallback(menuDef, menuDef.mouseOverFalse, []);
	menuDef.createShowAnimation    = this.getHandlerMethod(menuDef, 'createShowAnimation');
	menuDef.createHideAnimation    = this.getHandlerMethod(menuDef, 'createHideAnimation');
	menuElement.onmouseover        = this.createCallback(menuDef, menuDef.onMenuMouseOver, []);
	menuElement.onmouseout         = this.createCallback(menuDef, menuDef.onMenuMouseOut,  []);
	menuElement.style.display      = 'none';
	menuElement.style.visibility   = 'visible';
	if (activatorId) {
		var activator = document.getElementById(activatorId);
		if (!activator) {
			return;
		}
		menuDef.activatorId = activatorId;
		this.callHandlerMethod(menuDef, 'linkActivator');
	}
	this.menus[menuId] = menuDef;
	menuDef.init();
}

/**
 * Default handlers for types without specific handlers
 */

menus.handlers.standard = {};

menus.handlers.standard.init = function() {};

menus.handlers.standard.linkActivator = function(menuDef) {
	var activator         = document.getElementById(menuDef.activatorId);
	activator.onmouseover = menus.createCallback(menuDef, menuDef.onActivatorMouseOver, []);
	activator.onmouseout  = menus.createCallback(menuDef, menuDef.onActivatorMouseOut,  []);
};

menus.handlers.standard.createShowAnimation = function() {
	return new Animation([new AnimationStep_setV(this.id, true)]);
};

menus.handlers.standard.createHideAnimation = function() {
	return new Animation([new AnimationStep_setV(this.id, false)]);
};

menus.handlers.standard.show = function() {
	if (this.animationRunner) {
		this.animationRunner.stop();
	}
	this.animationRunner = this.createShowAnimation().run();
};

menus.handlers.standard.hide = function() {
	if (this.animationRunner) {
		this.animationRunner.stop();
	}
	this.animationRunner = this.createHideAnimation().run();
};

menus.handlers.standard.onMouse = function() {
	var mouseOver = this.menuMouseOver || this.activatorMouseOver;
	if (mouseOver == this.mouseOver) {
		return;
	}
	this.mouseOver = mouseOver;
	var callback   = mouseOver ? this.mouseOverTrueCallback : this.mouseOverFalseCallback;
	window.setTimeout(callback, 10);
};

menus.handlers.standard.onMenuMouseOver = function() {
	this.menuMouseOver = true;
	this.onMouse();
};

menus.handlers.standard.onMenuMouseOut = function() {
	this.menuMouseOver = false;
	this.onMouse();
};

menus.handlers.standard.onActivatorMouseOver = function() {
	this.activatorMouseOver = true;
	this.onMouse();
};

menus.handlers.standard.onActivatorMouseOut = function() {
	this.activatorMouseOver = false;
	this.onMouse();
};

menus.handlers.standard.mouseOverTrue = function() {
	if (this.menuMouseOver || this.activatorMouseOver) {
		this.show();
	}
};

menus.handlers.standard.mouseOverFalse = function() {
	if (!(this.menuMouseOver || this.activatorMouseOver)) {
		this.hide();
	}
};

/**
 * Specific handlers for type 'main'
 */

menus.handlers.main = {};

menus.handlers.main.init = function() {
	var menuElement                = document.getElementById(this.id); 
	menuElement.w                  = menuDef.width + 10;
	menuElement.maxW               = menuDef.width + 10;
	menuElement.style.width        = menuElement.w + "px"; 
	menuElement.h                  = 0;
	menuElement.maxH               = menuDef.height;
	menuElement.style.clip         = "rect(0px," + menuElement.w + "px,0px,0px)";
};

menus.handlers.main.linkActivator = function(menuDef) {
	var activator                 = document.getElementById(menuDef.activatorId);
	activator.onmouseover         = menus.createCallback(menuDef, menuDef.onActivatorMouseOver, []);
	activator.onmouseout          = menus.createCallback(menuDef, menuDef.onActivatorMouseOut,  []);
	var menuElement               = document.getElementById(menuDef.id);
	menuElement.style.top         = "" + (menus.getOffsetTopR(activator) + activator.offsetHeight) + "px";
	menuElement.style.left        = "" + menus.getOffsetLeftR(activator) + "px";
	var menuElementBridge         = document.getElementById(menuDef.id + "Bridge");
	menuElementBridge.style.width = "" + activator.offsetWidth + "px";
};

menus.handlers.main.createShowAnimation = function() {
	return new Animation([new AnimationStep_array([   
		this.activatorId ? new AnimationStep_addClass(this.activatorId, 'menuOpen') : new AnimationStep_nop(),	
		new AnimationStep_setV(this.id, true),	
		new AnimationStep_setZ(this.id, 99),
		new AnimationStep_animateHeight(this.id, this.height, function (current, target) { return current + 10; })
	])]);
};

menus.handlers.main.createHideAnimation = function() {
	return new Animation([
		new AnimationStep_array([
			new AnimationStep_setZ(this.id, 1),
			new AnimationStep_animateHeight(this.id, 0, function (current, target) { return current - 20; })
		]),
		new AnimationStep_array([
			this.activatorId ? new AnimationStep_removeClass(this.activatorId, 'menuOpen') : new AnimationStep_nop(),
			new AnimationStep_setV(this.id, false)
		])
	]);
};

