
var plMenuSystem = Class.create();
plMenuSystem.prototype = {

	initialize: function(){
	
		this.hideDelay = 400;
		this.showOnMouseOver = false;
	
		this.menus = new Array();
		this.visibleMenu = null;
		this.id = "plMenuSystem";	
				
		this.lastEvent = null;		
		
		this.showEffect = null;
		this.hideEffect = null;
		
		this.hiding = new Array();
	},
	
	activate: function(){
		var me = this;
		this.menus.each(function(m){m.activate(me);});		
		
		document.onclick = this.eventHandler.bindAsEventListener(this);
	},			
	
	addMenu: function(mnu){
		this.menus[this.menus.length] = mnu;
	},
		
	setEvent: function(evt){
		this.lastEvent = evt;		
	},
	
	findVisibleMenu: function(){
		this.visibleMenu = this.menus.find( function(m){return m.visible;});
	},
	
	checkMenuTree: function(noDelay){	
		this.dOut();
		if (noDelay) {
			this.hiding.each(function(obj){obj.hideMenu(true);});
			this.hiding = new Array();
		}
		
		var e = this.lastEvent;
		var toElem;
		if (e){		
			toElem = getToElement(e);
						
			if (toElem) {
				var revive = this.hiding.find( function(obj){return (isOrContains(obj.menuObj,toElem)); });		
				if (revive){
					this.dropHider(revive);
					revive.showMenu();
				}
			}			
		}
		
		
		this.findVisibleMenu();
		if (this.visibleMenu) this.visibleMenu.checkMenu(noDelay);
	},
	
	eventHandler: function(evt){
		
		this.setEvent(Object.extend(new Object(),evt));
		this.checkMenuTree(true);
	},
	
	addHider: function(obj){
		if (!this.hiding.include(obj)) this.hiding[this.hiding.length] = obj;
	},
	
	dropHider: function(obj){
		this.hiding = this.hiding.reject(function(o){ return o==obj;})		
	},
	
	dOut:  function(){
/*		var o = '';
		
		if (arguments.length == 0) $('dTxt').value = '';	
		
		for (var i = 0; i < arguments.length; i++) {
			o += arguments[i] + '\t';
		}
		$('dTxt').value = o + '\n' + $('dTxt').value;			
*/
	}
	
};	

var plMenu = Class.create();
plMenu.prototype = {

	initialize: function(obj,trigger,direction){
		this.menuObj = $(obj);
		this.trigger = $(trigger);				
		this.direction = direction; // 0-down 1-left  -->>?? 2-up 3-right
		this.trigger.menu = this;
		
		this.onShowMenu = null;
		this.onHideMenu = null;
		
		this.menuObjMouseOver = null;
		this.menuObjMouseOut = null;
		this.triggerMouseOver = null;
		this.triggerMouseOut = null;
				
		this.visible = false;		
		this.hiding = 3; // -1 = show effect transistion; 0 = visible; 1 = delay before hide; 2 = hide effect transition; 3 = hidden
		this.hideTimer = null;		
		this.showOnHide = false;
		this.hideOnShow = false;
		
		this.subMenus = new Array();		
		this.menuSystem = null;
		
		this.offset = {x: 0, y:0};
	},
	
	activate: function(mnuSys){			
		this.menuSystem = mnuSys;				
		this.menuObj.style.display = 'none';
		this.trigger.onclick = this.showMenu.bindAsEventListener(this);
		
		if ((!this.triggerMouseOver)&&(this.trigger.onmouseover)) this.triggerMouseOver = this.trigger.onmouseover;
		this.trigger.onmouseover = this.mouseOverTrigger.bindAsEventListener(this);				
		this.menuObj.onmouseover = this.mouseOverMenu.bindAsEventListener(this);

		
		if ((!this.menuObjMouseOut)&&(this.menuObj.onmouseout)) this.menuObjMouseOut = this.menuObj.onmouseout;
		if ((!this.triggerMouseOut)&&(this.trigger.onmouseout)) this.triggerMouseOut = this.trigger.onmouseout;
		
		this.subMenus.each(function(s){s.activate(mnuSys);});
	},
	
	addSubMenu: function(subMnu){
		this.subMenus[this.subMenus.length] = subMnu;
	},
	
	autoSize: function(target){
		var t = $(target);
		
		this.menuObj.style.position = 'absolute';
		this.menuObj.style.top = "-5000px";
		this.menuObj.style.left = "-5000px";
		this.menuObj.style.height = "4000px";
		this.menuObj.style.width= "4000px";
		this.menuObj.style.display = "";
		
		this.menuObj.style.height = t.offsetHeight + "px";
		this.menuObj.style.width = t.offsetWidth + "px";				
	},
	
	/*doDelay: function(evt){												
		if (((new Date()).getTime() - this.menuSystem.lastEventTime.getTime())>= this.menuSystem.hideDelay){
			this.menuSystem.dOut('dLay','fire');
			this.menuSystem.checkMenuTree();				
		}else this.menuSystem.dOut('dLay','no');
	},*/

	
	checkMenu: function(noDelay){
		var visibleSub = this.subMenus.find( function(subM){return (subM.visible); });

		var subVis = false;
		var hide = false;
		if (visibleSub) subVis = visibleSub.checkMenu(noDelay);

		this.menuSystem.dOut(this.trigger.id);		
		if (subVis) return true;
		
		var e = this.menuSystem.lastEvent;
		var toElem;
		
		if (e){
			toElem = getToElement(e);			
			
			if	(toElem && 
				 ((!isOrContains(this.menuObj,toElem))&&(!isOrContains(this.trigger,toElem))))
				 {						
					this.hideMenu(noDelay); 
					this.menuSystem.dOut('A',this.trigger.id,toElem.innerHTML,toElem.tagName,isOrContains(this.menuObj,toElem),isOrContains(this.trigger,toElem));
				 }

			else if ((!toElem)&&(this.menuSystem.lastEvent.pageX)){

				var lastX = Event.pointerX(this.menuSystem.lastEvent);
				var lastY = Event.pointerY(this.menuSystem.lastEvent);
				
				if	(	
						(!Position.within(this.menuObj,lastX,lastY))									
					&&	(!Position.within(this.trigger,lastX,lastY))
					)
					{					
						this.hideMenu(noDelay);	
						this.menuSystem.dOut('B');
					}
			}
		}		
			
		return this.visible;
	},
	
	mouseOutMenu: function(evt){
	
		this.menuSystem.dOut('mOutM',(evt.srcElement)?evt.srcElement.id+evt.srcElement.tagName:'null');
		this.menuSystem.setEvent(Object.extend(new Object(),evt));
		
		if (this.menuObjMouseOut) this.menuObjMouseOut.call(this.menuObj,evt);
		
		//window.setTimeout(this.doDelay.bindAsEventListener(this),this.menuSystem.hideDelay);
		if (this.menuSystem.showOnMouseOver) this.menuSystem.checkMenuTree();
	},

	mouseOutTrigger: function(evt){
	
		this.menuSystem.dOut('mOutT',(evt.srcElement)?evt.srcElement.id+evt.srcElement.tagName:'null');
		this.menuSystem.setEvent(Object.extend(new Object(),evt));

		if (this.triggerMouseOut) this.triggerMouseOut.call(this.trigger,evt);

		//window.setTimeout(this.doDelay.bindAsEventListener(this),this.menuSystem.hideDelay);
		if (this.menuSystem.showOnMouseOver) this.menuSystem.checkMenuTree();
	},
	
	mouseOverMenu: function(evt){
		if (this.hiding==2){ return; }
		
		this.menuSystem.dOut('mOver',(evt.srcElement)?evt.srcElement.id+evt.srcElement.tagName:'null',(evt.pageY?evt.pageY:'0'));
		this.menuSystem.setEvent(Object.extend(new Object(),evt));
		
		//window.setTimeout(this.doDelay.bindAsEventListener(this),this.menuSystem.hideDelay);
		this.menuSystem.checkMenuTree();
	},
	
	mouseOverTrigger: function(evt){
	
		this.menuSystem.dOut('sOMO',(evt.srcElement)?evt.srcElement.id+evt.srcElement.tagName:'null');
		this.menuSystem.setEvent(Object.extend(new Object(),evt));
		
		if (this.triggerMouseOver) this.triggerMouseOver.call(this.trigger,evt);

		if ((!this.visible) && ((this.menuSystem.visibleMenu)||(this.menuSystem.showOnMouseOver)))
			this.showMenu(evt);		
		/*else
			this.hideOnShow = false;*/
	},
	
	setForSubMenus: function(prop,value){
		this.subMenus.each(
			function(item,idx){
				item[prop]=value; 
				item.setForSubMenus(prop,value);
			}
		);
	},
	
	showMenu: function(evt){				

		var pos = Position.cumulativeOffset(this.trigger);
		var h = this.trigger.offsetHeight;
		var w = this.trigger.offsetWidth;
		var toElem;
		var inMenu = false;
		
		this.hideOnShow = false;
		
		if (evt) this.menuSystem.setEvent(Object.extend(new Object(),evt));
		toElem = getToElement(this.menuSystem.lastEvent);
		inMenu = ((toElem)&&(isOrContains(this.menuObj,toElem)));
		
		
		if (this.hiding == 2){
			if (!inMenu) this.showOnHide = true;
			return;
		}
		
		if (this.hideTimer) window.clearTimeout(this.hideTimer);
		this.hideTimer = null;

		this.menuSystem.dropHider(this);		
		
		if ((this.hiding==1)&&(inMenu)){
			this.visible = true;			
		}
		
		this.hiding = -1;
				
		this.menuSystem.checkMenuTree(true);
		
		if (this.direction == 0){
			Element.setStyle(this.menuObj,{top: pos[1]+h+this.offset.y+'px', left: pos[0]+this.offset.x+'px'});
		} else if (this.direction == 1){
			Element.setStyle(this.menuObj,{top: pos[1]+this.offset.y+'px', left: pos[0]+w+this.offset.x+'px'});
		}
		
		this.visible = true;				
		if (this.menuSystem.showEffect) 
			this.menuSystem.showEffect(this.menuObj,this.showFinal.bindAsEventListener(this));
		else{
			Element.setStyle(this.menuObj,{display: ''});
			this.showFinal();
		}		
		
		this.menuSystem.findVisibleMenu();

		this.menuObj.onmouseout = this.mouseOutMenu.bindAsEventListener(this);				
		this.trigger.onmouseout = this.mouseOutTrigger.bindAsEventListener(this);
		if (this.onShowMenu) this.onShowMenu.call(this);
		
	
	},	
	
	hideMenu: function(noDelay){

			this.showOnHide = false;		
			
			if (this.hiding == -1){
				this.hideOnShow = true;
				return;
			}
						
			this.visible = false;			
			this.hiding = 1;
			
			if (this.hideTimer){
				 window.clearTimeout(this.hideTimer);
				 this.hideTimer = null;
			}
			
			if (noDelay){
				/*if (this.menuSystem.hideEffect)
					this.menuSystem.hideEffect(this.menuObj,this.hideFinal.bindAsEventListener(this));
				else{*/
						Element.setStyle(this.menuObj,{display: 'none'});
						this.hideFinal();
				//}
			}else{
				this.hideTimer = window.setTimeout(this.hideStart.bindAsEventListener(this),this.menuSystem.hideDelay);
				this.menuSystem.addHider(this);
			}			
			
			this.menuObj.onmouseout = this.menuObjMouseOut;
			this.trigger.onmouseout = this.triggerMouseOut;			
			if (this.onHideMenu) this.onHideMenu();
			
			this.menuSystem.findVisibleMenu();
	},
	
	hideStart: function(evt){												
		if ((!this.visible)&&(this.hiding==1)){  //(this.menuSystem.hiding.include(this))){
		 
			this.hiding = 2;
		 	if (this.menuSystem.hideEffect)
				this.menuSystem.hideEffect(this.menuObj,this.hideFinal.bindAsEventListener(this));
			else{
				Element.setStyle(this.menuObj,{display: 'none'});		 
				this.hideFinal();
			}			
		 }
	},
	
	hideFinal: function(){
		this.hiding = 3;
		this.menuSystem.dropHider(this);
		if (this.showOnHide) this.showMenu();
	},
	
	showFinal: function(){	
		this.hiding = 0;
		if (this.hideOnShow) this.hideMenu(true);	
	}
	
};	


function ShowObj(obj,rec){
	var o = '';
	if (!rec) rec = 0;
	
	for (property in obj) {
		if (typeof obj[property] == 'object'){
		if (rec > 0)
			o += '[' + property + ' ' + '\n  ' + ShowObj(obj[property],rec-1).replace(/[\n]/g,'\n  ') + ']\n';
		else
			o += '[' + property + ' ' + (obj[property] ? (obj[property].toString?obj[property].toString():'[object]') : 'null') + ']\n';  //'\n' + ShowObj(obj[property]).replace('\n','  \n') + ']\n';
		}else
		o += property + ' : ' + (obj[property] ? obj[property].toString() : 'undefined') + '\n';
	}
	return o;
}


function getToElement(e){
	var toElem;
	
	if (e.toElement) toElem = e.toElement;
	if ((!toElem)&&(e.type&&(e.type=='mouseout'))&&(e.relatedTarget)) 
		toElem = e.relatedTarget;
	if ((!toElem)&&(e.target)) toElem = e.target;
	if ((!toElem)&&(e.srcElement)) toElem = e.srcElement;
	if (!e.toElement) e.toElement = toElem;
	
	return toElem;
}

function contains(obj1,obj2){
	if (obj1 == obj2) return true;
	if (!obj2.parentElement) return false;	
	if (obj2 == obj2.parentElement) return false;			
	
	return contains(obj1,obj2.parentElement);			
}

function isOrContains(obj1,obj2){
	if (obj1 == obj2) return true;
	
	element = $(obj2), ancestor = $(obj1);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
}

