
// openTrace();


//******* Class *********

function PopupMenu(name, level) {
	
	// ***** Fields ******
	
	this.name = name;
	this.next = null; // current
	this.parent = null;
	this.level = level;	
	this.locked = 0;
	this.state = 'created';
	this.shown = 0; // sub shown
	
	
	this.setStateClosed = function() {
		this.state = 'closed';
		traceBasic("PopupMenu.setStateClosed", this.name + " closed");
	}
	
	this.setStateCreated = function() {
		this.state = 'created';
	}
	
	this.setStateShown = function() {
		this.state = 'shown';
		traceBasic("PopupMenu.setStateShown", this.name + " shown");
	}
	
	this.isClosed = function() {
		return (this.state == 'closed');
	}
	
	this.isShown = function() {
		return (this.state == 'shown');
	}
	
	this.isCreated = function() {
		return (this.state == 'created');
	}
	
	
	this.setLockPrompt = function(which) {
		try {
			if (which < 1) return;
			
			var imgid = this.name + '_arrow' + which;
			
			if (this.locked == which) {
				document.images[imgid].title = '解锁';	
				return; 
			}

			document.images[imgid].title = '加锁';		
		} catch(ex) {
		}		
	}
	
	
	// source: the menu level, start from 0
	//
	this.popup = function(level, event, which) {
		traceRun("PopupMenu.popup");
		trace("PopupMenu.popup", "parent menu", this.name);
		trace("PopupMenu.popup", "level", level);
		trace("PopupMenu.popup", "to show which", which);
		
		if (level < 0 || which < 1) return;
		
		this.setLockPrompt(which);
		
		// to target
		if (level != this.level) {
			traceBasic("PopupMenu.popup", "forward to next");
			
			if (this.next)
				this.next.popup(level, event, which);
			
			return;
		}
		
		if (this.locked && which != this.locked) {
			traceBasic("PopupMenu.popup", "subm " + this.locked + " locked");
			return;
		}
		
		try {
			var subm = this.subs[which - 1];
			var mid = subm.name;
	
			showControl(mid);
		
			PopupMenu.arrowLeft = event.clientX - event.offsetX + PopupMenu.popUpOffsetX; //XX conf
			PopupMenu.arrowTop = event.clientY - event.offsetY + PopupMenu.popUpOffsetY; 	
			
			$(mid).style.left = PopupMenu.arrowLeft;
			$(mid).style.top = PopupMenu.arrowTop;
					
			this.shown = which;		
					
			this.next = subm; 
			this.next.setStateShown();
			this.next.parent = this;		
			
		} catch(ex) {
			traceEx("PopupMenu.popup", ex);
		}
	}
	
	
	this.showSub = function(target) {			
		try {	
			traceRun("PopupMenu.showSub");
			trace("PopupMenu.showSub", "target", target);
			trace("PopupMenu.showSub", "level", this.level);
			
			if (target == this.level) {
			// reached, no sub
				return;
			}
			
			var subm = this.next;		
			
			if (subm) {			
				showControl(this.name);
				this.setStateShown();
				
				showControl(subm.name);
				subm.setStateShown();		
				
				subm.parent = this; //??
			
				trace("PopupMenu.showSub", "entering ", subm.name);				
				subm.showSub(target);
			}
		} catch(ex) {
			trace("PopupMenu.showSub", ex);
		}
	}
	

	// level: from parent when self = false
	//
	this.close = function(event, self, level) {
		try {				
			var inbound = false;
			
			// trace("PopupMenu.close", "to close", which);
			trace("PopupMenu.close", "self", self);
			trace("PopupMenu.close", "target level", level);
			trace("PopupMenu.close", "current level", this.level);
			trace("PopupMenu.close", "event == null", (event == null));
			
			if (level < 0) return; // level
						
			if (event != null) {
				// menuStates[level] && !internal menu opened, to move in from outside
				
				/* trace("closeRightMenu", "arrowX", arrowX);
				trace("closeRightMenu", "event.clientX", event.clientX);
				trace("closeRightMenu", "arrowY", arrowY);
				trace("closeRightMenu", "event.clientY", event.clientY);
				*/
				if ((event.clientX - PopupMenu.arrowLeft > PopupMenu.eventRangeLeft) &&
						(event.clientY - PopupMenu.arrowTop > PopupMenu.eventRangeTop && 
						 event.clientY - PopupMenu.arrowTop < PopupMenu.eventRangeBottom))		
				{ //XX conf old: -5,50					
					traceBasic("PopupMenu.close", "Not to close: inbound");		
					inbound = true;		
				}
			}					
			trace("PopupMenu.close", "inbound", inbound);
			
			if (!self) {
			// close next, from parent	
				if (this.level < level) {
					traceBasic("PopupMenu.close", "forward to next");
				
					if (this.next)
						this.next.close(event, false, level);
						
					return;
				}
				
				var subm = this.next;								
				if (!subm) {
					traceBasic("PopupMenu.close", "Return: no next");
					return;
				}
				
				traceBasic("PopupMenu.close", "To close " + subm.name + " from " + this.name);
				
				if (subm.locked || this.locked) {
					traceBasic("PopupMenu.close", "Failed to close: locked");	
					trace("PopupMenu.close", "me locked", this.locked);	
					trace("PopupMenu.close", "next locked", subm.locked);	
					return;
				}
				
				trace("PopupMenu.close", "name", subm.name);				
				trace("PopupMenu.close", "state", subm.state);				
				
				if (inbound && subm.isShown()) {
					traceBasic("PopupMenu.close", "Failed to close" + subm.name);				
					return;
				}
	
				hideControl(subm.name);
				subm.setStateClosed();	

				if (subm.next)
					this.close(event, true, subm.level + 1);					
				
				return;
				
			} else {
			// close current, then upstream	

				if (this.level < level) {
					traceBasic("PopupMenu.close", "forward to next");
				
					if (this.next)
						this.next.close(event, true, level);
						
					return;
				}

				if (!inbound) {
					if (this.locked) return;
					
					if (this.parent)
						if (this.parent.locked) return;
					
					if (this.level == 0 && this.next) {
					// it's root
						this.next.close(event, true, this.level);
					}
					
					hideControl(this.name);	
					this.setStateClosed();											

					if (this.parent)
						this.parent.close(event, true, level - 1);	
					
				}
			}
		} catch(ex) {
			traceEx("PopupMenu.close", ex);
		}		
	}


	this.autoLock = function(auto) {
		try {		
			traceRun("PopupMenu.autoLock");
			trace("PopupMenu.autoLock", "level", this.level);
			trace("PopupMenu.autoLock", "name", this.name);
			
			if (this.level < 0) return;
			
			if (this.locked) {
				traceBasic("PopupMenu.lock", "already locked");
			} else {			
				var imgid = this.name + '_arrow' + this.shown;
				trace("PopupMenu.lock", "imgid", imgid);
				
				document.images[imgid].src = '/img/down_blue.gif';
				this.locked = this.shown;
			}
			
			if (auto && this.parent) {
				this.parent.autoLock(true);
			}
			
		} catch(ex) {
			traceEx("PopupMenu.lock", ex)
		}
	}
	

	this.unlock = function(auto) {
		try {		
			traceRun("PopupMenu.unlock");
			trace("PopupMenu.unlock", "level", this.level);
			trace("PopupMenu.unlock", "name", this.name);
			
			if (this.locked < 1) {
				traceBasic("PopupMenu.unlock", "nothing locked");
			} else {			
				var imgid = this.name + '_arrow' + this.locked;
				
				document.images[imgid].src = '/img/arrow-left.gif';
				this.locked = 0;
				traceBasic("PopupMenu.unlock", imgid + " unlocked");
			}
			
			if (auto && this.next) {
				this.next.unlock(true);
			}
			
		} catch(ex) {
			traceEx("PopupMenu.unlock", ex)
		}
	}


	// mlevel: current menu
	// which: the menu/arrow index
	//
	this.setLock = function(mlevel, which, event) {
		try {	
			if (!this.next || mlevel < 0 || which < 1) return;
			
			if (this.level < mlevel) {
				this.next.setLock(mlevel, which, event);
				return;
			}
			
			trace("PopupMenu.lock", "target level", mlevel);	
			trace("PopupMenu.lock", "current level", this.level);	
			trace("PopupMenu.lock", "to set lock", which);	
			trace("PopupMenu.lock", "locked val", this.locked);	
			//trace("PopupMenu.lock", "subs", this.subs.length);	

			// adjust me
			if (this.locked && which != this.locked) {
				traceBasic("PopupMenu.lock", "To Exchange Lock");
				this.unlock(true);
				//traceBasic("PopupMenu.lock", "to close");
				this.close(event, false, this.level);

				showControl(this.name);
				this.setStateShown();
				
				this.popup(this.level, event, which);
				//traceBasic("PopupMenu.lock", "to open");				
			}


			//trace("PopupMenu.lock", "subs", this.subs[2]);	
			var imgid = this.name + '_arrow' + which;
			trace("PopupMenu.lock", "imgid", imgid);
	
			if (!this.locked) {
			// to lock
				document.images[imgid].src = '/img/down_blue.gif';
				this.locked = which;
				traceBasic("PopupMenu.lock", "No. " + which + " locked");
				
				if (this.level && this.parent) {
					this.parent.autoLock(true);
				}
					
			} else {				
			// to unlock
				this.unlock(true);				
			}		
			
			this.setLockPrompt(which);
			
		} catch(ex) {
			traceEx("PopupMenu.lock", ex);
		}
	}
	
	
	this.isLocked = function() {
		var rslt = false;
		
		if (this.locked)
			rslt = true;
			
		if (!rslt && this.next)
			rslt = this.next.isLocked();
			
		return rslt;
	}
	
} // PopupMenu


function PopupMenu_initSubs(size) {
	if (size > 0) {
		this.subs = new Array(size);
	} else {
		this.subs = null;
	}
}


function PopupMenu_addSub(name, which) {
	var rslt = new PopupMenu(name, this.level + 1); //!! no use
	
	if (rslt && this.subs && which > 0) {
		this.subs[which - 1] = rslt;
	}

	trace("PopupMenu.addSub", "rslt == null", (rslt == null));
	return rslt;
}

PopupMenu.prototype.addSub = PopupMenu_addSub;
PopupMenu.prototype.initSubs = PopupMenu_initSubs;

PopupMenu.popUpOffsetX = -3;
PopupMenu.popUpOffsetY = -11;

PopupMenu.eventRangeLeft = -5;
PopupMenu.eventRangeTop = 5;
PopupMenu.eventRangeBottom = 30;

PopupMenu.arrowLeft;
PopupMenu.arrowTop;


//******* Helpers *********


function clearPopupRoot(event) {
	if (!gPopupRoot) return;
	
	if (!gPopupRoot.isLocked())
		gPopupRoot = null;
}


function createPopupRoot(name, size) {
	var rslt = null;
	
	if (!gPopupRoot && name != '') {
		gPopupRoot = new PopupMenu(name, 0);
		if (size > 0) gPopupRoot.initSubs(size); 
		rslt = gPopupRoot;			
	}
	
	//trace("createPopupRoot", "rslt == null", (rslt == null));
	return rslt;
}


function popup(source, event, which) {
	traceRun("popup");
	
	if (gPopupRoot) {
		/* var mn = gPopupRoot.subs[which - 1].name;
		var level = gPopupRoot.level + 1;
		
		trace("popup", "which", which);
		trace("popup", "level", level);
		trace("popup", "to show", mn);
		*/	
		gPopupRoot.popup(source, event, which);
	}
}


function showPopup(target) {
	if (gPopupRoot)
		gPopupRoot.showSub(target);
}


function hide(self, event, level, note) {
	try {
		traceRun("hide");
		
		if (gPopupRoot) {
			trace("hide", "level", level);
			trace("hide", "note", note);
						
			gPopupRoot.close(event, self, level);
		}
	} catch(ex) {
		traceEx("hide", ex);
		// trace("hide", "gPopupRoot == null", (gPopupRoot == null));
	}
}


// mlevel: parent
//
function usrSetLock(mlevel, which, event) {
	traceRun("gUsrSetLock");

	if (gPopupRoot) 
		gPopupRoot.setLock(mlevel, which, event);
}
