function cute_menu(params)
{
  this.container_id = params['container_id']==undefined?null:params['container_id'];
  this.item_class = params['item_class']==undefined?'cm_item':params['item_class'];
  this.level_class = params['level_class']==undefined?'cm_tier':params['level_class'];
  this.active_class = params['active_class']==undefined?'active':params['active_class'];
  this.default_class = params['default_class']==undefined?'default':params['default_class'];
  this.fancy = params['fancy']==undefined?true:!!params['fancy'];
 
  this.container = null;
  this.menus = [];
  
  this.hide_timeout = null;
  this.closing_menu = null;
  this.fade_timeout = null;
  this.fading_menu = null;

  cute_menu.prototype.init = function() {
    this.container = this.container_id==null?document:document.getElementById(this.container_id);
    this.initializeSubmenus(this.container);
  }
  
  cute_menu.prototype.initializeSubmenus = function(parent) {
    var submenu = this.getSubmenu(parent);
    if(submenu!=null) {
      this.initializeSubmenus(submenu);
    }
    var items = this.getMenuitems(parent);
    for(var i in items) {
      if(items.hasOwnProperty(i)) {
        var submenu = this.getSubmenu(items[i]);
        if(submenu!=null) {
          this.initializeSubmenus(submenu);
          this.addEventListener(items[i], 'mouseover', this.createShowMenuCallback(items[i], submenu, this.hasClassName(items[i], this.default_class)), this);
          if(!this.hasClassName(items[i], this.default_class)) {
            this.addEventListener(items[i], 'mouseout', this.createHideMenuCallback(items[i], submenu), this);
          }
        }
      }
    }
  }
  
  cute_menu.prototype.createShowMenuCallback = function(item, menu, is_default) {
    var cuteMenuObj = this;
    return function() {
      cuteMenuObj.showMenu(item, menu, is_default);
    }
  }
  
  cute_menu.prototype.showMenu = function(item, menu, is_default) {
    clearTimeout(this.hide_timeout);
    if(this.closing_menu!=null) {
      this.hideSubmenu(this.closing_menu, false);
      this.closing_menu = null;
    }
    clearTimeout(this.fade_timeout);
    if(this.fading_menu!=null) {
      this.hideSubmenu(this.fading_menu, false);
      this.setOpacity(this.fading_menu, 1.0);
      this.fading_menu = null;
    }
    if(!is_default) {
      this.addClassName(item, this.active_class);
      this.addClassName(menu, this.active_class);
    }
  }
  
  cute_menu.prototype.createHideMenuCallback = function(item, menu) {
    var cuteMenuObj = this;
    return function() {
      cuteMenuObj.hideMenu(item, menu);
    }
  }
  
  cute_menu.prototype.hideMenu = function(item, menu) {
    this.removeClassName(item, this.active_class);
    this.closing_menu = menu;
    this.hide_timeout = setTimeout(this.createHideSubmenuCallback(menu), 1000);
  }
  
  cute_menu.prototype.createHideSubmenuCallback = function(menu) {
    var cuteMenuObj = this;
    return function() {
      cuteMenuObj.hideSubmenu(menu, true);
    }
  }
  
  cute_menu.prototype.hideSubmenu = function(menu, fancy) {
    if(this.fancy && fancy) {
      var opacity = menu.style.opacity==undefined || menu.style.opacity==''?1.0:menu.style.opacity;
      var step = 0.05;
      this.fading_menu = menu;
      this.fadeSubmenu(menu, opacity, step);
    } else {
      this.removeClassName(menu, this.active_class);
    }
  }
  
  cute_menu.prototype.createFadeSubmenuCallback = function(menu, opacity, step) {
    var cuteMenuObj = this;
    return function() {
      cuteMenuObj.fadeSubmenu(menu, opacity, step);
    }
  }
  
  cute_menu.prototype.fadeSubmenu = function(menu, opacity, step) {
    if(opacity-step <= 0) {
      this.removeClassName(menu, this.active_class);
      this.setOpacity(menu, 1.0);
      this.fading_menu = null;
      clearTimeout(this.fade_timeout);
    } else {
      this.setOpacity(menu, opacity-step, step);
      this.fade_timeout = setTimeout(this.createFadeSubmenuCallback(menu, opacity-step, step), 50);
    }
  }
  
  cute_menu.prototype.getMenuitems = function(menu) {
    var items = [];
    var elements = menu.childNodes;
    for(var i = 0; i < elements.length; i++) {
      if(this.hasClassName(elements.item(i), this.item_class)) {
        items.push(elements.item(i));
      } else if(!this.hasClassName(elements.item(i), this.level_class)) {
        items.concat(this.getMenuitems(elements.item(i)));
      }
    }
    return items;
  }
  
  cute_menu.prototype.getSubmenu = function(item) {
    var menus = [];
    var elements = item.childNodes;
    for(var i = 0; i < elements.length; i++) {
      if(!this.hasClassName(elements.item(i), this.level_class)) {
        menus.concat(this.getSubmenu(elements.item(i)));
      } else {
        menus.push(elements.item(i));
      }
      if(menus.length>0){break;}
    }
    return menus.length>0?menus[0]:null;
  }
  
  cute_menu.prototype.hasFancyIncludes = function() {
    return (
      (typeof Prototype!='undefined') && 
      (typeof Scriptaculous!='undefined')
    );
  }

  cute_menu.prototype.setOpacity = function(element, value) {
    element.style.opacity = (value == 1 || value === '') ? '' :
      (value < 0.00001) ? 0 : value;
    element.style.filter = (value == 1 || value === '') ? '' :
      "alpha(opacity=" + (((value < 0.00001) ? 0 : value) * 100) + ");";
    return element;
  }

  cute_menu.prototype.getChildrenByClass=function(c,e){if(e==undefined)return false;
  var es=new Array();var r=new RegExp('\\b'+c+'\\b');var a=e.childNodes;
  for(var i=0;i<a.length;i++){if(r.test(a[i].className)){es.push(a[i]);}}
  return es;};
  cute_menu.prototype.getDescendantsByClass=function(c,e){if(e==undefined)return false;
  var es=new Array();var r=new RegExp('\\b'+c+'\\b');var a=e.getElementsByTagName('*');
  for(var i=0;i<a.length;i++){if(r.test(a[i].className)){es.push(a[i]);}}
  return es;};cute_menu.prototype.addEventListener=function(o,e,f,s,c){
  if(!c)c=false;var sd=s?function(ev){f.apply(s,[ev]);}:f;if(o.addEventListener)
  {o.addEventListener(e,sd,c); return true;}else if(o.attachEvent){
  return o.attachEvent("on"+e,sd);}};cute_menu.prototype.hasClassName=function(e,c){
  return e.className!=null && e.className.match(new RegExp('(\\s|^)'+c+'(\\s|$)'));}
  cute_menu.prototype.addClassName=function(e,c){if(!e.className){e.className=c;}else 
  if(!this.hasClassName(e,c)){e.className=e.className+" "+c;}}
  cute_menu.prototype.removeClassName=function(e,c){if(this.hasClassName(e,c))
  {var reg=new RegExp('(\\s|^)'+c+'(\\s|$)');e.className=e.className.replace(reg,' ');}}
  
  this.init();
}
