/*
	cDropMenu (c) Kirill Losev ( [test] ) , March 2005
				  http://www.eax.ru
	Javascript menu with slide and fade effects on selecting
	Thanks for ideas of realization: 
		Dmitry Koterov (http://forum.dklab.ru/users/DmitryKoterov/) 
		Alexander Shurkayev (http://htmlcoder.visions.ru)
		http://www.mediatemple.net 

	Do not remove this comment if you want to use script!
	Не удаляйте данный комментарий, если вы хотите использовать скрипт!
	
	version: 0.9
	 * No time to complete all i want to do
	 * First public release
*/

cDropMenu.instances = [];
cDropMenu.submenu_image = {	url: '../images/menu-arrow.gif ', width : 8, height : 10 };
cDropMenu.shadow_level = 30;

cDropMenu.AttachEvent = function (oObject,sEvent,fListener) {
	if ( oObject.addEventListener ) 
		return oObject.addEventListener(sEvent,fListener,false);
	else if ( oObject.attachEvent )
		return oObject.attachEvent('on' + sEvent,fListener);
	else 
		return false;
}

cDropMenu.GetRelativeCoord = function (oObject) {
  var Top = oObject.offsetTop;
  var Left = oObject.offsetLeft;
  while (oObject.offsetParent != null) {
    oObject = oObject.offsetParent;
    Top += oObject.offsetTop; 
    Left += oObject.offsetLeft; 
  };  
  return new Array(Top,Left);
};

cDropMenu.SetTransparencity = function (oDomObject, iLevel) {
	if ( typeof oDomObject.style.filter != 'undefined' )  {
		oDomObject.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=" + iLevel + ")";
		return true;
	}
	if ( typeof oDomObject.style.MozOpacity != 'undefined' ) { 
		oDomObject.style.MozOpacity = iLevel / 100;
		return true;
	}
	return false;
}

function cDropMenu() {
	// public properties
	this.id = cDropMenu.instances.length;
		cDropMenu.instances[this.id] = this;
	this.items = new Array();
	// align position @ string
	// 'bottom': align to bottom of object
	// 'right' : align to right of object
	this.AlignPosition = 'bottom'; 
	// animation type @ string:
	// 'slide' : like windows98 default menu animation,
	// 'fade'  : like windows2000 default menu animation (too buggy now)
	this.AnimationType = 'slide'; 
	// Hide timeout @ integer
	// time in milliseconds to hide when mouseover
	this.HideTimeout = 500;

	this.isOpen = false;
	this.Parent = null;
	this.HideTimer = null;

	// private variables
	var animation_timer = null;
	var _this = this; 	// small hack ? 
	
	// constructor
	// create menu layout
	var main_div = document.createElement('div'); // main container
	with ( main_div )  {
		style.top = 0;
		style.left = 0;
		style.position = 'absolute';
		style.visibility = 'hidden';
		style.overflow = 'hidden';
	}		
	var holder_div = document.createElement('div'); // sliding container, with items and shadow
	with ( holder_div ) {
		className = 'dropmenu';
		style.position = 'relative';
	}
	var shadow_div = document.createElement('div'); // shadow layer, to emulate shadow
	with ( shadow_div ) {
		className = 'shadow';
		style.position = 'absolute';
	}
	var items_table = document.createElement('table'); // items table
	var items_table_body =  document.createElement('tbody'); 
	with (items_table) {
		border = 0;
		cellPadding = 0;
		cellSpacing = 0;
		className = 'items';
		style.position = 'relative';
		items_table.style.zIndex = 1;
	}	
	// construct structure
	items_table.appendChild(items_table_body);
	holder_div.appendChild(shadow_div);
	holder_div.appendChild(items_table);
	main_div.appendChild(holder_div);
	// assigning to body
	document.body.appendChild(main_div);
	
	// public functions 
	// function RealignContent()
	// realign internal menu content, like correct shadow position
	this.RealignContent = function () {
		shadow_div.style.width = items_table.offsetWidth + 'px';
		shadow_div.style.height = items_table.offsetHeight + 'px';
		
		shadow_div.style.top = '2px';
		shadow_div.style.left = '2px';
		
		holder_div.style.width = items_table.offsetWidth + 2 + 'px';
		holder_div.style.height = items_table.offsetHeight + 2 + 'px';
		main_div.style.height = items_table.offsetHeight + 5 + 'px';
		main_div.style.width = items_table.offsetWidth + 5 + 'px';
		if ( (_this.AnimationType != 'fade') | (typeof holder_div.style.filter == 'undefined')  ) {
			// not fade, or fade but not IE
			// strange bug here ... shadow is undercovering items ... i don't understand why.
			cDropMenu.SetTransparencity(shadow_div, cDropMenu.shadow_level);
		}
		switch  ( this.AnimationType ) {
			case 'slide': {
				if ( this.Parent == null ) holder_div.style.top = - holder_div.offsetHeight + 'px';
									  else holder_div.style.left = - holder_div.offsetWidth + 'px';
				break;
			}
			case 'fade' : {
				cDropMenu.SetTransparencity(main_div, 0);
				break;
			}
		}
	}
	// function addItem(sCaption, sUrl)
	// sCaption - item caption only text may be here
	// sUrl - url to redirection
	this.addItem = function (sCaption, sUrl) {
		var item_id = this.items.length; 
		var menu_item = new cDropMenuItem (sCaption, sUrl);
		menu_item.id = item_id;
		menu_item.Parent = this;
		this.items[item_id] = menu_item
		items_table_body.appendChild(menu_item.getItemRow());
		this.RealignContent();
		return this.items[item_id];
	}
	this.SetItemsWidth = function (iNewWidth) {
		items_table.style.width = iNewWidth + 'px';
		this.RealignContent();
}
	
	this.AttachTo = function (oObject) {
		cDropMenu.AttachEvent(oObject,'mouseover', attached_mouseover);
		cDropMenu.AttachEvent(oObject,'mouseout', attached_mouseout);
	}	
	this.AlignTo = function (oObject) {
		var object_coord = cDropMenu.GetRelativeCoord(oObject);
		switch (this.AlignPosition) {
			case 'bottom' : { object_coord[0] += oObject.offsetHeight; break; }
			case 'right'  : { object_coord[1] += oObject.offsetWidth; break; }
		}
		main_div.style.top = object_coord[0] + 'px';
		main_div.style.left = object_coord[1] + 'px';
	}
	this.Show = function () {
		this.isOpen = true;
		animation_start();
	}
	this.Hide = function () {
		this.ClearTimers();
		this.isOpen = false;
		animation_start();
	}
	this.TimeoutHide = function () {
		this.ClearTimers();
		main_div.style.zIndex = 0;
		if ( !this.isOpen )	return false;
		var timeout_hide = ( this.Parent != null ) ? Math.round(this.HideTimeout / 3) : this.HideTimeout;
		this.HideTimer = window.setTimeout('cDropMenu.instances[' + this.id + '].Hide();', timeout_hide);
		if ( this.Parent != null ) {
			this.Parent.setSelected( false );
		}

	}
	this.CancelTimeoutHide = function () {
		window.clearTimeout(this.HideTimer);
		this.HideTimer = null;
		if ( this.Parent != null ) 
			this.Parent.setSelected( true );
	}
	this.TimeoutShow = function () {
		if ( !this.isOpen ) {
			this.ShowTimer = window.setTimeout('cDropMenu.instances[' + this.id + '].Show();', 250);
		}
	}
	this.CancelTimeoutShow = function () {
		window.clearTimeout(this.ShowTimer);
		this.ShowTimer = null;
	}
	this.ClearTimers = function () {
		window.clearTimeout(this.HideTimer);
		this.HideTimer = null;
		window.clearTimeout(this.ShowTimer);
		this.ShowTimer = null;		
	}
	
	// private functions
	function animation_start () {
		animation_timer = new cStepTimer();

		switch ( _this.AnimationType ) {
			case 'slide' : {
				var moving_axis = 0;
				if ( _this.Parent == null ) {
					// default moving for top to bottom
					moving_axis = holder_div.offsetHeight;
					animation_timer.onStep = animation_slidetop_step;
				} else {
					// moving from left to right
					moving_axis = holder_div.offsetWidth;
					animation_timer.onStep = animation_slideleft_step;
				}
				if ( _this.isOpen ) {
					animation_timer.startPoint =  (- moving_axis);
					animation_timer.stopPoint = 0;
					main_div.style.zIndex = 1;
				} else {
					animation_timer.startPoint = 0;
					animation_timer.stopPoint = (- moving_axis);
					main_div.style.zIndex = 0;
				}
				break;
			}
			case 'fade' : {
				if ( _this.isOpen ) {
					animation_timer.startPoint = 0;
					animation_timer.stopPoint = 100;						
				} else {
					animation_timer.startPoint = 100;
					animation_timer.stopPoint = 0;						
				}
				animation_timer.onStep = animation_fade_step;
				break;				
			}
			case 'none' : {
				animation_timer.startPoint = 0;
				animation_timer.stopPoint = 1;
				animation_timer.desiredTime = 1;
				break;
			}
		}

		// reset to default step
		animation_timer.onStep(animation_timer.startPoint);
		animation_timer.onEnd = animation_stop;
		animation_timer.Start();
		if ( _this.isOpen ) {
			main_div.style.visibility = 'visible';
		}
	}
	function animation_stop () {
		if ( !_this.isOpen ) 
			main_div.style.visibility = 'hidden';
	}
	function animation_slidetop_step ( value ) {
		holder_div.style.top = value + 'px';
	}
	function animation_slideleft_step ( value ) {
		holder_div.style.left = value + 'px';
	}
	function animation_fade_step ( value ) {
		cDropMenu.SetTransparencity(main_div, value);
	}
	function attached_mouseover (oEvent) {
		if ( _this.isOpen ) {
			_this.CancelTimeoutHide();
			return true;
		}
		var oTarget = ( window.event ) ? window.event.srcElement : oEvent.target;
		_this.AlignTo(oTarget);
		_this.Show();
	}
	function attached_mouseout (oEvent) {
		_this.TimeoutHide();
	}
}


function cDropMenuItem(caption, url) {
	this.caption = caption;
	this.url = url;
	this.id = -1;
	this.Parent = null;
	this.Submenu = null;
	
	var _this = this;
	
	with (document) {
		var caption_cell = createElement('td');
		caption_cell.appendChild(createTextNode(caption));
		caption_cell.noWrap = true;
		var submenu_cell = createElement('td');
		var item_row  = createElement('tr');
		item_row.appendChild(caption_cell);
		item_row.appendChild(submenu_cell);
	} 

	function row_mouseover () {
		_this.setSelected( true );
		if ( _this.Submenu != null ) {
			_this.Submenu.AlignTo(this);
			_this.Submenu.TimeoutShow();
		}
	}
	function row_mouseout () {
		_this.setSelected( false );
		if ( _this.Submenu != null ) {
			_this.Submenu.TimeoutHide();
		}
	}
	function caption_click () {
		_this.setSelected( false );
		window.location.href = _this.url;
	}
	
	// setting mouseover & mouseout	
	item_row.onmouseover = row_mouseover;
	item_row.onmouseout = row_mouseout;
	caption_cell.onclick = caption_click;


	// public functions
	this.addSubmenu = function () {
		this.Submenu = new cDropMenu();
		with ( this.Submenu ) {
			Parent = this;
			AlignPosition = 'right';
		}
		
		var img = document.createElement('img');
		img.src = cDropMenu.submenu_image.url;
		img.alt = '';
		img.width = cDropMenu.submenu_image.width;
		img.height = cDropMenu.submenu_image.height;
		submenu_cell.appendChild(img);
		this.Parent.RealignContent();
		return this.Submenu;
	}
	this.getItemRow = function () {
		return item_row;
	}
	this.setSelected = function (value) {
		if ( value ) {
			item_row.className = 'selected';
			this.Parent.CancelTimeoutHide();
		} else {
			item_row.className = '';
			this.Parent.TimeoutHide();
		}
	}
}

cStepTimer.instances = [];
cStepTimer.DefaultTime = 150;
cStepTimer.TimerResolution = 10;
cStepTimer.TimerID = null;

function cStepTimer(start_point, stop_point, desired_time) {	
	this.startPoint = start_point;
	this.stopPoint = stop_point;
	if ( typeof desired_time == 'undefined' ) desired_time = cStepTimer.DefaultTime;
	this.desiredTime = desired_time;
	this.onStep = null;
	this.onEnd = null;
	
	
	this.Start = function () {
		this.direction = this.startPoint < this.stopPoint;
		this.currentPosition = this.startPoint;
		if ( this.direction ) {
			this.step = Math.round ( Math.abs(this.stopPoint - this.startPoint) / (this.desiredTime / cStepTimer.TimerResolution));
		} else {
			this.step = Math.round (  - Math.abs(this.startPoint - this.stopPoint) / (this.desiredTime / cStepTimer.TimerResolution));
		}	
		cStepTimer._add( this );
	}
	this.Stop = function () {
		cStepTimer._remove ( this );
	}

	this.Step = function () {
		this.currentPosition += this.step;
		//alert(this.currentPosition);
		var completed_steps = false;
		completed_steps = ( this.direction ) ? this.currentPosition > this.stopPoint : this.currentPosition < this.stopPoint;
		if ( completed_steps ) {
			if ( this.onStep ) this.onStep(this.stopPoint);
			if ( this.onEnd ) this.onEnd();
			cStepTimer._remove(this);
			return;
		}

		if ( this.onStep ) this.onStep(this.currentPosition);
	} 
}

cStepTimer._add = function ( instance ) {
	this.instances[this.instances.length] = instance;
	if ( this.instances.length == 1 ) {
		this.TimerID = window.setInterval("cStepTimer._tick_all()" , cStepTimer.TimerResolution);
	};
}
cStepTimer._remove = function ( instance ) {
  for (i=0; i<this.instances.length; i++) {
    if (this.instances[i] == instance) {
	    this.instances = this.instances.slice(0,i).concat (this.instances.slice(i+1)); 
	    break;
    };
  };
  if (this.instances.length == 0) {
    window.clearInterval(this.TimerID);
    this.TimerID = null;
  };
};
cStepTimer._tick_all = function () {
  for (i=0; i<this.instances.length; i++) {
    this.instances[i].Step(); 
  };
};