var
$_D									= document,
$_W									= window,

/**
 *	Object detects and store browser information
 *
 * @author MMX <mmx@vitcompany.com>
 * @package VITFramework
 * @version 0.2
 */
$Browser						= new function(){
	var b								= navigator.userAgent;
	this.op							= (/opera/i.test(b));							//	Opera
	this.ff							= (/firefox/i.test(b));						//	Firefox
	this.sf							= (/safari/i.test(b));						//	Safari
	this.ie							= (/msie/i.test(b) && !this.op);	//	IE
	this.v							= parseFloat(											//	Version
		(this.ie)
			? navigator.userAgent.replace(/^.*?MSIE\s([\d\.]+).*?$/, '$1')
			: (this.ff)
					? navigator.userAgent.replace(/^.*?Firefox\/([\d\.]+)$/, '$1')
					: navigator.appVersion);
},

/**
 *	AutoStart object for:
 *	- register & call `onload` function
 *
 * @author MMX <mmx@vitcompany.com>
 * @package VITFramework
 * @version 0.2
 */
$Loader					= new function(){
	var
	/**
	 *	Detect is document load completed
	 *	@var boolean
	 */
	bDocLoaded					= 0,
	/**
	 *	Array of functions, which called on document load complete
	 *	@var array
	 */
	aHandlers						= [],

	/**
	 *	Call functions from array
	 *	@param array aHandlers Array with functions
	 */
	_callHandlers				= function (aHandlers, fHandler)
	{
		while(fHandler = aHandlers.shift())
			fHandler();
	};

	/**
	 *	Register functions, which called on document load complete
	 *	@param function fOnload : called on document load complete
	 */
	this.set						= function(fOnload)
	{
		if ('function' == typeof fOnload)
			(bDocLoaded) ? fOnload() : aHandlers[aHandlers.length] = fOnload;
	};

	/**
	 *	Call functions, registered by `this.set` method, when document load completed
	 */
	$_W.onload					= function()
	{
		bDocLoaded = 1;
		_callHandlers(aHandlers);
	};
};

/**
 *	Р”РѕР±Р°РІР»СЏРµРј С„СѓРЅРєС†РёРё СЂР°Р±РѕС‚С‹ СЃ DOM РµР»РµРјРµРЅС‚Р°РјРё
 *
 *	@author MMX <mmx@vitcompany.com>
 *	@package VITFramework
 *	@version 0.3
 */
/**
 *	Check that the argument is a DOM Element
 *	@param mixed m something
 *	@return boolean
 */
function isNode(m)
{
	return ((m) && (('undefined' != typeof m.nodeType) || (m.hasAttribute && m.hasAttribute('nodeType'))));
};

/**
 *	Cover for document.getElementById()
 *	@param string m DOMNode id
 *	@return DOMNode
 */
function byId(m)
{
	return (m && 'string' == typeof m) ? $_D.getElementById(m) : null;
};

/**
 *	Select from specified DOMNode elements By TagName
 *	@param string sTag elements tag name
 *	@param DOMNode [option] dNode startpoint
 *	@param boolean [option] bOne return first element
 *	@return DOMNode collection
 */
function byTag(sName, dNode, bOne)
{
	dNode = isNode(dNode) ? dNode : $_D;
	var aResult = ('*' == sName && $Browser.ie && 6 > $Browser.v)
		? dNode.all : dNode.getElementsByTagName(sName);
	return (aResult.length) ? (bOne) ? aResult[0] : aResult : null;
};

/**
 *	Select from specified DOMNode elements By ClassName
 *	@param string sName elements class name
 *	@param DOMNode [option] dNode startpoint
 *	@param boolean [option] bOne return first element
 *	@return DOMNode collection
 */
function byClass(sName, dNode, bOne)
{
	dNode = byTag('*', dNode);
	sClassName = ' ' + sName + ' ';
	var aResult = [];
	for (var i = 0; i < dNode.length; i ++)
	{
		if ( -1 != (' ' + dNode[i].className + ' ').indexOf(sName) )
		{
			aResult.push(dNode[i]);
		}
	}
	return (aResult.length) ? (bOne) ? aResult[0] : aResult : null;
};

/**
 *	Select from specified DOMNode elements By Name
 *	@param string sName elements name
 *	@param DOMNode [option] dNode startpoint
 *	@param boolean [option] bOne return first element
 *	@return DOMNode collection
 */
function byName(sName, dNode, bOne)
{
	var aResult = [];
	if (dNode)
	{
		dNode = byTag('*', dNode);
		for (var i = 0; i < dNode.length; i ++)
		{
			if (sName == dNode[i].name)
			{
				aResult.push(dNode[i]);
			}
		}
	}
	else
	{
		aResult = $_D.getElementsByName(sName);
	}
	return (aResult.length) ? (bOne) ? aResult[0] : aResult : null;
};

/**
 *	Add to DOM Element class
 *	@param DOMNode dNode target node
 *	@param string sClass class name
 *	@param boolean bReplace replace current element class
 *	@return DOMNode dNode
 */
function _classSet(dNode, sClass, bReplace)
{
	if ('string' == typeof sClass && isNode(dNode) &&
		(!_classHas(dNode, sClass) || bReplace)
	)
	{
		dNode.className = ((!bReplace && dNode.className) ? dNode.className + ' ' : '') + sClass;
	}
	return dNode;
};
/**
 *	Check that the node has specified className
 *	@param DOMNode dNode target node
 *	@param string sClass class name
 *	@return boolean
 */
function _classHas(dNode, sClass)
{
	return ('string' == typeof sClass && isNode(dNode) && -1 != (' ' + dNode.className + ' ').indexOf(' ' + sClass + ' '));
};
/**
 *	Remove class from DOMNode
 *	@param DOMNode dNode target node
 *	@param string [option] sClass class name
 *	@return DOMNode dNode
 */
function _classUnset(dNode, sClass)
{
	if (isNode(dNode))
	{
		dNode.className = (sClass && 'string' == typeof sClass)
			? dNode.className.replace( new RegExp('^(.*?)\\s?'+sClass+'(.*?)$') ,  '$1$2' )
			: '';
		dNode.className = dNode.className.replace( new RegExp('^\\s+?(.*?)\\s+?$'), '$1');
	}
	return dNode;
};

/**
 *	Add to DOM Element style attributes
 *	@param DOMNode dNode target node
 *	@param array aAttrs attributes (Key=>Attr, Value=>AttrValue)
 *	@return DOMNode dNode
 */
function _styleSet(dNode, aAttrs)
{
	if (isNode(dNode) && 'object' == typeof aAttrs)
	{
		for (var i in aAttrs)
		{
			dNode.style[i] = aAttrs[i];
		}
	}
	return dNode;
}


/**
 *	Provide displaying sub-menues
 *		on mouseOver/ mouseOut with timeout
 *
 * @author MMX <mmx@vitcompany.com>
 * @package VITFramework
 * @version 0.2
 */
var $MenuOver				= new function()
{
	var th							= this;
	this.tHover					= null;
	this.dActive				= null;
	this.dOpen					= null;
	this.sCandidate			= null;
	this.aMenues				= {};


	this.init						= function(sMenuId)
	{
		var aNodes = byTag('a', byId(sMenuId));
		if (!aNodes) return;
		var dNode, iLeft;
		for (var i = 0; i < aNodes.length; i ++)
		{
			if (aNodes[i].id && (dNode = byId('sub:'+aNodes[i].id)))
			{
				aNodes[i].onmouseover	= this.eHover;
				aNodes[i].onmouseout	= this.eOut;
				this.aMenues[aNodes[i].id] = dNode;
				dNode.onmouseover			= this.eHover;
				dNode.onmouseout			= this.eOut;
				if (!_classHas(dNode, 'dn'))		this.dOpen = dNode;
			}
		}
	};


	this.eHover					= function()
	{
		th._stopTimeout();
		if (th.aMenues[this.id])		th.sCandidate = this.id;
		else							return;
		if (th.dActive)		return th.slowHover();
		th.tHover = setTimeout(th.slowHover, 250);
	};
	this.slowHover			= function()
	{
		th._stopTimeout();
		if (th.dActive)			_classSet(th.dActive, 'dn');
		else if (th.dOpen)	_classSet(th.dOpen, 'dn');
		if (th.sCandidate)
		{
			th.dActive = th.aMenues[th.sCandidate];
			_classUnset(th.dActive, 'dn');
		}
	};

	this.eOut						= function()
	{
		th._stopTimeout();
		if (th.dActive)			th.tHover = setTimeout(th.slowOut, 250);
	};
	this.slowOut				= function()
	{
		th._stopTimeout();
		if (th.dActive)
		{
			_classSet(th.dActive, 'dn');
			th.dActive = null;
		}
	};

	this._stopTimeout		= function()
	{
		if (this.tHover)
		{
			clearTimeout(this.tHover);
			this.tHover = null;
		}
	}
};

$Loader.set(function(){$MenuOver.init('mm')});
