//======================================================================================
//
// OPTIONS
//
//======================================================================================

var rmb = {
	options: {
		tweenDuration: 400	
	}
};
rmb.squareOptions = {
	tweenDuration: rmb.options.tweenDuration
};
rmb.lineOptions = {
	tweenDuration: rmb.options.tweenDuration,
	imgsrc: './img/nav_vnav__line_both.png',
	width: 475,
	height: 1,
	top: 13,
	left: -60
}; 
rmb.submenuOptions = {
	tweenDuration: rmb.options.tweenDuration,
	offTop: -600,
	tolerance: 6,
	hideDelay: 300,
	imgsrc: 'img/quader_submenu.png',
	width: 405,
	height: 405,
	itemOpacity: 0.7,
	itemHeight: 13,
	lineAnimDuration: rmb.options.tweenDuration
};



//======================================================================================
//
// BASE CLASSES
//
//======================================================================================


//-------------------------------------
// NAV
//-------------------------------------

rmb.NavMenu = Class.extend({
	 
	init: function(element, itemConstructor){
		var self = this; 
		this.navmenu = this;
		this.element = $(element);
		this.items = [];
		this.itemConstructor = itemConstructor;
		$(element).find('a:not(.title)').each(function() {
			self.createNavItem(this);
		});
	},
	
	createNavItem: function(element) { 
		var item = new this.itemConstructor(element, this);
		this.items.push(item);
	},
	
	onItemRollOver: function(item) { 
		var i=0,items=this.items,t=items.length;
		while (i<t) { 
			if (items[i] != item) {
				items[i].hideAnimation();
			}
			i++;
		}
		item.showAnimation();
	},
	
	onItemRollOut: function(item) {
		item.hideAnimation();
	}
	
});



//-------------------------------------
// NAV ITEM
//-------------------------------------

rmb.NavItem = Class.extend({

	init: function(element, menu){
		this.element = $(element); 	
		element.navitem = this;
		this.menu = menu;
		this.locked = false;
		this.hasSub = this.element.closest('li').find('ul.l3').length === 1;		
		this.element.addClass('vnav-item '+(this.hasSub?'has-submenu':'no-submenu'));  
		if (this.hasSub) {
			this.submenuElement = this.element.closest('li').find('ul.l3');
		}
		
		this.inSub = this.element.closest('.l3').length === 1;
		this.element.replacetext();
		this.element.find('.replacement-image').bind('mouseenter.navi', $.proxy(this.onRollOver, this));
		this.element.find('.replacement-image').bind('mouseleave.navi', $.proxy(this.onRollOut, this));	
		if (site.ie7 && this.inSub) {  
			this.element.find('img').click(function() { 
				$(this).closest('a').click();
			})
		}
	}, 

	
	lock: function() {
		this.locked = true;
	},
	unlock: function() { 
		this.locked = false;
	},
	
	onRollOver: function() { 
		this.menu.onItemRollOver(this);
	},
	onRollOut: function() {
		this.menu.onItemRollOut(this);
	},
	
	showAnimation: function() { 
		// implement in derived class!
	},
	hideAnimation: function() { 
		// implement in derived class!
	}
});




//-------------------------------------
// SubMenu
//-------------------------------------

rmb.VSubMenu = Class.extend({
	init: function(options) {
		this.options = options;
		
		this.element = $('<div>')
		.attr({
			'class': 'submenu-rect'
		})
		.css({  
			background: 'transparent url('+options.imgsrc+') top left no-repeat',
			position: 'absolute',
			/*zIndex: 1,*/
			width: options.width,
			height: options.height,
			left: -options.width+1,
			top: options.offTop	
		}) 
		.append('<div class="inner" style="position:relative">')
		.bind('mouseenter', $.proxy(this.onMouseEnter, this));
		$(document).bind('mousedown.rmbSubMenu', $.proxy(this.onMouseDown, this));
	},
	
	/**
	 * Clears the <code>submenuHideTimeout</code> when the mouse moves into the submenu element.
	 * We use a timeout to hide the submenu with a little delay, so it doesn't jump back and forth when rolling over
	 * menu items. When you move the mouse quickly out and back into the submenu, the menu would normally disappear after the delay,
	 * so we clear the timeout here. 
	 */
	onMouseEnter: function() {
		if (this.submenuHideTimeout) {
			window.clearTimeout(this.submenuHideTimeout);
		}
	},
	
	//--------------------------------------------------------------------------------------- 
	// SHOW SUBMENU 
	//---------------------------------------------------------------------------------------
	
	/**
	 * Shows the submenu for a NavItem.
	 * Animates the position and attaches the item's l3 menu
	 * @param item {NavItem}
	 */
	show: function(item) {
		this.currentSubParent = item;		
		this.show__animatePosition();
		this.show__appendList();		
		this.bindMouse();
	}, 
	
	/**
	 * Animates the position of the submenu container.
	 * Called in show()
	 */
	show__animatePosition: function() {
		if (this.submenuHideTimeout) {
			window.clearTimeout(this.submenuHideTimeout);
		}		
		var self = this,
		item = this.currentSubParent,
		y = item.element.position().top - (this.element.height() - item.element.height())/2, 
		pos = this.element.position();
		if (pos && pos.top && (y !== pos.top) ) { 
			this.element
			.stop()
			.animate({
				top: y 
			}, this.options.tweenDuration, function() {
				self.onShowComplete();
			});
		}
		
	},
	onShowComplete: function() {
		var self = this;
		this.element.find('a').each(function() {
			if ($(this).attr('data-path') == '/'+hash()) {
				self.currentSubParent.moveLeftLineTo(this, rmb.submenuOptions.lineAnimDuration/2);
			}
		}); 
	},
	/**
	 * Appends the actual submenu links for the current NavItem.
	 * Creates a clone of the ul.l3 list of the currentSubParent.
	 * Called in show()
	 */
	show__appendList: function() {
		this.element.find('.inner').empty();
		var self = this,
		item = this.currentSubParent,
		ul = item.submenuElement.clone() 
			.css({
				display:'block',
				position: 'absolute'
			})
			.attr('data-path', item.element.attr('data-path'))
			.appendTo(this.element.find('.inner')); 
		

		ul.find('li').each(function() {
			var img = $(this).find('.replacement-image'),
			w = img.width(),
			h = img.height()
			css = {
				width: w,
				height: h				
			},
			itemOpacity = rmb.submenuOptions.itemOpacity;
			
			// apply basic css
			img.css({right: 0});			
			$(this).css(css);			
			$(this).find('.text-image')
			.css(css)
			.animate({opacity:itemOpacity}, 0);
			
			
			$(this).find('a')
			.css(css) 
			.hover(
				function() { 
					$(this).find('.text-image').stop().animate({opacity:1},'fast');
					self.currentSubParent.moveLeftLineTo(this); 
				},
				function() {
					$(this).find('.text-image').stop().animate({opacity:itemOpacity},'fast');
				}
			);
		});
		
		ul.find('li, a, .text-image').width( ul.width() ); 
		ul.css({
			top: (this.element.height()/2) - ul.find('li').height() + 3,
			right: 10
		})
	},
	 
	//--------------------------------------------------------------------------------------- 
	// HIDE SUBMENU 
	//---------------------------------------------------------------------------------------
	
	
	hide: function(instant) {
		if (this.submenuHideTimeout) {
			window.clearTimeout(this.submenuHideTimeout);
		}
		if (instant) {
			this.hide_doHide();
		}
		else {
			this.submenuHideTimeout = window.setTimeout($.proxy(this.hide_doHide, this), this.options.hideDelay)
		}
	},
	hide_doHide: function() {
		var y = this.options.offTop,
		pos = this.element.position();
		if (pos && pos.top && (y !== pos.top) ) { 
			this.element
			.stop()
			.animate({
				top: y 
			}, this.options.tweenDuration, function() {
				// tween complete!
			});
		}
		
		this.unbindMouse();
		
		if (this.currentSubParent) {
			this.currentSubParent.hideAnimation();
		}
	},
	
	/**
	 * Binds mouse events to observe when the submenu needs to be hidden again.
	 */
	bindMouse: function() { 
		$(document).bind('mousemove.rmbSubMenu', $.proxy(this.onMouseMove, this));
	},
	
	
	/**
	 * Hides submenu when a click occurs outside of it.
	 */
	onMouseDown: function(e) { 
		if (this.element[0] != e.target && !$(e.target).isChildOf(this.element)) {
			this.hide(true); 
		}
	},
	
	/**
	 * Observes mouse movements and determines whether the <code>hide()</code> method needs to be called.
	 */
	onMouseMove: function(e) {
		var o = this.options,
		rect = this.element,
		link = this.currentSubParent.element,
		offset = link.offset(),
	 	inRect = $(e.target).hasClass('submenu-rect') || $(e.target).parents('.submenu-rect').length > 0,
	 	inLink = ($(e.target).isChildOf(link) && e.pageX < offset.left + $(link).width())
	 		|| 
	 		/*
	 		 * Nach links hin checken wir für besseres user-handling, ob die Maus sich in einem Dreieck befindet (mit der hohen Seite links und der Spitze rechts).
	 		 * Die variable spread bestimmt dabei wie hoch das Dreieck links ausfällt, wie tolerant also die y-position der Maus behandelt wird.
	 		 */
	 		function() {
	 			var leftDist = offset.left - e.pageX;
	 			var leftPad = 60;
	 			var spread = o.tolerance;
	 			var extraH = $(link).height()*spread*leftDist/leftPad;				 			
	 			return (e.pageX <= offset.left && e.pageX >= rect.offset().left && e.pageY >= offset.top-extraH && e.pageY <= offset.top+$(link).height()+extraH);
	 		}(),
	 	offRight = e.pageX > offset.left + $(link).width(),
	 	offLeft = e.pageX < this.element.offset().left; 
	 	
	 	if ((!inRect && !inLink) || offRight || offLeft ) {
	 		this.hide(offRight || offLeft);
		}
	},
	/**
	 * Clears mouse bindings for hiding the submenu once <code>hide()</code> has been called.
	 */
	unbindMouse: function() { 
		$(document).unbind('mousemove.rmbSubMenu');
		//$(document).unbind('mousedown.rmbSubMenu');
	}
});


//-------------------------------------
// ANIMATED ASSET
//-------------------------------------

/**
 * Base class for an animated element. Creates a <code>span</code> element which is accessible via the <code>element</code> property.
 * Provides <code>show()</code> and <code>hide()</code> functions that animate the element's opacity.
 * @see show()
 * @see hide()
 */
rmb.AnimatedAsset = Class.extend({
	
	init: function(options) {
		this.options = options; 
		this.element = $('<span>');
		this.state = 'default';
	}, 
	 
	
	show: function() { 
		switch (this.state) {
			case 'showProgress':
			case 'showComplete':
				return;
		}
		this.state = 'showProgress';
		this.showAnimation();
	},
	hide: function() { 
		switch (this.state) {
			case 'hideProgress':
			case 'default':
				return;
		}
		this.state = 'hideProgress';
		this.hideAnimation();
	},
	
	
	showAnimation: function() {
		var self = this;
		this.element
		.stop()
		.animate({opacity: 1}, this.options.tweenDuration, function() {
			self.showAnimationComplete();
		});
	},
	showAnimationComplete: function() {
		this.state = 'showComplete';
	},
	
	 
	
	hideAnimation: function() {
		var self = this;
		this.element
		.stop()
		.animate({opacity: 0}, this.options.tweenDuration,  function() {
			self.hideAnimationComplete();
		});
	},
	hideAnimationComplete: function() {
		this.state = 'default';
	}
	
});


//======================================================================================
//
// DERIVED CLASSES
//
//======================================================================================


//-------------------------------------
// HORIZONTAL NAV
//-------------------------------------
rmb.HNavMenu = rmb.NavMenu.extend({
	
	init: function(element){
		this._super(element, rmb.HNavItem); 
	}	 

});

//-------------------------------------
// VERTICAL NAV
//-------------------------------------

rmb.VNavMenu = rmb.NavMenu.extend({
	
	init: function(element){
		this._super(element, rmb.VNavItem);
		
		this.submenu = new rmb.VSubMenu(rmb.submenuOptions); 
		this.submenu.element.prependTo( this.element )
	},
	
	onItemRollOver: function(item) {
		this._super(item);
		if (item.hasSub) {
			this.submenu.show(item);
		}
		else {
			this.submenu.hide(true);
		}
	},
	
	/**
	 * Override the default rollout: Only activate the hide-animation if there is no submenu, otherwise the submenu will take care of it
	 */
	onItemRollOut: function(item) {
		var self = this;
		if (!item.hasSub) {
			item.hideAnimation();
		}	
	}

});
 
//-------------------------------------
// HORIZONTAL NAV ITEM
//-------------------------------------

rmb.HNavItem = rmb.NavItem.extend({
	init: function(element, menu){
		this._super( element, menu );  
	}
});

//-------------------------------------
// VERTICAL NAV ITEM
//-------------------------------------

rmb.VNavItem = rmb.NavItem.extend({
	
	init: function(element, menu){
		this._super( element, menu );  	
		if (!this.inSub) {
			this.createAnimations();
		}
	},
	 
	createAnimations: function() {
		// create square icon
		this.square = new rmb.AnimatedSquare(rmb.squareOptions);
		this.element.append(this.square.element);
		// create line on right side
		this.lineRight = new rmb.AnimatedLineRight(rmb.lineOptions);
		this.element.append(this.lineRight.element);		
		// create line on left side
		this.lineLeft = null;
		// but only if this item has a submenu
		if (this.hasSub) {
			this.lineLeft = new rmb.AnimatedLineLeft(rmb.lineOptions);
			this.element.append(this.lineLeft.element);
			this.lineLeft.element.css({ 
				left: rmb.lineOptions.left - rmb.lineOptions.width/2
			});
		}
	},
	
	lock: function() {
		this._super();
		var self = this;
		setTimeout(function(){
			self.square.show();
			self.lineRight.show();
			if (self.lineLeft) {
				self.lineLeft.hide();
			}
		}, 500);
	},
	
	unlock: function() {
		this._super();
		if (this.square) { // initial call occurs when elements are not created yet
			this.square.hide();
			this.lineRight.hide();
			if (this.lineLeft) {
				this.lineLeft.hide();
			}
		}
	},
	
	showAnimation: function() {  
		if (this.inSub) {
			return;
		}

		if (this.lineLeft) {
			this.lineLeft.show();
		}
		
		if (this.locked) {
			return;
		}
		this.square.show();
		this.lineRight.show(); 
	},
	
	hideAnimation: function() {
		if (this.inSub) {
			return;
		}

		if (this.lineLeft) {
			this.lineLeft.hide();
		}
		
		if (this.locked) {
			return;
		}
		this.square.hide(); 
		this.lineRight.hide();
	},
	
	moveLeftLineTo: function(link, duration) { 
		if (this.lineLeft) {  
			var offset = 3;
			if (site.ie7) {
				offset = 7;
			}
			this.lineLeft.element.stop().animate({
				top: $(link).offset().top - $(link).closest('ul').offset().top + rmb.submenuOptions.itemHeight - offset
			}, typeof duration === undefined ? rmb.submenuOptions.lineAnimDuration : duration)
		}
	}
});


//-------------------------------------
// ANIMATIONS
//-------------------------------------
 

/**
 * Overrides the default show() and hide() functions
 */
rmb.AnimatedLine = rmb.AnimatedAsset.extend({

	init: function(options) {
		 
		this._super(options);
		var o = options;
		this.element.css({
			display: 'block', 
			position: 'relative',
			zIndex: 2222,
			overflow: 'hidden',
			top: o.top,
			left: o.left - o.width/2,
			width: o.width, 
			height: o.height
		});
		
		this.innerElement = $('<span>').appendTo(this.element);
		this.innerElement.css({
			display: 'block',
			position: 'absolute', 
			overflow: 'hidden',
			zIndex: 2,
			fontSize: 0,
			lineHeight: 0,
			width: o.width,
			height: o.height
		})
		
		this.image = $('<img>') 
		.css({
			visibility: 'hidden',
			display: 'block',
			margin: '0 auto'
		})
		.bind('load', $.proxy(this.imageLoaded, this))
		.appendTo(this.innerElement);		
		
		this.image.attr('src', o.imgsrc)
		
	},
	imageLoaded: function() {
		this.image.animate({width:0,height:this.options.height}, 0)
		.css({
			visibility: 'visible'
		});
	},
	showAnimation: function() { 
		var o = this.options,
		self = this;
		this.element.css('top', o.top);
		this.image
		.stop()
		.animate({width:o.width, height:o.height}, o.tweenDuration,  function() {
			self.showAnimationComplete();
		}); 
	},
	hideAnimation: function() {
		var o = this.options,
		self = this;
		
		this.image
		.stop()
		.animate({width:0, height:o.height}, o.tweenDuration,  function() {
			self.hideAnimationComplete();
		}); 
	}
});

rmb.AnimatedLineRight = rmb.AnimatedLine.extend({
	init: function(options) {
		this._super(options);
		var o = this.options,
		w = o.width/2;		
		this.element.css({
			width: w,
			left: o.left
		});
		this.innerElement.css({
			left: -w
		});
	}
});

rmb.AnimatedLineLeft = rmb.AnimatedLine.extend({
	init: function(options) {
		this._super(options);

		var o = this.options,
		w = o.width/2;				
		this.element.css({
			width: w,
			left: o.left
		});
		this.innerElement.css({
			left: 1
		});
	}
});



/**
 * The square icon element for each vnav item.
 * Uses the default <code>show()</code> and <code>hide()</code> functions.
 */
rmb.AnimatedSquare = rmb.AnimatedAsset.extend({
	/**
	 * Adds the class 'square-icon' and appends the appropriate image.
	 */
	init: function(options) {
		this._super(options);
		this.element
		.addClass('square-icon')
		.css('opacity', 0)
		.append($('<img src="./img/nav_vnav__hoversquare.png">'));
	}
});


