function Menu( menuDivID, varName, opts ){
  this.menu = {id:-1,children:[]};
  this.objects=[];
  this.menuDiv = DOM.getObj( menuDivID );
  this.currentMenuPath = [];
  this.open = null;
  this.varName = varName;
  this.menuWidth = this.menuHeight = 0;
  this.options = {
    maxHeight:-1,
    backText:'Back',
    hideTimeout:1.5,
    useTimeout:true
  };

  if( opts ){
    for( var x in this.options ){
      if( typeof opts[x] != 'undefined' ) {
        this.options[x] = opts[x];
      }
    }
  }

  // functions
  this.toggle=function(idx){
    if( !idx ){
      idx = 0;
    }
    // clear timeout
    this.menuOver();

    this.open = !( this.menuDiv.style.display == '' );
    if( this.open && this.currentMenuPath.length == 0 ){
      this.show(0);
    } else if( this.open ) {
      this.show(this.currentMenuPath[this.currentMenuPath.length-1]);
    }
    this.menuDiv.style.display = ( this.open ? '' : 'none' );
  };
  this.init=function(){
    var uls = this.menuDiv.getElementsByTagName('ul');
    if(uls.length > 0){
      this.traverseTree(uls[0], this.menu);
    }else{
      Debug.dbg('cannot find ul');
    }
    uls[0].style.display = 'none';

    this.switchDiv = DOM.create( 'div', {} );
    this.menuDiv.appendChild( this.switchDiv );

    // get the height for first menu
    this.menuHeight = this.show(0);
    this.currentMenuPath.length = 0;

    // check height
    //this.menuHeight = this.menuDiv.offsetHeight;
    Debug.dbg( 'oh=' + this.menuDiv.offsetHeight );
    Debug.dbg( 'mh=' + this.menuHeight );
    Debug.dbg( 'maxh=' + this.options.maxHeight );
    if( this.options.maxHeight > -1 ){// && ( this.menuHeight == 0 || this.menuHeight > this.options.maxHeight ) ){
      this.menuHeight = this.options.maxHeight;
    }
    // set default height
    this.menuDiv.style.height = this.menuHeight + "px";
    
    // now hide it
    if( this.menuDiv.style.display == '' ){
      this.toggle();
    }
  };
  this.traverseTree=function(obj,parentMenu){
    // assumption obj = ul
    if( obj.nodeName.toLowerCase() != 'ul' ){
      return false;
    }

    // save each menu
    var idx = this.objects.length,
        mIdx = parentMenu.children.length;
    obj.className = 'menu';
    this.objects[idx] = obj;
    parentMenu.children[mIdx]={obj:obj,id:idx,children:[]};

    for( var i=0; i<obj.childNodes.length; i++ ){
      if( obj.childNodes[i].nodeName.toLowerCase() != 'li' ){
        // ff has #text elements
        continue;
      }
      var node = obj.childNodes[i],
          children = node.getElementsByTagName( 'ul' ),
          hc = ( children.length > 0 ),
          links = node.getElementsByTagName( 'a' ),
          link = ( links.length > 0 ? links[0] : null );

      // IE hover fix
      node.onmouseover = function(e){addClass( this, 'hover' );};
      node.onmouseout = function(e){removeClass( this, 'hover' );};

      if( hc ){
        if( link ){
          // ignore click
          link.onclick = new Function("return false");
        }
        var id=this.traverseTree( children[0], parentMenu.children[mIdx] );
        addClass( node, 'children');
        node.onclick = new Function( this.varName + '.show(' + id + ');return false');
      } else {
        node.onclick = link.onclick;
      }
    }

    return idx;
  };
  this.menuOver=function(e){
    if( this.tout ){
      clearTimeout(this.tout);
    }
  };
  this.menuOut=function(e){
    /*  Ignore the timeout */
    this.menuOver(e);
    if( this.options.useTimeout ){
      this.tout = setTimeout(this.varName + ".toggle()", this.options.hideTimeout * 1000);
    }
  };
  this.show=function(idx){
    if( !this.objects[idx] ){
      return false;
    }
    if( this.currentMenuPath.length == 1 && this.currentMenuPath[0] == idx ){
      return true;
    }
    
    this.switchDiv.innerHTML = '';
    var mH = this.menuHeight;

    while( this.currentMenuPath.length > 0 && this.currentMenuPath.indexOf( idx ) > -1 ){
      // while the index exists, try to remove it
      this.currentMenuPath.pop();
    }
    if( this.currentMenuPath.length > 0 ){
      // not main page, add back
      var back = DOM.create( 'div', {className:'menuback',innerHTML:this.options.backText} );
      back.onclick = new Function( this.varName + '.show(' + this.currentMenuPath[this.currentMenuPath.length-1] + ');return false' );
      this.switchDiv.appendChild( back );
      mH -= back.offsetHeight;
    }
    
    if( this.currentMenuPath.indexOf( idx ) == -1 ){
      // put it back in (or in the first time)
      this.currentMenuPath.push( idx );
    }

    var d = DOM.create('div', {position:'absolute'} ),
        o = DOM.create( 'ul', {className:'menu'} ),
        obj = this.objects[idx];

    this.switchDiv.appendChild( d );
    d.onmouseover = new Function(this.varName + ".menuOver()");
    d.onmouseout = new Function(this.varName + ".menuOut()");

    for( var i=0; i<obj.childNodes.length; i++ ){
      var node = obj.childNodes[i];
      if( node.nodeName.toLowerCase() != 'li' ){
        continue;
      }
      var li = DOM.create( 'li', {} ),
          a = DOM.create( 'a', {} ),
          links = node.getElementsByTagName( 'a' ),
          hc = (node.getElementsByTagName( 'ul' ).length > 0);
      if( links.length > 0 ){
        a.href = links[0].href;
        a.innerHTML = links[0].innerHTML;
        a.title = links[0].title;
      }
      a.onmouseover = links[0].onmouseover;
      a.onmouseout = links[0].onmouseout;
      if( links[0].target ){
        a.target = links[0].target;
      }
      li.onmouseover = node.onmouseover;
      li.onmouseout = node.onmouseout;
      li.appendChild(a);
      if( node.className ){
        li.className = node.className;
      }
      if( hc ){
        addClass(li, 'children');
        li.onclick = node.onclick;
        a.onclick = node.onclick;
      } else {
        a.onclick = links[0].onclick;
        li.onclick = links[0].onclick;
      }
      o.appendChild( li );
    }
    d.appendChild( o );

    Debug.dbg( 'mh= ' + mH + ' offset=' + d.offsetHeight );
    if( d.offsetHeight == 0 || ( mH > 0 && d.offsetHeight > mH ) ){
      d.style.height = mH + "px";
      addClass( d, 'menuOverflow');
    }

    // if you are here, set the timeout, just in case they don't mouse over...
    this.menuOver(); // clearTimeout
    if(this.open && this.options.useTimeout ){
      this.tout = setTimeout(this.varName + ".toggle()", this.options.hideTimeout * 2000); // double it
    }

    return d.offsetHeight;
  };
  
  this.init();
}
