// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// _r JavaScript menu builder library
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Version 0.1.1
// 0.1.0 - First working version
// 0.1.1 - Separate the Root Object ( _r ) and the Node Objects ( _n )
// Tested in IE 6.0, Firefox 3.0.5, FireFox 3.0.13, Opera 9.10
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

var _ = new _r()		// create an instance of the Root Object

// Node Object

function _n(name) {
   this._name = name
   this._R = null		// _R - a reference to a "real" (implemented) object
   this._U = null		// _U - a reference to the upper node
   this._P = null		// _P - a reference to the parent element
   this._L = null		// _L - a reference to the lower mode
   this._C = new Array()	// _C - an array of references to the child nodes
   this._C.length = 0 
   this._N = new Array()	// _N - an array of references to the real child elemets
   this._N.length = 0 
   this._S = null;		// default style
   this._T = timeoutStack.length		// save the timeout stack element seq number
   timeoutStack[timeoutStack.length] = this	// reference to this element from the timeout stack
   this._tid = 0		// active timeout id 
   this._opacity = 100		// 0 - invisible; 100 - fully visible
   this.backgroundcolor = "red"
   return this
}

// Root Object

function _r() {
   this._name = "_r root"
   this._o		= null; // last object processed by one of the functions of the Root Node
   this.cssMenu 	= "padding:0;margin:0;list-style-type:none;float:left;visibility:visible;background-image:url(../images/bar.jpg);background-repeat: repeat-x;";
   this.cssMenuTop 	= "float:left;width:140px;position:relative;text-align:center;color:#666666;border-right:1px solid #ffffff;padding:4px 0px 0px 3px;font-weight:bolder;font-size:10px;height:18px;";
   this.cssMenuHide 	= "position:absolute;height:0;top:20px;left:0; visibility:hidden;";
   this.cssMenuSub 	= "float:left;width:140px;height:auto;position:relative;text-align:left; border-bottom: 1px solid #FFF;background:gray;padding-left:3px;color:white;font-family:verdana;font-size:9px;font-weight:normal;"
   this.backgroundcolor = "red"

   this.fadetime        = 160
   this.fadesteps       = 10
   this.fadedelay       = this.fadetime / this.fadesteps
   this.opacitygradient = 100 / this.fadesteps
   return this

   return this

}

//---------------------------------------------------
// "is" - create a new NODE object
//---------------------------------------------------
_r.prototype.is = function(id) {
   var el = document.getElementById(id)

   var node = new _n(id)	// create a new node object
   this._o = node		// remember last object processed

   node._R = el  		// reference forward
   el._R = node  		// reference back
   this._addEvent(el,'mouseover','onmouseover')._addEvent(el,'mouseout','onmouseout');

   // make all child nodes point to this (parent) node
   var childs = el.childNodes
   for (i=0;i<childs.length;i++)
   {
      var child = childs[i]

      if (child.nodeType == 1) {
         child._parent = node  	// include a reference to the parent node
         node._N[node._N.length] = child	// save reference to the real sub-element
      }
   }
   return this;
}

//---------------------------------------------------
// insideOf - put current node "inside" another node
//---------------------------------------------------
_r.prototype.insideOf = function(o) {
   this._o._P = o   		// reference to the parent object
   o._C[o._C.length] = this._o	// add child to the parent
   return this
}

//------------------------------------------------------------
// linkedTo - make current node subordinate to the upper node
//------------------------------------------------------------
_r.prototype.linkedTo = function(o) {
   this._o._U = o   		// reference to the upper object
   o._L = this._o   		// reference to this node from the upper node
   return this
}

//------------------------------------------------------------
// css - save the default style of an element
//------------------------------------------------------------
_r.prototype.css = function(css) {
   var newcss = this._o._R.style.cssText + ' ' + css	// add provided stype to previously defined
   this._o._S = newcss;			// save original style
   this._o._R.style.cssText = newcss;	// set the style of "real" element
   return this;
}

//------------------------------------------------------------
// fin - finish building an object
//------------------------------------------------------------
_r.prototype.fin = function() {
   return this._o;
}

//------------------------------------------------------------
// _addEvent - attach an event listener to a "real" element
//------------------------------------------------------------
_r.prototype._addEvent = function(el,e,IEe) {
   if (el.addEventListener) {
      eval("el.addEventListener('"+e+"',this._"+e+",false)")
   }
   else {
      eval("el.attachEvent('"+IEe+"',this._"+e+")")
   }
   return this
}

//------------------------------------------------------------
// _mouseover - 
//------------------------------------------------------------
_r.prototype._mouseover = function(e) {
   var targ = eventTarget(e);		// "real" object 
   if (targ == null) {return}		// this guy is not a part of our structure

   targ.style.background = _.backgroundcolor
   var node = targ._R
   targ.style.background = node.backgroundcolor
   if (node._L) {clearTimeout(node._L._tid); node._L._tid = 0; _._setOpacity(node._L,100);}	// make lower node visible
   if (node._P) {clearTimeout(node._P._tid); node._P._tid = 0; _._setOpacity(node._P,100);}	// remove timeout, if any, for the parent node
   _.mouseover(targ)
}

//------------------------------------------------------------
// _mouseout - 
//------------------------------------------------------------
_r.prototype._mouseout = function(e) {
   var targ = eventTarget(e);
   if (targ == null) {return}		// this guy is not a part of our structure

   var node = targ._R
   if (node._C.length == 0) {
      _._cssRestore(node)	// restore style of this node if it's not a parent (e.g. ignore parent's node mouseout
   }
   // restore style of the lower node, if any
   if (node._L) {
      if (node._L._tid > 0) {clearTimeout(node._L._tid)}
      var fn = "processTimeout("+node._L._T+")"
      node._L._tid = setTimeout(fn,_.fadedelay)
   }

   if (node._P && node._P._U) {
      if (node._P._tid > 0) {clearTimeout(node._P._tid)}
      var fn = "processTimeout("+node._P._T+")"
      node._P._tid = setTimeout(fn,_.fadedelay)
   }
   _.mouseout(targ)		// execute user exit
}

//------------------------------------------------------------
// _processTimeout - process timeout for specified object
//------------------------------------------------------------
_r.prototype._processTimeout = function(o) {
   if (o._tid > 0) {
      if (o._opacity < 10) {
         o._opacity = 100
         o._tid = 0	// no timeouts for this object
         _._cssRestore(o)
      }
      else {
         o._opacity = o._opacity - _.opacitygradient
         _._setOpacity(o,o._opacity)
         var fn = "processTimeout("+o._T+")"
         o._tid = setTimeout(fn,_.fadedelay)
      }
   }
}

//------------------------------------------------------------
// startFading - process timeout for specified object
//------------------------------------------------------------
_r.prototype.startFading = function(o) {
   this._o = o
   if (o._tid > 0) {clearTimeout(o._tid)}
   this._setOpacity(o,100)
   var fn = "processFade("+o._T+")"
   o._tid = setTimeout(fn,2000)
}

//------------------------------------------------------------
// _processFade - process timeout for specified object
//------------------------------------------------------------
_r.prototype._processFade = function(o) {
   if (o._tid > 0) {
      o._opacity = o._opacity - _.opacitygradient
      if (o._opacity < 0) {
         o._opacity = 0
         o._tid = 0	// no timeouts for this object
      }
      else {
         _._fade(o,o._opacity)
         var fn = "processFade("+o._T+")"
         o._tid = setTimeout(fn,_.fadedelay)
      }
   }
}

//------------------------------------------------------------
// _fade - set opacity "v" for node "o" and its subnodes
//------------------------------------------------------------
_r.prototype._fade = function(o,v) {

   o._R.style.opacity = v/100;
   o._R.style.filter = 'alpha(opacity=' + v + ')';

//   for (i=0;i<o._N.length;i++)
//   {
//      var child = o._N[i]
//      if (child.style) {
//         child.style.opacity = v/100;
//         child.style.filter = 'alpha(opacity=' + v + ')';
//      }
//   }

   this._o = o;		// save last processed element
   o._opacity = v;
   if (v == 100) {o._R.style.visibility=""}
   if (v == 0) {o._R.style.visibility="hidden"}
}


//------------------------------------------------------------
// _cssRestore - restore the default style of a node
//------------------------------------------------------------
_r.prototype._cssRestore = function(o) {
   o._R.style.cssText = o._S		// restore original style
   _.mouseout(o._R)			// execute user exit
}

//------------------------------------------------------------
// setOpacity - set opacity "v" for node "o"
//------------------------------------------------------------
_r.prototype._setOpacity = function(o,v) {
   this._o = o;		// save last processed element
   o._R.style.opacity = v/100;
   o._R.style.filter = 'alpha(opacity=' + v + ')';
   o._opacity = v;
   if (v == 100) {o._R.style.visibility=""}
   if (v == 0) {o._R.style.visibility="hidden"}
}

//---------------------------------------------------
// user exits for events
//---------------------------------------------------

_r.prototype.mouseover = function(targetObject) {}

_r.prototype.mouseout = function(targetObject) {}

//---------------------------------------------------
// timeout handling 
//---------------------------------------------------

var timeoutStack = new Array()	// a stack of timeout events

function processTimeout (i) {
   _._processTimeout(timeoutStack[i])
}

function processFade (i) {
   _._processFade(timeoutStack[i])
}

//---------------------------------------------------
// debug function to display object's properties
//---------------------------------------------------

function dumpProps(obj) {
   // Go through all the properties of the passed-in object
   for (var i in obj) {
      var msg = i + "\n" + obj[i];
      if (!confirm(msg)) { return; }
   }
}

//---------------------------------------------------
// eventTarget - get the target object of an event
//---------------------------------------------------

function eventTarget(e)
{
var targ;
if (!e)
  {
  var e=window.event;
  }
if (e.target)
  {
  targ=e.target;
  }
else if (e.srcElement)
  {
  targ=e.srcElement;
  }
if (targ.nodeType==3)
  {
  targ = targ.parentNode; // Safari bug
  }

// if this target is not an explicitly referenced child node of one of our objects - re-target it
   if (!targ._R) {				// this guy is not a part of our structure (doesn't have _R)
	if (!targ._parent) {return null}	// and he's not pointing to our object - return null
	targ = targ._parent._R			// otherwise re-target to our parent object
   }
  return targ;
}

//---------------------------------------------------
// END of _r
//---------------------------------------------------

//---------------------------------------------------
// Build the top menu
//---------------------------------------------------
window.onload = function() 
{
	buildMenu();
}
function buildMenu()
{
   var A = _.is("menu").css(_.cssMenu).fin();

   for (var i=1;i<12;i++) {
	var b = "b_top" + i;
	var c = "c_menu" + i;
	if (document.getElementById(b)) {
	   var bb = _.is(b).insideOf(A).css(_.cssMenuTop).fin();
	   bb.backgroundcolor = null
	   if (document.getElementById(c)) {
	      var cc = _.is(c).linkedTo(bb).css(_.cssMenuHide).fin()
	      for (var j=1;j<24;j++) {
	         var d = "d_" + i + "_" + j;
	         if (document.getElementById(d)) {
		    var dd = _.is(d).insideOf(cc).css(_.cssMenuSub).fin()
		 }
	      }
	   }
	}
   }
}

