// Hey, don't expect much - made by me and for me only due to courtesy of mootools
var _dropdown_sindex=0;

function DropDown(name,parent,type)
{
	// default values
	this.props={transition:"Fx.Transitions.linear",
				timeouts:{transition:50, show:200, fade:1000},
				box:{prefix:"dd_", styles:{h:"dd_hbox", v:"dd_vbox", hf:"dd_hbox_fixed", vf:"dd_vbox_fixed"}},
				item:{prefix:"item_", styles:{h:"dd_hitem", v:"dd_vitem"}},
				pitem:{styles:{active:"dd_a_item",inactive:"dd_i_item"}}};

	this._id=_dropdown_sindex++; // keep uniqueness
	this._items=[];
	this._counter=0;
	this._selectedItem=null;
	this._refs=new Object();
	this._left=0;
	this._top=0;
	this._width=0;
	this._height=0;
	this.offsetObject=null; // forced offset. it's expected to have a function getOffsets() => {x:<val>, y:<val>}
	this.rememberPos=true; // remember Left & Top or recalculate it every time
	this._active=false;
	this._timer=null;

	this.name=name; // stupid, stupid js doesn't know what real classes are
	this.parent=parent;
	this._idtag=this.props.box.prefix+this._id;
	this._type=type;
	this.hidden=true;

	this.browserWS=function() {
		var width,height;
		var coords=$(document.documentElement).getCoordinates();
		if (window.innerHeight) height=window.innerHeight;
		return {width:coords.width, height:height};
	};

	this._renderDyn=function(bReverse,left0,top0,width0,height0,left1,top1,width1,height1) {
		var ddms=new Fx.Morph(this._idtag,"{duration: "+this.props.timeouts.transitioon+", transition: "+this.props.transition+"}");
		var leftb=left0,topb=top0,widthb=width0,widthe=width1,heightb=height0,heighte=height1;
		if (bReverse) {
			leftb=left1,topb=top1,widthb=width1,widthe=width0,heightb=height1,heighte=height0;
			// IE just despicable!!! Damn it.
			eval("var func=function() { $("+this.name+"._idtag).setStyles({visibility:'hidden'}); }");
			ddms.addEvent('complete',func);
		}
		$(this._idtag).setStyles({ left:leftb, top:topb, width:widthb, height:heightb, display:'block', visibility:'visible' });
		ddms.start({
		    'width': [widthb, widthe],
		    'height': [heightb, heighte]
		});
	};
	this._renderOpacity=function(bReverse,left0,top0,width0,height0,left1,top1,width1,height1) {
		var ddms=new Fx.Morph(this._idtag,"{duration: "+this.props.timeouts.transition+", transition: "+this.props.transition+"}");
		var opacityb=0.0,opacitye=1.0;
		if (bReverse) {
			opacityb=1.0,opacitye=0.0;
			// IE just despicable!!! Damn it.
			eval("var func=function() { $("+this.name+"._idtag).setStyles({visibility:'hidden'}); }");
			ddms.addEvent('complete',func);
		}
		$(this._idtag).setStyles({ left:left1, top:top1, width:width1, height:height1, opacity:opacityb, display:'block', visibility:'visible' });
		ddms.start({
		    'opacity': [opacityb, opacitye]
		});
	};
	this._renderPlain=function(bReverse,left0,top0,width0,height0,left1,top1,width1,height1) {
		if (bReverse) {
			$(this._idtag).setStyles({ visibility:'hidden' });
		}
		else {
			$(this._idtag).setStyles({ left:left0, top:top0, width:width1, height:height1, display:'block', visibility:'visible' });
		}
	};

	// select the proper way to render dropdown
	//	this._render=this._renderOpacity;
	this._render=this._renderPlain;

	// clear timers chain from bottom to root
	this._clearTC=function() {
		$clear(this._timer);
		if (this.parent) if (this.parent.box) this.parent.box._clearTC();
	};
	// set timers chain (to fade box, of cause) from bottom to root
	this._setTC=function() {
		eval("this._timer=(function() { "+this.name+".fade(); }).delay("+this.name+".props.timeouts.fade);");
		if (this.parent) if (this.parent.box) if (!this.parent.box._active) this.parent.box._setTC();
	};
	// fade effect from selectedItem to bottom
	this._fadeWC=function() {
		if (this._selectedItem) if (this._selectedItem.child) this._selectedItem.child._fadeWC();
		this.fade();
	};


	this.getType=function() { return this._type; };

	// the way to add new item to box
	// alas, no multithreading... ;)
	this.addItem=function(htmlItem,child,href) {
		this._items[this._counter]=new Object();
		this._items[this._counter].box=this;
		this._items[this._counter].idtag=this._idtag+"_"+this.props.item.prefix+this._counter;
		this._items[this._counter].html=htmlItem;
		if (!href) href="#";
		this._items[this._counter].href=href;
		this._items[this._counter].selected=false;
		this._items[this._counter].child=child; // the next level box
		if (child) if (child instanceof DropDown) child.parent=this._items[this._counter];

		this._refs[this._items[this._counter].idtag]=this._counter;
		this._counter++;
	};

	// reset/reload all box items
	// expects an array of object of kind {html:<string>,child:<object>,href:<string>}
	this.rrItems=function(items) {
		var counter;
		this._items=[];
		for (i=0;i<items.length;i++) {
			this._items[i]=new Object();
			this._items[i].box=this;
			this._items[i].idtag=this._idtag+"_"+this.props.item.prefix+i;
			this._items[i].html=items[i].html;
			if (!items[i].href) items[i].href="#";
			this._items[i].href=items[i].href;
			this._items[i].selected=false;
			this._items[i].child=items[i].child; // the next level box
			if (items[i].child) if (items[i].child instanceof DropDown) items[i].child.parent=this._items[i];
	
			this._refs[this._items[i].idtag]=i;
		}
		this._counter=i;
	}
	
	// attach events to elements
	// warning: only AFTER publishing
	this.activateItems=function() {
		var i;

		// no need for root box
		if (this.parent) {
			eval("var func=function(e) { \
					e=new Event(e); \
					"+this.name+"._active=true; \
					e.stop(); \
			};");
			$(this._idtag).addEvent("mouseover",func);
			eval("var func=function(e) { \
					e=new Event(e); \
					"+this.name+"._active=true; \
					"+this.name+"._clearTC(); \
					e.stop(); \
			};");
			$(this._idtag).addEvent("mouseenter",func);
			eval("var func=function(e) { \
					e=new Event(e); \
					"+this.name+"._active=false; \
					"+this.name+".parent.box._active=false; \
					"+this.name+"._setTC(); \
					e.stop(); \
			};");
			$(this._idtag).addEvent("mouseleave",func);
		}

		for (i=0;i<this._items.length;i++) {
			// let an item minds own business if necessary
			
			if (this._items[i].html._idtag) {
				var id=$(this._items[i].html._idtag);
				if (this._items[i].html.mouseEnter) id.addEvent("mouseenter",this._items[i].html.mouseEnter);
				if (this._items[i].html.mouseLeave) id.addEvent("mouseleave",this._items[i].html.mouseLeave);
				if (this._items[i].html.mouseDown) id.addEvent("mousedown",this._items[i].html.mouseDown);
				if (this._items[i].html.mouseClick) id.addEvent("click",this._items[i].html.mouseClick);
			}

			if (this._items[i].child) {
				// IE just despicable!!! Damn it.

				eval("var func=function(e) { \
						e=new Event(e); \
						"+this.name+"._active=true; \
						"+this._items[i].child.name+"._clearTC(); \
						if ("+this._items[i].child.name+".hidden) { \
							if ("+this.name+"._selectedItem) if ("+this.name+"._selectedItem.child) "+this.name+"._selectedItem.child._fadeWC(); \
						"+this._items[i].child.name+"._timer=(function() { "+this._items[i].child.name+".show(); }).delay("+this.name+".props.timeouts.show); \
						} \
						e.stop(); \
				};");
				$(this._items[i].idtag).addEvent("mouseover",func);
				eval("var func=function(e) { \
						if ("+this._items[i].child.name+".hidden) $clear("+this._items[i].child.name+"._timer); \
						else "+this._items[i].child.name+"._timer=(function() { "+this._items[i].child.name+".fade(); }).delay("+this.name+".props.timeouts.fade); \
				};");
				$(this._items[i].idtag).addEvent("mouseleave",func);
				this._items[i].child.activateItems();
			}
		}
	};

	this.setValue=function(idx,param,value) {
		var item;
		if (isNaN(parseInt(idx))) {
			if (this._refs[idx]) item=this._items[idx];
			else return;
		}
		else item=this._items[this._refs[idx]];
		item[param]=value;
		if (param == "child") item.child.parent=item;
	};

	// generate html code
	// container100 - a container can hold 100% width of browser window for proper menu width calculations or null
	this.writeHtmlTo=function(container,recursive,container100) {
		if (this._type == "h") {
			var i,counter=0,bufs=[],buffer="<table id=\""+this._idtag+"\" class=\""+this.props.box.styles[this._type]+"\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr>",buffer100="",itemstyle=this.props.item.styles[this._type];
			for (i=0;i<this._items.length;i++) {
				buffer+="<td class=\""+this.props.item.styles[this._type]+"\"><a id=\""+this._items[i].idtag+"\" href=\""+this._items[i].href+"\">"+this._items[i].html+"</a></td>";
				if (recursive && this._items[i].child) bufs[counter++]=this._items[i].child.writeHtmlTo(null,recursive);
			}
			if (container && container100) {
				buffer+="</tr></tbody></table>";
				buffer100=bufs.join("");
			}
			else buffer+="</tr></tbody></table>"+bufs.join("");
		}
		else {
			var addtype="f";
			if (this.parent) addtype="";
			var i,counter=0,bufs=[],buffer="<div id=\""+this._idtag+"\" class=\""+this.props.box.styles[this._type+addtype]+"\"><table cellspacing=\"0\" cellpadding=\"0\" border=\"0\"><tbody>",buffer100="",itemstyle=this.props.item.styles[this._type];
			for (i=0;i<this._items.length;i++) {
				buffer+="<tr><td class=\""+this.props.item.styles[this._type]+"\"><a  id=\""+this._items[i].idtag+"\" href=\""+this._items[i].href+"\">"+this._items[i].html+"</a></td></tr>";
				if (recursive && this._items[i].child) bufs[counter++]=this._items[i].child.writeHtmlTo(null,recursive);
			}
			if (container && container100) {
				buffer+="</tbody></table></div>";
				buffer100=bufs.join("");
			}
			else buffer+="</tbody></table></div>"+bufs.join("");
		}
		if (container) {
			if (container100)
				if ($(container100)) $(container100).set("html",buffer100);
				else buffer+=buffer100;
			if (container==document) document.write(buffer);
			else $(container).set("html",buffer);

			// for root menu only
			if (this.parent==null) {
				eval("var func=function() {"+this.name+"._fadeWC();};");
				window.addEvent("mousewheel",func);
			}
			return "";
		}
		else return buffer;
	};

	// when the time to show something
	this.show=function() {
		if (this.hidden) {
			if (this.parent) {
				if (this._width==0 || this._height==0 || !this.rememberPos) {
					var bws=this.browserWS();
					var pi_type,pi_coords,coords,coord_left,coord_top;

					pi_type=this.parent.box.getType();
					pi_coords=$(this.parent.idtag).getCoordinates();
					coords=$(this._idtag).getCoordinates();

					if (pi_type == "h") {
						if (pi_coords.left>coords.width && pi_coords.right+coords.width>bws.width) coord_left=pi_coords.right-coords.width;
						else coord_left=pi_coords.left;
						if (pi_coords.top-coords.height>bws.height-(pi_coords.bottom+coords.height)) coord_top=pi_coords.top-coords.height;
						else coord_top=pi_coords.bottom;
					}
					else {
						var pb_coords=$(this.parent.box._idtag).getCoordinates();
						pi_coords.left=pb_coords.left;
						pi_coords.right=pb_coords.right;
						if (pi_coords.left>coords.width && pi_coords.right+coords.width>bws.width) coord_left=pi_coords.left-coords.width;
						else coord_left=pi_coords.right;
						coord_top=pi_coords.top;
						if (this.offsetObjectV) {
							var offsets=this.offsetObjectV.getOffsets();
							coord_left+=offsets.x;
							coord_top+=offsets.y;
						}
					}
					this._left=coord_left;
					this._top=coord_top;
					if (this._width==0 || this._height==0) {
						this._width=coords.width-2;
						this._height=coords.height-2;
					}
				}
				if (this.offsetObject) {
					var offsets=this.offsetObject.getOffsets();
					this._left+=offsets.x;
					this._top+=offsets.y;
				}
				this._render(false,this._left,this._top,0,0,this._left,this._top,this._width,this._height);
				$(this.parent.idtag).addClass(this.props.pitem.styles.active); 
			}
			else return;
		}
		this.hidden=false;
		this.parent.box._selectedItem=this.parent;
	};

	// the better way to fade
	this.fade=function() {
		if (!this.hidden) {
			if (this.parent) {
				if (this._width==0 || this._height==0) {
					var bws=this.browserWS();
					var pi_type,pi_coords,coords,coord_left,coord_top;

					pi_type=this.parent.box.getType();
					pi_coords=$(this.parent.idtag).getCoordinates();
					coords=$(this._idtag).getCoordinates();

					if (pi_type == "h") {
						coord_left=pi_coords.left;
						if (pi_coords.top-coords.height>bws.height-(pi_coords.bottom+coords.height)) coord_top=pi_coords.top-coords.height;
						else coord_top=pi_coords.bottom;
					}
					else {
						if (pi_coords.left>coords.width && pi_coords.right+coords.width>bws.width) coord_left=pi_coords.left-coords.width;
						else coord_left=pi_coords.right;
						coord_top=pi_coords.top;
					}
					this._left=coord_left;
					this._top=coord_top;
					this._width=coords.width;
					this._height=coords.height;
				}
				this._render(true,this._left,this._top,0,0,this._left,this._top,this._width,this._height);
				$(this.parent.idtag).removeClass(this.props.pitem.styles.active); 
			}
			else return;
		}
		this.hidden=true;
		this._selectedItem=null;
	};

}

function Menu(name,parent,type)
{
	DropDown.call(this,name,parent,type);

	this.props={transition:"Fx.Transitions.linear",
				timeouts:{transition:50, show:200, fade:1000},
				box:{prefix:"menu_", styles:{h:"menu_hbox", v:"menu_vbox", hf:"menu_hbox_fixed", vf:"menu_vbox_fixed"}},
				item:{prefix:"item_", styles:{h:"menu_hitem", v:"menu_vitem"}},
				pitem:{styles:{active:"menu_a_item",inactive:"menu_i_item"}}};

	this.writeTo=function(container,container100) {
		if (container == undefined) container=document;
		this.writeHtmlTo(container,true,container100);
		this.activateItems();
	};
}
Menu.prototype=new DropDown();

function List(name,parent,type)
{
	DropDown.call(this,name,parent,type);

	this.props={transition:"Fx.Transitions.linear",
				timeouts:{transition:50, show:200, fade:1000},
				box:{prefix:"list_", styles:{h:"list_hbox", v:"list_vbox"}},
				item:{prefix:"item_", styles:{h:"list_hitem", v:"list_vitem"}},
				pitem:{styles:{active:"list_a_item",inactive:"list_i_item"}}};

	this.parent={idtag:parent, box:{_active: false,
									_selectedItem: null,
									getType: function(){ return "h";},
									_clearTC: function(){},
									_setTC: function(){}}}; // assume parent is DOM element or DOM element id

	this._rememberPos=false;

	this.writeTo=function(container) {
		if (container == undefined) container=document;
		this.writeHtmlTo(container,true);
		this.activateItems();
		this.hidden=true;
	};
}
List.prototype=new DropDown();