/*
 *         developed by Matteo Bicocchi on JQuery
 *        © 2002-2009 Open Lab srl, Matteo Bicocchi
 *			    www.open-lab.com - info@open-lab.com
 *       	version 2.2
 *       	tested on: 	Explorer and FireFox for PC
 *                  		FireFox and Safari for Mac Os X
 *                  		FireFox for Linux
 *         MIT (MIT-LICENSE.txt) licenses.
 */
//document.oncontextmenu = function() { return false };
// to get the element that is fireing a contextMenu event you have $.mbMenu.lastContextMenuEl that returns an object.

(function($) {
	$.mbMenu = {
		actualMenuOpener:false,
		options: {
			template:"yourMenuVoiceTemplate",// the url that returns the menu voices via ajax. the data passed in the request is the "menu" attribute value as "menuId"
			additionalData:"",
			menuSelector:".menuContainer",
			menuWidth:150,
			openOnRight:false,
			iconPath:"ico/",
			hasImages:true,
			fadeInTime:20,
			fadeOutTime:200,
			menuTop:0,
			menuLeft:0,
			submenuTop:0,
			submenuLeft:4,
			opacity:1,
			shadow:false,
			shadowColor:"black",
			shadowOpacity:.2,
			openOnClick:true,
			closeOnMouseOut:false,
			closeAfter:500,
			minZindex:"auto", // or number
			hoverIntent:0, //if you use jquery.hoverIntent.js set this to time in milliseconds; 0= false;
			submenuHoverIntent:0, //if you use jquery.hoverIntent.js set this to time in milliseconds; 0= false;
			onContextualMenu:function(){} //it pass o (the menu you clicked on) and e (the event)
		},
		buildMenu : function (options){
			return this.each (function ()
			{
				var thisMenu =this;
				thisMenu.id = !this.id ? "menu_"+Math.floor (Math.random () * 1000): this.id;
				this.options = {};
				$.extend (this.options, $.mbMenu.options);
				$.extend (this.options, options);

				$(".menu").hide();
				thisMenu.clicked = false;
				thisMenu.rootMenu=false;
				thisMenu.clearClicked=false;
				thisMenu.actualOpenedMenu=false;
				thisMenu.menuvoice=false;
				var root=$(this);
				var openOnClick=this.options.openOnClick;
				var closeOnMouseOut=this.options.closeOnMouseOut;

				//build roots
				$(root).each(function(){

					/*
					 *using metadata plugin you can add attribut writing them inside the class attr with a JSON sintax
					 * for ex: class="rootVoice {menu:'menu_2'}"
					 */
					if ($.metadata){
						$.metadata.setType("class");
						thisMenu.menuvoice=$(this).find(".rootVoice");
						$(thisMenu.menuvoice).each(function(){
							if ($(this).metadata().menu) $(this).attr("menu",$(this).metadata().menu);
						})
					}

					thisMenu.menuvoice=$(this).find("[menu]");

					$(thisMenu.menuvoice).each(function(){
						$(this).addClass("rootVoice");
						$(this).attr("nowrap","nowrap");
					});
					if(openOnClick){
						$(thisMenu.menuvoice).bind("click",function(){
							if (!$(this).attr("isOpen")){
								$(this).buildMbMenu(thisMenu,$(this).attr("menu"));
								$(this).attr("isOpen","true");
							}else{
								$(this).removeMbMenu(thisMenu,true);
								$(this).addClass("selected");
							}

							//empty
							if($(this).attr("menu")=="empty"){
								if(thisMenu.actualOpenedMenu){
									$(thisMenu.actualOpenedMenu).removeClass("selected");
									thisMenu.clicked=true;
									$(this).removeAttr("isOpen");
									clearTimeout(thisMenu.clearClicked);
								}
								$(this).removeMbMenu(thisMenu);
							}
							return false;
						});
					}
					var mouseOver=$.browser.msie?"mouseenter":"mouseover";
					var mouseOut=$.browser.msie?"mouseleave":"mouseout";
					if (this.options.hoverIntent==0){
						$(thisMenu.menuvoice).bind(mouseOver,function(){
							if (closeOnMouseOut) clearTimeout($.mbMenu.deleteOnMouseOut);
							if (!openOnClick) $(thisMenu).find(".selected").removeClass("selected");
							if(thisMenu.actualOpenedMenu){ $(thisMenu.actualOpenedMenu).removeClass("selected");}
							$(this).addClass("selected");
							if((thisMenu.clicked || !openOnClick) && !$(this).attr("isOpen")){
								clearTimeout(thisMenu.clearClicked);
								$(this).buildMbMenu(thisMenu,$(this).attr("menu"));
								if ($(this).attr("menu")=="empty"){
									$(this).removeMbMenu(thisMenu);
									$(this).removeAttr("isOpen");
								}
							}
						})
						$(thisMenu.menuvoice).bind(mouseOut,function(){
							if (closeOnMouseOut)
								$.mbMenu.deleteOnMouseOut= setTimeout(function(){$(this).removeMbMenu(thisMenu,true)},$(root)[0].options.closeAfter);
							if(!thisMenu.clicked)
								$(this).removeClass("selected");
							$(document).bind("click",function(){
								$(this).removeMbMenu(thisMenu,true);
							})
						})
					}else{ // HOVERHINTENT

//						$(thisMenu.menuvoice).bind(mouseOver,function(){
//							$(this).addClass("selected");
//						})
//						$(thisMenu.menuvoice).bind(mouseOut,function(){
//							$(this).removeClass("selected");
//						})

						$(thisMenu.menuvoice).hoverIntent({
							over:function(){
								if (closeOnMouseOut) clearTimeout($.mbMenu.deleteOnMouseOut);
								if (!openOnClick) $(thisMenu).find(".selected").removeClass("selected");
								if(thisMenu.actualOpenedMenu){ $(thisMenu.actualOpenedMenu).removeClass("selected");}
								$(this).addClass("selected");
								if((thisMenu.clicked || !openOnClick)  && !$(this).attr("isOpen")){
									clearTimeout(thisMenu.clearClicked);
									$(this).buildMbMenu(thisMenu,$(this).attr("menu"));
									if ($(this).attr("menu")=="empty"){
										$(this).removeMbMenu(thisMenu);
										$(this).removeAttr("isOpen");
									}
								}
							},
							sensitivity: 30,
							interval: this.options.hoverIntent,
							timeout: 0,
							out:function(){
								if (closeOnMouseOut)
									$.mbMenu.deleteOnMouseOut= setTimeout(function(){$(this).removeMbMenu(thisMenu,true)},$(root)[0].options.closeAfter);
								if(!thisMenu.clicked)
									$(this).removeClass("selected");
								$(document).bind("click",function(){
									$(this).removeMbMenu(thisMenu,true);
								})
							}
						})
					}

				})
			})
		},
		buildContextualMenu :  function (options){
			return this.each (function ()
			{
				var thisMenu = this;
				thisMenu.options = {};
				$.extend (thisMenu.options, $.mbMenu.options);
				$.extend (thisMenu.options, options);
				$(".menu").hide();
				thisMenu.clicked = false;
				thisMenu.rootMenu=false;
				thisMenu.clearClicked=false;
				thisMenu.actualOpenedMenu=false;
				thisMenu.menuvoice=false;

				/*
				 *using metadata plugin you can add attribut writing them inside the class attr with a JSON sintax
				 * for ex: class="rootVoice {menu:'menu_2'}"
				 */
				var cMenuEls;
				if ($.metadata){
					$.metadata.setType("class");
					cMenuEls= $(this).find(".cmVoice");
					$(cMenuEls).each(function(){
						if ($(this).metadata().cMenu) $(this).attr("cMenu",$(this).metadata().cMenu);
					})
				}
				cMenuEls= $(this).find("[cMenu]");

				$(cMenuEls).each(function(){
					$(this).css("-khtml-user-select","none");
					var cm=this;
					cm.id = !cm.id ? "menu_"+Math.floor (Math.random () * 100): cm.id;
					$(cm).css({cursor:"default"});
					$(cm).bind("contextmenu","mousedown",function(event){
						//if (event.button ==2 || event.which==3){
						event.preventDefault();
						event.stopPropagation();
						event.cancelBubble=true;

						$.mbMenu.lastContextMenuEl=cm;

						if ($.mbMenu.options.actualMenuOpener) {
							$(thisMenu).removeMbMenu($.mbMenu.options.actualMenuOpener);
						}
						/*add custom behavior to contextMenuEvent passing the el and the event
						 *you can for example store to global var the obj that is fireing the event
						 *mbActualContextualMenuObj=cm;
						 *
						 * you can for example create a function that manipulate the voices of the menu
						 * you are opening according to a certain condition...
						 */

						thisMenu.options.onContextualMenu(this,event);

						$(this).buildMbMenu(thisMenu,$(this).attr("cMenu"),"cm",event);
						$(this).attr("isOpen","true");

						//}
					})
				})
			})
		}
	}
	$.fn.extend({
		buildMbMenu: function(op,m,type,e){
			var msie6=$.browser.msie && $.browser.version=="6.0";
			var mouseOver=$.browser.msie?"mouseenter":"mouseover";
			var mouseOut=$.browser.msie?"mouseleave":"mouseout";
			$().bind("click",function(){$(document).removeMbMenu(op,true)})
			if (e) {
				this.mouseX=$(this).getMouseX(e);
				this.mouseY=$(this).getMouseY(e);
			}

			if ($.mbMenu.options.actualMenuOpener && $.mbMenu.options.actualMenuOpener!=op)
				$(op).removeMbMenu($.mbMenu.options.actualMenuOpener);
			$.mbMenu.options.actualMenuOpener=op;
			if(!type || type=="cm")	{
				if (op.rootMenu) {
					$(op.rootMenu).removeMbMenu(op);
					$(op.actualOpenedMenu).removeAttr("isOpen")
				}
				op.clicked=true;
				op.actualOpenedMenu=this;
				$(op.actualOpenedMenu).attr("isOpen","true")
				$(op.actualOpenedMenu).addClass("selected");
			}
			var opener=this;
			var where=(!type|| type=="cm")?$(document.body):$(this).parent().parent();

			//empty
			if($(this).attr("menu")=="empty"){
				return;
			}

			var menuClass= op.options.menuSelector.replace(".","")
			where.append("<div class='menuDiv'><div class='"+menuClass+"' style='display:table'></div></div>");
			this.menu  = where.find(".menuDiv");
			$(this.menu).css({width:0, height:0});
			if (op.options.minZindex!="auto"){
				$(this.menu).css({zIndex:op.options.minZindex++});
			}else{
				$(this.menu).mb_BringToFront();
			}
			this.menuContainer  = $(this.menu).find(op.options.menuSelector);
			$(this.menuContainer).bind(mouseOver,function(){
				$(opener).addClass("selected");
			})
			$(this.menuContainer).css({
				position:"absolute",
				opacity:op.options.opacity
			});
			if (!$("#"+m).html()){
				$.ajax({
					type: "POST",
					url: op.options.template,
					cache: false,
					async: false,
					data:"menuId="+m+(op.options.additionalData!=""?"&"+op.options.additionalData:""),
					success: function(html){
						$("body").append(html);
						$("#"+m).hide();
					}
				});
			}
			$(this.menuContainer).hide();
			this.voices= $("#"+m).find("a").clone();


			if (op.options.shadow) {
				var shadow = $("<div class='menuShadow'></div>").hide();
				if(msie6)
					shadow = $("<iframe class='menuShadow'></iframe>").hide();
			}

			/*
			 *using metadata plugin you can add attribut writing them inside the class attr with a JSON sintax
			 * for ex: class="rootVoice {menu:'menu_2'}"
			 */
			if ($.metadata){
				$.metadata.setType("class");
				$(this.voices).each(function(){
					if ($(this).metadata().disabled) $(this).attr("disabled",$(this).metadata().disabled);
					if ($(this).metadata().img) $(this).attr("img",$(this).metadata().img);
					if ($(this).metadata().menu) $(this).attr("menu",$(this).metadata().menu);
					if ($(this).metadata().action) $(this).attr("action",$(this).metadata().action);
					if ($(this).metadata().disabled) $(this).attr("disabled",$(this).metadata().disabled);
				})
			}

			// build each voices of the menu
			$(this.voices).each(function(i){

				var voice=this;
				var imgPlace="";
				var isText=$(voice).attr("rel")=="text";
				var isTitle=$(voice).attr("rel")=="title";
				var isDisabled=$(voice).is("[disabled]");
				var isSeparator=$(voice).attr("rel")=="separator";

				if (op.options.hasImages && !isText){

					var imgPath=$(voice).attr("img")?$(voice).attr("img"):"blank.gif";
					imgPath=(imgPath.length>3 && imgPath.indexOf(".")>-1)?"<img class='imgLine' src='"+op.options.iconPath+imgPath+"'>":imgPath;
					imgPlace="<td class='img'>"+imgPath+"</td>"
				}
				var line="<table id='"+m+"_"+i+"' class='line"+(isTitle?" title":"")+"' cellspacing='0' cellpadding='0' border='0' style='width:100%; display:table' width='100%'><tr>"+imgPlace+"<td class='voice' nowrap></td></tr></table>";
				if(isSeparator)
					line="<div class='separator' style='width:100%; display:inline-block'><img src='"+op.options.iconPath+"blank.gif' width='1' height='1'></div>"
				if(isText)
					line="<div style='width:100%; display:table' class='line' id='"+m+"_"+i+"'><div class='voice'></div></div>";

				$(opener.menuContainer).append(line);

				if(!isSeparator){
					$(opener.menuContainer).find("#"+m+"_"+i).find(".voice").append(this);
					if($(this).attr("menu")){
						$(opener.menuContainer).find("#"+m+"_"+i).find(".voice a").wrap("<div class='menuArrow'></div>");
						$(opener.menuContainer).find("#"+m+"_"+i).find(".menuArrow").addClass("subMenuOpener");
						$(opener.menuContainer).find("#"+m+"_"+i).css({cursor:"default"})
						this.isOpener=true;
					}
					if(isText){
						$(opener.menuContainer).find("#"+m+"_"+i).find(".voice").addClass("textBox");
						this.isOpener=true;
					}
					if(isDisabled){
						$(opener.menuContainer).find("#"+m+"_"+i)
							.addClass("disabled")
							.css({cursor:"default"})
					}

					if(!(isText || isTitle || isDisabled)){
						$(opener.menuContainer)
							.find("#"+m+"_"+i)
							.css({cursor:"pointer"});
						if (op.options.submenuHoverIntent==0){
							$(opener.menuContainer).find("#"+m+"_"+i)
								.bind("mouseover",function(event){
								clearTimeout($.mbMenu.deleteOnMouseOut);
								$(this).addClass("selected");
								if(opener.menuContainer.actualSubmenu && !$(voice).attr("menu")){
									$(opener.menu).find(".menuDiv").remove();
									$(opener.menuContainer.actualSubmenu).removeClass("selected");
									opener.menuContainer.actualSubmenu=false;
									//return false;
								}
								if ($(voice).attr("menu")){

									if(opener.menuContainer.actualSubmenu && opener.menuContainer.actualSubmenu!=this){
										$(opener.menu).find(".menuDiv").remove();
										$(opener.menuContainer.actualSubmenu).removeClass("selected");
										opener.menuContainer.actualSubmenu=false;
									}
									if (!$(voice).attr("action")) $(opener.menuContainer).find("#"+m+"_"+i).css("cursor","default")
									if (!opener.menuContainer.actualSubmenu || opener.menuContainer.actualSubmenu!=this){
										$(opener.menu).find(".menuDiv").remove();

										opener.menuContainer.actualSubmenu=false;
										$(this).buildMbMenu(op,$(voice).attr("menu"),"sm",event);
										opener.menuContainer.actualSubmenu=this;
									}
									$(this).attr("isOpen","true")
									return false;
								}
							})
						}else{  // HOVERHINTENT
							$(opener.menuContainer).find("#"+m+"_"+i)
								.bind("mouseover",function(event){
								clearTimeout($.mbMenu.deleteOnMouseOut);
								$(this).addClass("selected");
							});
							$(opener.menuContainer).find("#"+m+"_"+i).hoverIntent({
								over:function(event){
									if(opener.menuContainer.actualSubmenu && !$(voice).attr("menu")){
										$(opener.menu).find(".menuDiv").remove();
										$(opener.menuContainer.actualSubmenu).removeClass("selected");
										opener.menuContainer.actualSubmenu=false;
									}
									if ($(voice).attr("menu")){

										if(opener.menuContainer.actualSubmenu && opener.menuContainer.actualSubmenu!=this){
											$(opener.menu).find(".menuDiv").remove();
											$(opener.menuContainer.actualSubmenu).removeClass("selected");
											opener.menuContainer.actualSubmenu=false;
										}
										if (!$(voice).attr("action")) $(opener.menuContainer).find("#"+m+"_"+i).css("cursor","default")
										if (!opener.menuContainer.actualSubmenu || opener.menuContainer.actualSubmenu!=this){
											$(opener.menu).find(".menuDiv").remove();

											opener.menuContainer.actualSubmenu=false;
											$(this).buildMbMenu(op,$(voice).attr("menu"),"sm",event);
											opener.menuContainer.actualSubmenu=this;
										}
										$(this).attr("isOpen","true")
										return false;
									}
								},
								out:function(){},
								sensitivity: 30,
								interval: op.options.submenuHoverIntent,
								timeout: 0
							})
						}

						$(opener.menuContainer).find("#"+m+"_"+i).bind(mouseOut,function(){
							$(this).removeClass("selected");
						})
					}
					if(isDisabled || isTitle){
						$(this).removeAttr("href");
						$(opener.menuContainer).find("#"+m+"_"+i).bind(mouseOver,function(){
							$(document).unbind("click");
							if(opener.menuContainer.actualSubmenu){
								$(opener.menu).find(".menuDiv").remove();
								opener.menuContainer.actualSubmenu=false;
							}
						}).css("cursor","default")
					}
					$(opener.menuContainer).find("#"+m+"_"+i).bind("click",function(){
						if (($(voice).attr("action") || $(voice).attr("href")) && !isDisabled){
							var target=$(voice).attr("target")?$(voice).attr("target"):"_self";
							if ($(voice).attr("href") && $(voice).attr("href").indexOf("javascript:")>-1){
								$(voice).attr("action",$(voice).attr("href").replace("javascript:",""));
								$(voice).removeAttr("href");
							}
							var link=$(voice).attr("action")?$(voice).attr("action"):"window.open('"+$(voice).attr("href")+"', '"+target+"')";
							$(voice).removeAttr("href");
							eval(link);
							$(this).removeMbMenu(op,true);
						}else if($(voice).attr("menu"))
							return false;
					})
				}
			})

			// Close on Mouseout

			var closeOnMouseOut=$(op)[0].options.closeOnMouseOut;
			if (closeOnMouseOut){
				$(opener.menuContainer).bind("mouseenter",function(){
					clearTimeout($.mbMenu.deleteOnMouseOut);
				})
				$(opener.menuContainer).bind("mouseleave",function(){
					var menuToRemove=$.mbMenu.options.actualMenuOpener;
					$.mbMenu.deleteOnMouseOut= setTimeout(function(){$(this).removeMbMenu(menuToRemove,true)},$(op)[0].options.closeAfter);
				})
			}


			//positioning opened
			var t=0,l=0
			$(this.menuContainer).css({
				width:op.options.menuWidth
			})
			if ($.browser.msie) $(this.menuContainer).css("width",$(this.menuContainer).width()+2);


			switch(type){
				case "sm":
					t=$(this).position().top+op.options.submenuTop;

					l=$(this).position().left+$(this).width()-op.options.submenuLeft;
					break;
				case "cm":
					t=this.mouseY-5;
					l=this.mouseX-5;
					break;
				default:
					if (op.options.openOnRight){
						t=$(this).offset().top-($.browser.msie?2:0)+op.options.menuTop;
						l=$(this).offset().left+$(this).outerWidth()-op.options.menuLeft-($.browser.msie?2:0);
					}else{
						t=$(this).offset().top+$(this).outerHeight()-(!$.browser.mozilla?2:0)+op.options.menuTop;
						l=$(this).offset().left+op.options.menuLeft;
					}
					break;
			}

			$(this.menu).css({
				position:"absolute",
				top:t,
				left:l
			})

			if (!type || type=="cm") op.rootMenu=this.menu;
			$(this.menuContainer).bind(mouseOut,function(){
				$(document).bind("click",function(){$(document).removeMbMenu(op,true)})
			})

			if (op.options.fadeInTime>0) $(this.menuContainer).fadeIn(op.options.fadeInTime);
			else $(this.menuContainer).show();

			if (op.options.shadow) {
				$(this.menu).prepend(shadow)
				shadow.css({
					width:$(this.menuContainer).outerWidth(),
					height:$(this.menuContainer).outerHeight()-1,
					position:'absolute',
					backgroundColor:op.options.shadowColor,
					border:0,
					opacity:op.options.shadowOpacity
				}).show();
			}

			var wh=$(window).height();
			var ww=$(window).width();
			var mh=$(this.menuContainer).outerHeight();
			var mw=shadow?shadow.outerWidth():$(this.menuContainer).outerWidth();

			var actualX=$(where.find(".menuDiv:first")).offset().left;
			var actualY=$(where.find(".menuDiv:first")).offset().top;
			switch(type){
				case "sm":
					if ((actualX+mw)>= ww){
						l-=((op.options.menuWidth*2)-(op.options.submenuLeft*2))
					}
					break;
				case "cm":
					if ((actualX+(op.options.menuWidth*1.5))>= ww){
						l-=((op.options.menuWidth*2)-(op.options.submenuLeft))
					}
					break;
				default:
					if ((actualX+mw)>= ww){
						l-=($(this.menuContainer).offset().left+mw)-ww;
					}
					break;
			}
			if ((actualY+mh)>= wh-10){
				t-=((actualY+mh)-wh)+30;
			}

			$(this.menu).css({
				top:t,
				left:l
			})
		},
		removeMbMenu: function(op,fade){
			if(!op)op=$.mbMenu.options.actualMenuOpener;
			if (op.rootMenu) {
				$(op.actualOpenedMenu)
					.removeAttr("isOpen")
					.removeClass("selected");
				$(op.rootMenu).css({width:1, height:1});
				if (fade) $(op.rootMenu).fadeOut(op.options.fadeOutTime,function(){$(this).remove()});
				else $(op.rootMenu).remove();
				op.rootMenu=false;
				op.clicked=false
				$(document).unbind("click");
			}
		},

		//mouse  Position
		getMouseX : function (e){
			var mouseX;
			if ($.browser.msie)mouseX = event.clientX + document.body.scrollLeft;
			else mouseX = e.pageX;
			if (mouseX < 0) mouseX = 0;
			return mouseX;
		},
		getMouseY : function (e){
			var mouseY;
			if ($.browser.msie)	mouseY = event.clientY + document.body.scrollTop;
			else mouseY = e.pageY;
			if (mouseY < 0)	mouseY = 0;
			return mouseY;
		},
		//get max z-inedex of the page
		mb_BringToFront: function(){
			var zi=10;
			$('*').each(function() {
				if($(this).css("position")=="absolute"){
					var cur = parseInt($(this).css('zIndex'));
					zi = cur > zi ? parseInt($(this).css('zIndex')) : zi;
				}
			});

			$(this).css('zIndex',zi+=10);
		}

	})
	$.fn.buildMenu = $.mbMenu.buildMenu;
	$.fn.buildContextualMenu = $.mbMenu.buildContextualMenu;
})(jQuery);