function push(value, stack)
{
stack[stack.length] = value;
}

function pop(stack)
{
if (stack.length == 0) return false;
var ret = stack[stack.length - 1];
stack.length--;
return ret;
}

function menu_SetBgColor(nodenum)
{
this.overnode = nodenum;
var curnode = GetById('tr_' + this.instance + '_' + nodenum);
curnode.style.background = this.overBgColor;
}

function menu_RestoreBgColor(nodenum)
{
this.overnode = -1;
var curnode = GetById('tr_' + this.instance + '_' + nodenum);
curnode.style.background = this.outBgColor;
}

function menu_GetNode(nodenum)
{
var struct =  (menu_GetNode.arguments.length == 1) ? this.struct : menu_GetNode.arguments[1];
var result = false;
for(var i=0; i<struct.length; i++)
{
  if (struct[i]['nodenum'] == nodenum) 
  {
   return struct[i];
  }
  if (struct[i]['child'] != null) 
  {
   result = this.GetNode(nodenum, struct[i]['child']);
   if (result != false) return result;
  }
}
return result;
}

function menu_Hide()
{
var stacklength = this.stack.length;
for(var i=0; i<stacklength; i++)
{
  var curmenu = pop(this.stack);
  var struct = this.GetNode(this.overnode);
  if ((curmenu != this.overnode) && (struct['menunum'] != curmenu))
  {
   GetById('table_' + this.instance + '_' + curmenu).style.visibility = 'hidden';
   this.lefttoright = true;
  }
  else
  {
   push(curmenu, this.stack);
   return;
  }
}
}

function menu_Show(nodenum)
{
if (!this.run) return false;
this.SetBgColor(nodenum);
this.Hide(); 
for(var i=0; i<this.stack.length; i++)
{
  if (this.stack[i] == nodenum) return;
}
this.overnode = nodenum;
var showmenu = GetById('table_' + this.instance + '_' + nodenum);
if (!showmenu) return;
push(nodenum, this.stack); 
var struct = this.GetNode(nodenum);
var curmenu = GetById('table_' + this.instance + '_' + struct['menunum']);
var curnode = GetById('tr_' + this.instance + '_' + nodenum, curmenu.document); 
if (this.isIe)
{
  if (menu_Show.arguments.length == 2)
  {
   GetById(menu_Show.arguments[1]).style.height = 0;
  }
  curmenu.style.height = 0;
  curnode.style.height = 0;
}
var y = (menu_Show.arguments.length == 2) ? GetById(menu_Show.arguments[1]).offsetTop + this.firstLevelOffsetY : curmenu.offsetTop + curnode.offsetTop + this.otherLevelOffsetY;
if (menu_Show.arguments.length == 2)
{
   var x = GetById(menu_Show.arguments[1]).offsetLeft + this.firstLevelOffsetX;
}
else
{
  var rightlimit = curmenu.offsetLeft + curmenu.offsetWidth + showmenu.offsetWidth;
  if (rightlimit > document.body.clientWidth) this.lefttoright = false;
  var leftlimit = curmenu.offsetLeft - showmenu.offsetWidth;
  
  if (leftlimit < 0) this.lefttoright = true;
  if (this.lefttoright)
  {
   var x = curmenu.offsetLeft + curmenu.offsetWidth + this.otherLevelOffsetX;
  }
  else
  {
   var x = leftlimit + 1;
  }
}
showmenu.style.left = x;
showmenu.style.top = y;
showmenu.style.visibility = 'visible';
}

function menu_Out(nodenum)
{
if (!this.run) return false;
this.RestoreBgColor(nodenum);
clearTimeout(this.timeout);
this.timeout = setTimeout(this.instance + '.Hide()', this.overTimeout);
}

function menu_Run()
{
this.run = true;
var firstlevel = (menu_Run.arguments.length == 0);
var struct =  firstlevel ? this.struct : menu_Run.arguments[0];
var tableid = firstlevel ? -1 : menu_Run.arguments[1];
this.tmpcreatemenu[this.menucounter] = '<div id="table_' + this.instance + '_' + tableid + '" style="position:absolute; z-index:' + this.menucounter + ';visibility:hidden">';
this.tmpcreatemenu[this.menucounter] += '<table border="0" cellspacing="0" cellpadding="0" class="popup">';
for(var i=0; i<struct.length; i++)
{
  this.tmpcreatemenu[this.menucounter] += '<tr bgcolor="' + this.outBgColor + '" onmouseover="' + this.instance + '.Show(' + struct[i]['nodenum'] + ')" onmouseout="' + this.instance + '.Out(' + struct[i]['nodenum'] + ')">';
  this.tmpcreatemenu[this.menucounter] += '<td><div style="width:100%; position:relative;" id="tr_' + this.instance + '_' + struct[i]['nodenum'] + '">' + struct[i]['text'] + '</div></td>';
  struct[i]['menunum'] = tableid;
  if (struct[i]['child'] != null)
  {
   this.menucounter++;
   this.Run(struct[i]['child'], struct[i]['nodenum']);
  }
  this.tmpcreatemenu[this.menucounter] += '</tr>';
}
this.tmpcreatemenu[this.menucounter] += '</table></div>';
WriteHtml(this.tmpcreatemenu[this.menucounter]);
this.menucounter--;
}

function menu_AddNode(text, parnum)
{
if (parnum == null)
{
  var rootlength = this.struct.length;
  this.struct[rootlength] = new Array(4);
  this.struct[rootlength]['text'] = text;
  this.struct[rootlength]['nodenum'] = this.curnode;
  this.struct[rootlength]['child'] = null;
  this.struct[rootlength]['menunum'] = -1;
}
else
{
  var struct = this.GetNode(parnum);
  var tmparr = new Array(4);
  tmparr['text'] = text;
  tmparr['nodenum'] = this.curnode;
  tmparr['child'] = null;  
  tmparr['menunum'] = -1;
  
  if (struct['child'] == null)
  {
   struct['child'] = new Array();
  }
  curlength =  struct['child'].length;
  struct['child'][curlength] = tmparr;
}
return this.curnode++;
}

function Menu(instance)
{
// Параметры конструктора
this.instance = instance;

// Private переменные
this.isIe = navigator.appName == "Microsoft Internet Explorer";
this.struct = new Array();
this.tmpcreatemenu = new Array();
this.menucounter = 0;
this.curnode = 0; // Уникальный идентификатор узла
this.lefttoright = true;
this.stack = new Array();
this.overnode = -1;
this.timeout = 0;
this.overTimeout = 1500;
this.firstLevelOffsetX = 1;
this.firstLevelOffsetY = 10;
this.otherLevelOffsetX = -1;
this.otherLevelOffsetY = -1;
this.overBgColor = '#80bd00';
this.overBgPos = "right";
this.overBgRep = "no-repeat";
this.outBgColor = '#CCCCCC';
this.padding_left = '11px';
this.run = false;

// Private методы
this.Hide = menu_Hide;
this.GetNode = menu_GetNode;
this.SetBgColor = menu_SetBgColor;
this.RestoreBgColor = menu_RestoreBgColor;

// Public методы
this.AddNode = menu_AddNode;
this.Run = menu_Run;
this.Show = menu_Show;
this.Out = menu_Out;
}
