var Menu = function (trigger, containerClassName, listClassName)
{
  this.container  = Menu.buildContainer(trigger, containerClassName);
  this.isInMotion = false;
  this.list       = Menu.buildList(listClassName);
  this.originalH  = 0;
  this.originalW  = 0;
  this.trigger    = trigger;
  this.isClicked  = false;

  this.fnCache = {};
  this.fnCache.onFinishAnimate = EventRunner.scope(this, this.onFinishAnimate);

  this.container.appendChild(this.list);
  document.body.appendChild(this.container);

  var jq         = $(this.container);
  this.originalW = jq.innerWidth();
  this.originalH = jq.innerHeight();

  EventRunner.register(this.container, 'mouseenter', this.onMouseEnter, this);
  EventRunner.register(this.container, 'mouseleave', this.onMouseLeave, this);
}


// STATICs
// ________________________________________________________________________


Menu.buildList = function (cls)
{
  cls = cls || 'menu';
  var ul = document.createElement('ul');
  ul.className = cls;
  return ul;
}


Menu.buildContainer = function (trigger, cls)
{
  var jq = $(trigger);
  var pos = jq.position();
  var height = jq.innerHeight();
  cls = cls || 'menuContainer';
  var c = document.createElement('div');
  c.className = cls;
  c.style.position = 'absolute';
  c.style.left = pos.left + 'px';
  c.style.top  = (pos.top + height) + 'px';
  c.style.display = 'none';
  return c;
}


// VIEW METHODS
// _______________________________________________________________________


Menu.prototype.toggle = function (ev)
{
  var result;
  if (this.isShowing)
  {
    this.hide(ev);
    result = true;
  }
  else
  {
    this.show(ev);
    result = false;
  }
  return result;
}


Menu.prototype.show = function (ev)
{
  if (this.isInMotion)
  {
    $(this.container).stop();
  }
  else
  {
    this.container.style.height = this.originalH + 'px';
  }
  this.isInMotion = true;
  $(this.container).slideDown(undefined, this.fnCache.onFinishAnimate);
  this.isShowing = true;
}


Menu.prototype.hide = function (ev)
{
  if (this.isInMotion)
  {
    $(this.container).stop();
  }
  this.isInMotion = true;
  $(this.container).slideUp(undefined, this.fnCache.onFinishAnimate);
  this.isShowing = false;
}


// EVENT METHODS
// _______________________________________________________________________


Menu.prototype.onClick = function (ev)
{
  if (this.isInMotion)
  {
    $(this.container).stop();
  }
  if (!this.isClicked)
  {
    this.show(ev);
  }
  else
  {
    this.hide(ev);
  }
  this.isClicked = !this.isClicked;
}


Menu.prototype.onFinishAnimate = function (ev)
{
  this.isInMotion = false;
  this.container.style.height = this.originalH + 'px';
}


Menu.prototype.onMouseEnter = function (ev)
{
  if (!this.isClicked)
  {
    this.show(ev);
  }
}


Menu.prototype.onMouseLeave = function (ev)
{
  if (!this.isClicked)
  {
    this.hide(ev);
  }
}


Menu.prototype.onResize = function (ev)
{
  var jq = $(this.trigger);
  var pos = jq.position();
  var height = jq.innerHeight();
  this.container.style.left = pos.left + 'px';
  this.container.style.top  = (pos.top + height) + 'px';
}


// UTILITY METHODS
// _______________________________________________________________________


Menu.prototype.append = function (str, link)
{
  if (!str && !link) return;
  var data;
  str = str || '(untitled)';
  if (link)
  {
    data  = document.createElement('a');
    data.href = link;
    data.appendChild(document.createTextNode(str));
  }
  else
  {
    link = null;
    data = document.createTextNode(str);
  }
  var li = document.createElement('li');
  li.appendChild(data);
  this.list.appendChild(li);
  jQuery.data(li, 'name', str);
  jQuery.data(li, 'link', link);
}



