/*
 * vegUI is copyright (c) 2005 Stefan Pratter
 *
 * This file is part of vegUI
 *
 * vegUI is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * vegUI is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with vegUI; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

/******************************************************************************
 * G L O B A L S
 *****************************************************************************/

var VEGUIOBJ = [];
var mouseX, mouseY;

/** Element Types */

var VUI_NODE = 1;
var VUI_BASE = 2;
var VUI_MANAGER = 3;
var VUI_BUTTON = 4;
var VUI_CBOX = 5;
var VUI_SCROLL = 6;
var VUI_WIN = 7;
var VUI_LIST = 8;
var VUI_MENU = 9;
var VUI_MENU_ITEM = 10;

/** node events */
var VUI_MOUSE_DOWN = 1;
var VUI_MOUSE_UP = 2;
var VUI_MOUSE_OVER = 3;
var VUI_MOUSE_OUT = 4;
var VUI_MOUSE_MOVE = 5;
var VUI_KEY_DOWN = 6;
var VUI_KEY_UP = 7;

/** Bounding box directions */

var VUI_UP = 1;
var VUI_DOWN = 2;
var VUI_LEFT = 3;
var VUI_RIGHT = 4;

/** Flags */

/* Any element */
var VUI_HMOUSE_UP = 0x01;
var VUI_HMOUSE_DOWN = 0x02;
var VUI_HMOUSE_OVER = 0x04;
var VUI_HMOUSE_OUT = 0x08;
var VUI_HMOUSE_MOVE = 0x10;
var VUI_HKEY_DOWN = 0x10000;
var VUI_HKEY_UP = 0x20000;
var VUI_DISABLED = 0x20;
var VUI_TEMPLATE = 0x40;

/* Content Box flags */
var VUI_HIDE_SCROLLX = 0x80;
var VUI_HIDE_SCROLLY = 0x100;
var VUI_HIDE_SCROLLS = VUI_HIDE_SCROLLX | VUI_HIDE_SCROLLY;

/* Window Flags */
var VUI_KILL_ON_CLOSE = 0x200;
var VUI_NORESIZE_W = 0x400;
var VUI_NORESIZE_H = 0x800;
var VUI_NORESIZE = VUI_NORESIZE_W | VUI_NORESIZE_H;
var VUI_NOMOVE_X = 0x1000;
var VUI_NOMOVE_Y = 0x2000;
var VUI_NOMOVE = VUI_NOMOVE_X | VUI_NOMOVE_Y;

var testarr = new Array();

/* General Settings */

/* Resize body to manager canvas size, this is to fix
 * text selection and onmouseout in internet explorer 
 */ 

var ADJUST_BODY_SIZE = true; 

/* IE SUCKS */
var browser_str = navigator.userAgent.toLowerCase();
function iesucks(Node) {
  var i;
  if(Node.nodeName != '#text') {
    Node.onmousemove = null;
    Node.onmouseover = null;
    Node.onmouseout = null;
    Node.onmousedown = null;
    Node.onmouseup = null;
    Node.onkeydown = null;
    Node.onkeyup = null;
    Node.onkeypress = null;
    Node.onselectstart = null;
    Node.ondrag = null;
    for(i in Node.childNodes)
      iesucks(Node.childNodes[i]);
  }
}

if((browser_str.indexOf('msie')+1))
  window.onunload = function() { iesucks(document.body); };

var VUI_VERSION = '1.0';

/******************************************************************************
 * F U N C T I O N S
 *****************************************************************************/

/** Clones any object */
function Clone(Obj) {
  var i;
  for(i in Obj) {
    if(Obj && Obj.push)
      this[i] = cloneArray(Obj[i]);
    else if(typeof Obj[i] == 'object' && Obj[i] != null) {
      this[i] = new Clone(Obj[i]);
    } else
      this[i] = Obj[i];
  }
}

/** merge object */
function merge(srcObj, trgObj) {
  var i;
  for(i in trgObj) {
    if(typeof trgObj[i] == 'object' && trgObj[i] != null)
      srcObj[i] = new Clone(trgObj[i]);
    else
      srcObj[i] = trgObj[i];
  }
}


/** clone array */

function cloneArray(Arr) {
  if(!Arr || !Arr.push) {
    if(typeof Arr != 'function')
      return new Clone(Arr);
    else
      return Arr;
  }
  var newArr = [];
  var i;
  for(i in Arr)
    newArr[i] = cloneArray(Arr[i]);
  return newArr;
}


/* Checks if _parent is a parent node of _Node */
function has_parent(_Node, _Parent) {
  var _p = _Node;
  if(!_p) return false;
  while((_p = _p.parentNode)) {
    if(_p == _Parent)
      return true;
  }
  return false;
}

/* get mouse pointer loc */
var mouseX;
var mouseY;
function get_mouse(e) {
  if (e.pageX || e.pageY) {
    mouseX = e.pageX;
    mouseY = e.pageY;
  }
  else if (e.clientX || e.clientY) {
    mouseX = e.clientX + document.documentElement.scrollLeft;
    mouseY = e.clientY + document.documentElement.scrollTop;
  }
}

/* wrapper to create a html node */
function htmlnode(nodeName, parentNode) {
  var _node = document.createElement(nodeName);
  if(parentNode)
    parentNode.appendChild(_node);
  return _node;
}

/* wrapper to create image node */
function imgnode(src, w, h, parentNode) {
  var _node = htmlnode('img', parentNode);
  _node.src = src;
  _node.setAttribute('width', w);
  _node.setAttribute('height', h);
  return _node;
}

/******************************************************************************
 * V E G U I M O U S E E V E N T
 ******************************************************************************
 ** Object that stores scripts to execute and properties for a mouse state */

/***************************************************/
/** Constructor */

function VegUIMouseState(eventType, Parent) {
  this.Parent = Parent;
  this.type = eventType;
  this.Scripts = new VegUIDynFunc();
  this.P = this.Properties = [];
}

/******************************************************************************
 * V E G U I N O D E
 ******************************************************************************
 ** Controls a html node */

VEGUIOBJ[VUI_NODE] = VegUINode;

/***************************************************/
/** Constructor */

function VegUINode(refName, Parent, Manager) {

  /* objects */
  this.refName = refName;
  this.Parent = Parent;
  this.Manager = Manager;
  this.type = VUI_NODE;
  this.Childs = this.C = [];
  this.Template = this.T = {Css : {}};
  this.Base = null;
  this.Css = null;
  this.flags = 0;
  this.BBox = new VegUIBBox(this);
  
  this.T.pos = 'absolute';
  this.nodeId = this.refName + "_node";
  this.T.nodeType = 'DIV';
  
  /* mouse event states */
  this.States = [];
  this.States[VUI_MOUSE_DOWN] = new VegUIMouseState(VUI_MOUSE_DOWN, this);
  this.States[VUI_MOUSE_OVER] = new VegUIMouseState(VUI_MOUSE_OVER, this);
  this.States[VUI_MOUSE_MOVE] = new VegUIMouseState(VUI_MOUSE_MOVE, this);
  this.States[VUI_MOUSE_OUT]  = new VegUIMouseState(VUI_MOUSE_OUT, this);
  this.States[VUI_MOUSE_UP]  = new VegUIMouseState(VUI_MOUSE_UP, this);
  this.States[VUI_KEY_UP]  = new VegUIMouseState(VUI_KEY_UP, this);
  this.States[VUI_KEY_DOWN]  = new VegUIMouseState(VUI_KEY_DOWN, this);

  
  /* custom element event handlers */
  this.on_state_change = function() { return false };
  this.on_resize = function() { return false };
  this.on_move = function() { return false };
  this.on_kill = function() { return false };

  /* link methods */
  this.x = vuinode_x;
  this.y = vuinode_y;
  this.x2 = vuinode_x2;
  this.y2 = vuinode_y2;
  this.abs_x = vuinode_abs_x;
  this.abs_y = vuinode_abs_y;
  this.width = vuinode_width;
  this.height = vuinode_height;
  this.is_hidden = vuinode_is_hidden;
  this.set_width = vuinode_set_width;
  this.set_height = vuinode_set_height;
  this.set_x = vuinode_set_x;
  this.set_y = vuinode_set_y;
  this.set_pos = vuinode_set_pos;
  this.hide = vuinode_hide;
  this.move = vuinode_move;
  this.resize = vuinode_resize;
  this.set_marg = vuinode_set_marg;
  this.set_node = vuinode_set_node;
  this.build_node = vuinode_build_node;
  this.tgl_event = vuinode_tgl_event;
  this.hevent_node = vuinode_handle_event;
  this.add_child = vuinode_add_child;
  this.add_child_o = vuinode_add_child_o;
  this.align_childs = vuinode_align_childs;
  this.clone_node = vuinode_clone;
  this.clear = vuinode_clear;
  this.dock = vuinode_dock;
  this.disable_node = vuinode_disable_node;
  this.call_ondock = vuinode_call_ondock;
  this.kill = vuinode_kill;
  this.set_transparency = vuinode_set_transparency;
  this.add_skin = vuinode_add_skin;
  
  /* wrappers */
  this.build = this.build_node;
  this.set = this.set_node;
  this.hevent = this.hevent_node;
  this.disable = this.disable_node;
  this.clone = this.clone_node;

  /* Event Handler */
  this.onmove = function() { return true; }
  this.onresize = function() { return true; }
  this.ondock = function() { return true; }
  this.onchange = function() { return true; }
}

/***************************************************/
/** VegUINode functions to retrieve node properties*/

/** get width **************************************/

function vuinode_width() {
  if(!this.Base)
    return null;
  return (this.Css.width ? parseInt(this.Css.width) : this.Base.offsetWidth);
}

/** get height *************************************/

function vuinode_height() {
  if(!this.Base)
    return null;
  return (this.Css.height ? parseInt(this.Css.height) : this.Base.offsetHeight);
}

/** get x ******************************************/

function vuinode_x() {
  return (this.Base ? (parseInt(this.Css.left) || 0) : null);
}

/** get y ******************************************/

function vuinode_y() {
  return (this.Base ? (parseInt(this.Css.top) || 0) : null);
}

/** get x2 (right) *********************************/

function vuinode_x2() {
  if(!this.Base)
    return null;
  return (this.x() + this.width());
}

/** get y2 (bottom) ********************************/

function vuinode_y2() {
  if(!this.Base)
    return null;
  return (this.y() + this.height());
}

/** get absolute x *********************************/
function vuinode_abs_x() {
  if(!this.Base)
    return null;
  var _par = this,x = this.x();
  while((_par = _par.Parent))
    x += _par.x();
  return (x+this.Manager.x());
}

/** get absolute y *********************************/

function vuinode_abs_y() {
  if(!this.Base)
    return null;
  var _par = this, y = this.y();
  while((_par = _par.Parent))
    y += _par.y();
  return (y+this.Manager.y());
}

/** get visibility *********************************/

function vuinode_is_hidden() {
  if(!this.Base)
    return null;
  return (this.Css.visibility == 'hidden' ? true : false);
}

/***************************************************/
/** VegUINode functions to manipulate the existing
  * node 
  */

/** set width **************************************/

function vuinode_set_width(n, noAlign) {
  if(!this.Base || isNaN(n) || n < 1)
    return;
  this.Css.width = n + "px";
  if(!noAlign)
    this.align_childs();
}

/** set height *************************************/

function vuinode_set_height(n, noAlign) {
  if(!this.Base || isNaN(n) || n < 1)
    return;
  this.Css.height = n + "px";
 if(!noAlign)
    this.align_childs();
}

/** set x ******************************************/

function vuinode_set_x(n) {
  if(!this.Base || n == null || isNaN(n) || this.BBox.validate(n, null))
    return;
  this.Css.left = n + "px";
}

/** set y ******************************************/

function vuinode_set_y(n) {
  if(!this.Base || n == null || isNaN(n) || this.BBox.validate(null, n))
    return;
  this.Css.top = n + "px";
}

/** set position (layer) ***************************/

function vuinode_set_pos(pos, n) {
  if(!this.Base)
    return;
  if(pos) 
    this.Css.position = pos;
  if(!isNaN(n) && n > -1)
    this.Css.zIndex = n;
}

/** hide node **************************************/

function vuinode_hide(b) {
  if(!this.Base)
    return;
  var _c;
  this.Css.visibility = b ? 'hidden' : 'visible';
  for(_c in this.C) {
    if(b || !this.C[_c].noAutoShow)
      this.C[_c].hide(b);
  }
}

/** move node **************************************/

function vuinode_move(x, y) {
  this.set_x(x);
  this.set_y(y);
  this.onmove();
}

/** resize node ************************************/

function vuinode_resize(w, h) {
  this.set_width(w, 1);
  this.set_height(h, 1);
  this.align_childs();
  this.onresize();
}

/** set margin of node *****************************/

function vuinode_set_marg(rmarg, bmarg, rmarg_nr, bmarg_nr) {
  this.T.rmarg = rmarg;
  this.T.bmarg = bmarg;
  this.T.rmarg_nr = rmarg_nr;
  this.T.bmarg_nr = bmarg_nr;
}

/** clear node *************************************/

function vuinode_clear(replacement) {
  while(this.Base.childNodes[0])
    this.Base.removeChild(this.Base.childNodes[0]);
  if(replacement)
    this.Base.appendChild(replacement);
}

/** disable/enable node ****************************/

function vuinode_disable_node(b) {
  if(b && !(this.flags & VUI_DISABLED))
    this.flags |= VUI_DISABLED;
  else if(!b && (this.flags & VUI_DISABLED))
    this.flags ^= VUI_DISABLED;
}

/***************************************************/
/*** set transparency */

function vuinode_set_transparency(n) {
  this.Css.filter = 'alpha(opacity=' + n +');';
  this.Css.opacity = n;
  this.Css.MozOpacity = n / 100;
}

/***************************************************/
/** VegUINode.dock(): append this node to another
  * html node
  */

function vuinode_dock(toNode) {
  if(!this.Base)
    alert('CRITICAL ERROR: COULD NOT DOCK NODE TO DOCUMENT, REASON: NO NODE ('+this.refName + ',' + this.childName +')');
  if(!toNode || !this.Base)
    return;

  this.T = {Css:{}};
  toNode.appendChild(this.Base);
  this.call_ondock();
}

/****************************************************/
/** VegUINode.call_ondock(): function that calls
  * ->ondock() in all childs */

function vuinode_call_ondock() {
  var c;
  this.ondock();
  for(c in this.C)
    this.C[c].call_ondock();
}

/***************************************************/
/** VegUINode.kill(): kills node, removing all
  * html elements from document with the option
  * to also remove the the object from its 
  * parent and the manager
  */

function vuinode_kill(removeSelf) {
  if(this.Base && this.Base.parentNode) {
    if((browser_str.indexOf('msie')+1))
      iesucks(this.Base);
    this.Base.parentNode.removeChild(this.Base);
  }
  if(removeSelf){
    var c;

    for(c in this.C) 
      this.C[c].kill(1);

    if(this.Parent)
      delete this.Parent.C[this.childName];
    delete this.Manager.E[this.eleIdx];
  }
}

/***************************************************/
/** align childs within node */

function vuinode_align_childs(Child) {
  var c, i;
  for(i in this.C) {
    c = this.C[i];
    if(Child)
      c = Child;
    if(!isNaN(c.rmarg) && c.rmarg !== null)
      c.resize(this.width() - c.x() - c.rmarg, null);
    else if(!isNaN(c.rmarg_nr) && c.rmarg_nr !== null)
      c.move((this.width() - c.width()) - c.rmarg_nr, null);
    if(!isNaN(c.bmarg) && c.bmarg !== null)
      c.resize(null, this.height() - c.y() - c.bmarg);
    else if(!isNaN(c.bmarg_nr) && c.bmarg_nr !== null)
      c.move(null,(this.height() - c.height()) - c.bmarg_nr);

    if(Child)
      return;
  }
}

/***************************************************/
/** VegUINode.set_node(), function to set
  * up the template for the node (before its
  * actually buildt)
  */

function vuinode_set_node(nodeType, w, h, x, y, pos, z) {
  if(nodeType) this.T.nodeType = nodeType;
  if(!isNaN(w) && w > 0) this.T.w = w;
  if(!isNaN(h) && h > 0) this.T.h = h;
  if(x != null) this.T.x = x;
  if(y != null) this.T.y = y;
  if(pos) this.T.pos = pos;
  if(z) this.T.z = z;
}

/***************************************************/
/** VegUINode.build_node(), creates the node from
  * the template
  */

function vuinode_build_node(toNode) {
  if(this.Base || (this.flags & VUI_TEMPLATE))
    return null;
  
  var i;
  
  /* create node */
  this.Base = document.createElement(this.T.nodeType);
  this.Css = this.Base.style;
  this.Base.id = this.nodeId;

  /* set node properties */
  this.move(this.T.x, this.T.y);
  this.resize(this.T.w, this.T.h);
  this.set_pos(this.T.pos, this.T.z);
  if(this.T.className)
    this.Base.className = this.T.className;
  
  this.rmarg = this.T.rmarg;
  this.bmarg = this.T.bmarg;
  this.rmarg_nr = this.T.rmarg_nr;
  this.bmarg_nr = this.T.bmarg_nr;
  
  /* Setup cursor change */
  if(this.T.micon) {
    if(!(this.flags & VUI_HMOUSE_OUT))
      this.flags |= VUI_HMOUSE_OUT;
    if(!(this.flags & VUI_HMOUSE_OVER))
      this.flags |= VUI_HMOUSE_OVER; 

    var micon = this.T.micon;
    this.States[VUI_MOUSE_OVER].Scripts.add(function(argArr) { argArr[0].Css.cursor = micon });
    this.States[VUI_MOUSE_OUT].Scripts.add(function(argArr) { argArr[0].Css.cursor = 'default' });
  }
  
  /* set mouse event handlers */
  this.tgl_event((this.flags & VUI_HMOUSE_DOWN), VUI_MOUSE_DOWN, 'onmousedown');
  this.tgl_event((this.flags & VUI_HMOUSE_MOVE), VUI_MOUSE_MOVE, 'onmousemove');
  this.tgl_event((this.flags & VUI_HMOUSE_OVER), VUI_MOUSE_OVER, 'onmouseover');
  this.tgl_event((this.flags & VUI_HMOUSE_OUT), VUI_MOUSE_OUT, 'onmouseout');
  this.tgl_event((this.flags & VUI_HKEY_UP), VUI_KEY_UP, 'onkeyup');
  this.tgl_event((this.flags & VUI_HKEY_DOWN), VUI_KEY_DOWN, 'onkeypress');
  

  /* transparency */
  if(this.T.t) {
    this.set_transparency(t);
  }

  /* image src */
  if(this.T.img_src)
    this.Base.src = this.T.img_src;

  /* set styles */
  var css;
  for(css in this.T.Css) {
      this.Css[css] = this.T.Css[css];
  }
    
  /* build childs */
  for(i in this.C) {
    this.C[i].build(this.Base);
  }
  
  this.align_childs();

  if(this.T.innerHTML)
    this.Base.innerHTML = this.T.innerHTML;
   
  /* append node to document */
  this.dock(toNode);
  return 1;
}

/***************************************************/
/** VegUINode.tgl_event(): Toggle event 
  * handler on node 
  */

function vuinode_tgl_event(b, eventType, nodeProp) {
  if(b) {
    var Obj = this;
    this.Base[nodeProp] = function(e) {
      if(!e) var e = event;
      Obj.hevent(eventType, e);
      return true;
    };
  } else if(this.Base[nodeProp])
    this.Base[nodeProp] = null;
}

/****************************************************/
/** VegUINode.handle_event(): Handle mouse/key event */

function vuinode_handle_event(eventType, mEvent) {
  if(!this.Base || !window.VUI_DISABLED || (this.flags & VUI_DISABLED))
    return;
  var _state = this.States[eventType], _p = _state.P, i;

  /* change node properties */
  if(_p.className) {
    this.Base.className = _p.className;
  }

  this.mEvent = mEvent;
  
  if(eventType == VUI_KEY_DOWN) {
    this.aKey = mEvent.which ? mEvent.which : mEvent.keyCode;
    this.aKeyChar = String.fromCharCode(this.aKey);
  } else if(eventType != VUI_KEY_UP) {
    this.toE = (mEvent.relatedTarget || mEvent.toElement) 
  }
 
  _state.Scripts.execute([this]);
  
  this.on_state_change();
  return _state;
}

/****************************************************/
/** VegUINode.add_child(): add child element */

function vuinode_add_child(name, type, nodeName, pos) {
  var _e = this.Manager.get_new(type, this);
  _e.childName = name;
  this.C[name] = _e;
  if(nodeName)
    _e.T.nodeType = nodeName;
  if(pos != undefined)
    _e.T.pos = pos;
  return _e;
}

/***************************************************/
/** VegUINode.add_skin(), wrapper function
  * to quickly setup a skin node
  */

function vuinode_add_skin(n,w,h,x,y,c,rm,bm,rm_nr,bm_nr) {
  var e = this.add_child(n, VUI_NODE)
  e.set_node('div', w, h, x, y);
  e.T.className = c;
  e.set_marg(rm,bm,rm_nr,bm_nr);
}

/****************************************************/
/** VegUINode.add_child_o(): add existing template
  * as child
  */

function vuinode_add_child_o(name, Obj) {
  Obj.childName = name;
  this.C[name] = Obj;
  Obj.Parent = this;
}

/****************************************************/
/** Clone properties from template */

function vuinode_clone(Template) {
  var i, c;
  
  merge(this.T, Template.T);
  this.flags = Template.flags;
  for(i in Template.States) {
    this.States[i].Scripts.Funcs = cloneArray(Template.States[i].Scripts.Funcs);
    merge(this.States[i].P, Template.States[i].P);
  }  


  /* Clone Event Handlers */
  this.onmove = Template.onmove;
  this.onresize = Template.onresize;
  this.ondock = Template.ondock;
  this.onchange = Template.onchange;

  /* Clone BBox */
  this.BBox.set(
    Template.BBox.x,
    Template.BBox.y,
    Template.BBox.w,
    Template.BBox.h,
    Template.BBox.enabled
  );
  
  /* Clone Childs Elements */
  for(c in Template.C) {
    if(!this.C[c] || this.C[c].type != Template.C[c].type) 
      this.add_child(c, Template.C[c].type);
    //  this.C[c] = this.Manager.get_new(Template.C[c].type, this);
    this.C[c].clone(Template.C[c]);
  }

  return this;
}

/******************************************************************************
 * V E G U I M A N A G E R
 *****************************************************************************/
/** Spawns and keeps track of all vegUI elements 
  * Protoype: VegUINode
  */

VEGUIOBJ[VUI_MANAGER] = VegUIManager;

/***************************************************/
/** Constructor */

function VegUIManager(refName) {
  this.constructor = VegUINode;
  this.constructor(refName, null, this);
  
  /* objects */
  this.type = VUI_MANAGER;
  this.eleIdx = 0;
  this.winIdx = 0;
  this.Elements = this.E = [];
  this.Windows = this.W = [];
  
  this.flags |= VUI_HMOUSE_UP | VUI_HMOUSE_OUT | VUI_HMOUSE_MOVE;
  
  /* methods links */
  this.get_new = vuimanager_get_new;
  this.get_clone = vuimanager_get_clone;
  this.set_manager = vuimanager_set_manager;
  this.build_manager = vuimanager_build_manager;
  this.build_element = vuimanager_build_element;
  this.get_free_idx = vuimanager_get_free_idx;
  
  /* wrappers */
  this.build = this.build_manager;
  this.set = this.set_manager;
}
VegUIManager.prototype = VegUINode;

/***************************************************/
/** get free element index */

function vuimanager_get_free_idx() {
  var idx = (Math.round(Math.random()*9999)+1);
  while(this.E[idx])
    idx = (Math.round(Math.random()*9999)+1)
  return idx;
}

/***************************************************/
/** get new vegUI element */

function vuimanager_get_new(type, Parent, Template) {
  var _idx = this.get_free_idx();
  var _refName = this.refName + ".E[" + _idx + "]";
  var _e = this.E[_idx] = new VEGUIOBJ[(Template ? Template.type : type)](_refName,  Parent, this);
  if(Template)
    _e.clone(Template);
  _e.eleIdx = _idx;
  return _e;
}

/***************************************************/
/** Wrapper to get cloned element */

function vuimanager_get_clone(Template, Parent) {
  return this.get_new(null, Parent, Template);
}

/***************************************************/
/** set up the template for the manager base
  * node 
  */

function vuimanager_set_manager(w,h,x,y) {
  this.set_node('DIV', w, h, x, y);
  this.nodeId = this.refName + "_node";
}

/****************************************************/
/** Build manager */

function vuimanager_build_manager(toNode) {
  var Manager = this;
  this.build_node();
  /*
   * the manager node is the only node who
   * has an actual mouse up event handler
   */
  
  this.tgl_event(true, VUI_MOUSE_UP, 'onmouseup');
  this.States[VUI_MOUSE_UP].Scripts.add(
    function(argArr) {
      var Obj = argArr[0];
      if(Obj.focusedElement)
        Obj.focusedElement.hevent(VUI_MOUSE_UP, Obj.mEvent);
    }
  );

  /*
   * if a key press or release is detected on the site 
   * route it to the focusedElement 
   */

  document.onkeypress = function(e) {
    if(!e) var e = window.event;
    Manager.hevent(VUI_KEY_DOWN, e);
  }

  document.onkeyup = function(e) {
    if(!e) var e = window.evemt;
    Manager.hevent(VUI_KEY_UP, e);
  } 

  this.States[VUI_KEY_DOWN].Scripts.add(
    function(argArr) {
      if(argArr[0].focusedElement)
        argArr[0].focusedElement.hevent(VUI_KEY_DOWN, argArr[0].mEvent)
    }
  );

  this.States[VUI_KEY_UP].Scripts.add(
    function(argArr) {
      if(argArr[0].focusedElement)
        argArr[0].focusedElement.hevent(VUI_KEY_UP, argArr[0].mEvent)
    }
  );

  /* 
   * set on mouse up event to trigger on mouse out 
   */
  
  this.tgl_event(true, VUI_MOUSE_OUT, 'onmouseout');
  this.States[VUI_MOUSE_OUT].Scripts.add(
    function(argArr) {
      var Obj = argArr[0];
      var toE = (Obj.mEvent.relatedTarget || Obj.mEvent.toElement);
      if(Obj.focusedElement && toE != Obj.Base && toE != Obj.focusedElement.Base) {
        if(!has_parent(toE, Obj.Base))
          Obj.hevent(VUI_MOUSE_UP, Obj.mEvent);
      }
    }
  );

  this.Css.overflow = 'hidden';
  this.dock(toNode);

  /* Adjust document body size, this is to fix ie text selection
   * on absolute positioned elements 
   */

  if(ADJUST_BODY_SIZE) {
    document.body.style.width = (this.width() + 50) + "px";
    document.body.style.height = (this.height() + 50) + "px";
  }
 
  /* 
   * Set up onmouse move event handler 
   */

  this.States[VUI_MOUSE_MOVE].Scripts.add(
    function(argArr) {
      get_mouse(argArr[0].mEvent);
    }
  );
 
}

/****************************************************/
/** Build element */

function vuimanager_build_element(VegUIObj, toNode) {
  if(!this.Base) return;
  
  if(!toNode) {
    var toNode = VegUIObj.Parent && VegUIObj.Parent.Base ? VegUIObj.Parent.Base : this.Base;
  }
  
  VegUIObj.build(toNode);
}

/******************************************************************************
 * V E G U I B B O X
 *****************************************************************************/
/** Bounding box for elements, limits where an element can be moved to */

/****************************************************/
/** Constructor */

function VegUIBBox(VegUIElement) {
  this.Parent = VegUIElement;
  
  this.set = vuibbox_set;
  this.validate = vuibbox_validate;
  this.correct = vuibbox_correct;
}

/*****************************************************/
/** VegUIBBox.set(): sets bbox properties */

function vuibbox_set(x, y, w, h, b, c) {
  this.x = x;
  this.x2 = w + x;
  this.y = y;
  this.y2 = h + y;
  this.w = w;
  this.h = h;
  this.enabled = b;
  this.c = c;
  if(c)
    this.correct(c);
}

function vuibbox_correct() {
  if(!this.enabled)
    return;
  this.enabled = false;
  if(this.Parent.y2() > this.y2)
    this.Parent.move(0,this.Parent.y()-(this.Parent.y2()-this.y2))
  else if(this.Parent.y() < this.y)
    this.Parent.move(0,this.y);
  if(this.Parent.x2() > this.x2)
    this.Parent.move(this.Parent.x()-(this.Parent.x2()-this.x2))
  else if(this.Parent.x() < this.x)
    this.Parent.move(this.x,0);
  this.enabled = true;
}

/******************************************************/
/** VegUIBBox.validate(): validates coordinates */

function vuibbox_validate(x, y) {
  var ew = this.Parent.width();
  var eh = this.Parent.height();
  this.bumped = 0;
 
  if(!this.enabled)
    return 0;
  else if(!isNaN(x) && x < this.x)
    this.bumped = VUI_LEFT;
  else if(!isNaN(x) && (x + ew) > (this.x + this.w))
    this.bumped = VUI_RIGHT;
  else if(!isNaN(y) && y < this.y)
    this.bumped = VUI_UP;
  else if(!isNaN(y) && (y + eh) > (this.y + this.h))
    this.bumped = VUI_DOWN;
  else
    this.bumped = 0;

  return this.bumped;
}


/******************************************************************************
 * D Y N F U N C
 *****************************************************************************/
 /** Allows to have a function with dynamic content */

/******************************************************/
/** Constructor */

function VegUIDynFunc(returnVal) {
  this.Funcs = [];
  this.returnVal = returnVal || false;

  this.add = function(fn,id) { 
    
    if(id) {
      this.Funcs[id] = fn;
    }
    else
      this.Funcs.push(fn);
  }

  this.free = function(id) { delete this.Funcs[id]; }

  this.execute = function(argArr) {
    var i, returnVal = this.returnVal;
    for(i in this.Funcs)
      this.Funcs[i](argArr);
    return returnVal;
  }

}


