/**********************
 Copyright (c) 2009, CiraniArte, LLC.
 ALL RIGHTS RESERVED
*******************/

function getBrowserType() {
  var agt=navigator.userAgent.toLowerCase();
  if (agt.indexOf("opera") != -1) return 'Opera';
  if (agt.indexOf("firefox") != -1) return 'Firefox';
  if (agt.indexOf("safari") != -1) return 'Safari';
  if (agt.indexOf("msie") != -1) return 'IE';
  if (agt.indexOf("netscape") != -1) return 'Netscape';
  if (agt.indexOf("mozilla/5.0") != -1) return 'Mozilla';
  return 'Unknown';
}

var globalBrowserType = getBrowserType();

function inherit(baseClassName) {
  function inheritance() {}
  baseClass = eval(baseClassName);
  inheritance.prototype = baseClass.prototype;
  var inh = new inheritance();
  inh[baseClassName] = baseClass;
  return inh;
}  

function XMLDOM() {
};
XMLDOM.getNodes = function(parentNode, nodeNames) {
  if (typeof(nodeNames) == 'string') {
    return parentNode.getElementsByTagName(nodeNames);
  }
  else {
    var oldParentNode = null;
    for (i = 0; i < nodeNames.length; i++) {
      var childNodes = parentNode.childNodes;
      var matchingNodes = [];
      for (j = 0; j < childNodes.length; j++) {
	//alert(j + ':' + childNodes[j].nodeName);
	if (childNodes[j].nodeName == nodeNames[i]) {
	  matchingNodes.push(childNodes[j]);
	}
      }
      //var parentNodes = parentNode.getElementsByTagName(nodeNames[i]);
      var parentNodes = matchingNodes;
      if (! parentNodes || parentNodes.length == 0) {
	//alert('Could not find node: ' + nodeNames[i]);
	return []; // no matches
      }
      parentNode = parentNodes[0];
    }
    return parentNodes;
  }
}
XMLDOM.getChildText = function(node, childName) {
  var childNodes = node.getElementsByTagName(childName);
  if (! childNodes || childNodes.length == 0) {
    alert('No children:' + childName);
    return '';
  }
  return XMLDOM.getText(childNodes[0]);
}
XMLDOM.getText = function(node) {
  var textNodes = node.childNodes;
  if (! textNodes || textNodes.length == 0) {
    alert('No text child');
    return '';
  }
  return textNodes[0].nodeValue;
}

function DOM() {
};
DOM.get = function(id) {
  el = document.getElementById(id);
  if (el) {
    return el;
  }
  else {
    alert('No such element: ' + id);
  }
}
DOM.getSafe = function(id) {
  return document.getElementById(id);
}
// not using object/associative array for args, because name in the name/value pair cannot be
// a variable
DOM.setAttribute = function(el, argDef) {
  if (argDef == null) {
    return;
  }
  var arg = argDef[0];
  var argVal = argDef[1];
  if (arg == 'style') {
    var s = el.style;
    if (argVal == 'float') {
      DOM.setFloat(s, argDef[2]);
    }
    else {
      s[argVal] = argDef[2];
    }
  }
  else if (arg == 'handler') {
    DOM.addEventListener(el, argVal, argDef[2]);
  }
  else {
    //alert(arg + '=' + argVal);
    if (arg == "class") {
      DOM.replaceClass(el, argVal, argDef[2]);
    }
    else {
      el.setAttribute(arg, argVal);
    }
  }
}
DOM.setAttributes = function(el, args) {
  if (args != null) {
    for (ix in args) {
      this.setAttribute(el, args[ix]);
    }
  }
}
DOM.getAttribute = function(el, argName) {
  return el.getAttribute(argName);
}
DOM.setFloat = function(styleElement, val) {
  styleElement.cssFloat = val;
  styleElement.styleFloat = val;
}
DOM.replaceClass = function(el, newClass, oldClass) {
  var attrName = '';
  /**
  if (globalBrowserType == 'IE') {
    // for IE
    attrName = "className";
  }
  else {
    attrName = "class";
  }
**/
  currentClasses = el.className; //getAttribute(attrName);
  if (currentClasses && oldClass) {
    var i = currentClasses.indexOf(oldClass);
    if (i != -1) {
      currentClasses = currentClasses.substring(0, i) + newClass + currentClasses.substring(i + oldClass.length);
    }
    else {
      currentClasses += ' ' + newClass;
    }
  }
  else {
    currentClasses = newClass;
  }
  //el.setAttribute(attrName, currentClasses);
  el.className = currentClasses;
}
DOM.element = function(elementType, args, children) {
  var el = document.createElement(elementType);
  var ix;
  DOM.setAttributes(el, args);
  DOM.appendChildren(el, children);
  return el;
}
DOM.text = function(text) {
  return document.createTextNode(text);
}
DOM.getChild = function(el) {
  c = el.childNodes[0];
  return c;
}
DOM.appendChildren = function(el, children) {
  if (children != null) {
    if (children instanceof Array) {
      for (ix in children) {
	//alert(el.nodeName + '-CHILD:' + children[ix].nodeName);
	el.appendChild(children[ix]);
      }
    }
    else {
      el.appendChild(children);
    }
  }
}
DOM.appendChild = function(el, child) {
  if (child != null) {
    el.appendChild(child);
  }
  return el;
}
DOM.removeSelf = function(el) {
  if (el != undefined) {
    var p = el.parentNode;
    if (p != undefined) {
      p.removeChild(el);
    }
  }
}
DOM.replaceChild = function(el, child, target) {
  if (child != null) {
    if (target == null) {
      target = el.childNodes[0];
    }
    if (target == undefined) {
      el.appendChild(child);
    }
    else {
      el.replaceChild(child,target);
    }
  }
  return el;
}

// remove existing children, add a new child 
DOM.setChild = function(el, child) {
  while (el.firstChild) {
    el.removeChild(el.firstChild);
  }
  el.appendChild(child);
}
DOM.setChildren = function(el, children) {
  while (el.firstChild) {
    el.removeChild(el.firstChild);
  }
  for (var i = 0; i < children.length; i++) {
    el.appendChild(children[i]);
  }
}

// NOTE: Usage of taregt means the DOM object is the object trigger the even, not the object
// the event listener is attached to (IE doesn't support the latter)
// HMMM... passing in el instead, ok?

// if handler function returns true, perform default, else not
DOM.stopPropagation = function(e) {
  if (e.stopPropagation) {e.stopPropagation();}
  e.cancelBubble = true;
}
DOM.preventDefault = function(e) {
  if (e.preventDefault) {e.preventDefault();}
  e.returnValue = false;
}
DOM.addEventListener = function(el, eventName, handlerFunction) {
  if(el.addEventListener) {
    el.addEventListener(eventName, function(e) {handlerFunction.call(this, e, el)}, false);
  }
  else if(el.attachEvent) {
    // EI
    el.attachEvent('on' + eventName, function(e) {handlerFunction.call(this, e, el)});
  }
  else {
    alert('Event Listener Error');
  }
}
DOM.create = function(domStruct) {
}
DOM.getDom = function() {
  return domObject;
}
DOM.setDom = function(dom) {
  this.domObject = dom;
}
DOM.a = function(args, children) {
  return DOM.element('a', args, children);
}
DOM.table = function(args, children) {
  // IE only works with tbody
  // might want to add thead and tfoot, since they are required by W3C spec
  // if tbody is present
  var t;
  t = DOM.element('table', args);
  return DOM.appendTableRows(t, children);
}
DOM.appendTableRows = function(elTable, children) {
  if (children != null) {
    DOM.appendChild(elTable, DOM.element('tbody', [], children));
  }
  return elTable;
}
DOM.tr = function(args, children) {
  return DOM.element('tr', args, children);
}
DOM.td = function(args, children) {
  return DOM.element('td', args, children);
}
DOM.div = function(args, children) {
  return DOM.element('div', args, children);
}
DOM.br = function(args) {
  return DOM.element('br', args, []);
}
DOM.img = function(args, children) {
  return DOM.element('img', args, children);
}
DOM.form = function(args, children) {
  return DOM.element('form', args, children);
}
DOM.input = function(args, children) {
  return DOM.element('input', args, children);
}

// attributes
function ATTR(name, value) {
  return [name, value];
};
ATTR.href = function(href) {
  return ATTR('href',href);
}
ATTR.title = function(inType) {
  return ATTR('title',inType);
}
ATTR.type = function(inType) {
  return ATTR('type',inType);
}
ATTR.colspan = function(n) {
  // upper case S for IE
  return ATTR('colSpan',n);
}
ATTR.width = function(n) {
  return ATTR('width',n);
}
ATTR.height = function(n) {
  return ATTR('height',n);
}
ATTR.id = function(n) {
  return ATTR('id',n);
}
ATTR.border = function(n) {
  return ATTR('border',n);
}
ATTR.src = function(n) {
  return ATTR('src',n);
}
ATTR.inputName = function(n) {
  return ATTR('name',n);
}
ATTR.value = function(n) {
  return ATTR('value',n);
}
ATTR.clear = function(n) {
  return ATTR('clear',n);
}
ATTR.valign = function(n) {
  return ATTR('valign',n);
}
ATTR.colspan = function(n) {
  return ATTR('colspan',n);
}

function STYLE(name, value) {
  return ['style', name, value];
}
STYLE.backgroundColor = function(color) {
  return STYLE('backgroundColor', color);
}
STYLE.border = function(def) {
  return STYLE('border', def);
}
STYLE.display = function(def) {
  return STYLE('display', def);
}
STYLE.color = function(def) {
  return STYLE('color', def);
}
STYLE.position = function(posType) {
  return STYLE('position', posType);
}
STYLE.left = function(pos) {
  return STYLE('left', pos);
}
STYLE.top = function(pos) {
  return STYLE('top', pos);
}
STYLE.width = function(pos) {
  return STYLE('width', pos);
}
STYLE.height = function(pos) {
  return STYLE('height', pos);
}
STYLE.zIndex = function(pos) {
  return STYLE('zIndex', pos);
}
STYLE.overflow = function(pos) {
  return STYLE('overflow', pos);
}
STYLE.marginTop = function(value) {
  return STYLE('marginTop', value);
}
STYLE.marginLeft = function(value) {
  return STYLE('marginLeft', value);
}
STYLE.marginRight = function(value) {
  return STYLE('marginRight', value);
}
STYLE.cssFloat = function(value) {
  return STYLE('float', value);
}
STYLE.cursor = function(value) {
  return STYLE('cursor', value);
}
STYLE.textDecoration = function(value) {
  return STYLE('textDecoration', value);
}
STYLE.ABSOLUTE = 'absolute';
STYLE.RELATIVE = 'relative';
STYLE.HIDDEN = 'hidden';

function EVENTHANDLER(name, handlerFunction) {
  return ['handler', name, handlerFunction];
}
EVENTHANDLER.click = function(handlerFunction) {
  return EVENTHANDLER('click', handlerFunction);
}
EVENTHANDLER.mouseover = function(handlerFunction) {
  return EVENTHANDLER('mouseover', handlerFunction);
}
EVENTHANDLER.mouseout = function(handlerFunction) {
  return EVENTHANDLER('mouseout', handlerFunction);
}
EVENTHANDLER.mousedown = function(handlerFunction) {
  return EVENTHANDLER('mousedown', handlerFunction);
}
EVENTHANDLER.submit = function(handlerFunction) {
  return EVENTHANDLER('submit', handlerFunction);
}

function CLASSNAME(name, oldClassName) {
  //alert(name);
  return ['class', name, oldClassName];
}

function DisplayObject() {
  this.domObject = document;
}
DisplayObject.prototype.serialize = function() {return '(unknown)';};
DisplayObject.prototype.getDom = function() {return domObject;}
DisplayObject.prototype.setDom = function(dom) {this.domObject = dom;}
DisplayObject.prototype.element = function(elementType, args) {
  this.domObject = DOM.element(elementType, args);
  return this;
}

var globalIdCnt = 0;

function DynamicMenu(className, children) {
  this.DisplayObject();
  this.children = children;
  this.className = className;
  this.root = null;
  this.parent = null;
  this.index = 0;

  this.div = null;
}
DynamicMenu.prototype = inherit('DisplayObject');
DynamicMenu.prototype.serialize = function() {
  var str = 'Menu[';
  var delim = '';
  for (c in this.children) {
    str += delim;
    str += this.children[c].serialize();
    delim = ',';
  }
  str += ']';
  return str;
}
DynamicMenu.prototype.init = function(root, parent, index) {
  if (root == null) root = this;
  this.root = root;
  this.parent = parent;
  this.index = index;
  if (this.children != null) {
    for (var i = 0; i < this.children.length; i++) {
      this.children[i].init(root, this, i);
    }
  }
}
DynamicMenu.prototype.getChildren = function() {return this.children;}
DynamicMenu.prototype.setChildren = function(children) {this.children = children;}
DynamicMenu.prototype.render = function() {
  var ix;
  var rows = [];

  var className = this.className;
  if (className == null) className = 'dynamicMenuDiv';
  var div = DOM.div([CLASSNAME(className),ATTR.width('100%')]);

  for (ix in this.children) {
    var r = this.children[ix].render();
    DOM.appendChild(div, r);
  }
  this.div = div;
  return div;
}
DynamicMenu.prototype.findSelected = function() {
  // find the menu entry after that is selected,
  // and select it (invoke callback function too)
  // returns: -1 = found no selected
  //          0 = found selected, but no subsequent sibling
  //          1 = found selected, and selected Next, operation complete
}

function MenuEntry(title, selected, highlighted, callBack, attr) {
  this.DisplayObject();
  this.title = title;
  this.selected = selected;
  this.highlighted = highlighted;
  this.callBack = callBack;
  this.attr = attr;
  this.root = null;
  this.parent = null;
  this.index = 0;

  this.div = null; // set if rendered
}
MenuEntry.prototype = inherit('DisplayObject');
MenuEntry.prototype.serialize = function() {
  return 'Entry[' + this.title + ']';
}
MenuEntry.prototype.init = function(root, parent, index) {
  this.root = root;
  this.parent = parent;
  this.index = index;

  if (this.selected) {
    this.root.oldMenuSelect = this;
  }
}
MenuEntry.prototype.getIndex = function() {return this.index;}
MenuEntry.prototype.getSibling = function(offset) {
  var children = this.parent.children;
  var newIndex = this.index + offset;
  if (newIndex >= 0 && newIndex < children.length) {
    return children[newIndex];
  }
  else {
    return null;
  }
}
MenuEntry.prototype.setCallback = function(callBack) {
  this.callBack = callBack;
}
MenuEntry.prototype.setMouseOver = function(callBack) {
  this.mouseOverFun = callBack;
}
MenuEntry.prototype.setMouseOut = function(callBack) {
  this.mouseOutFun = callBack;
}
MenuEntry.prototype.setMouseDown = function(callBack) {
  this.mouseDownFun = callBack;
}
MenuEntry.prototype.render = function() {
  var obj = this;
  // cannot use "this" here, because it has a special meaning
  var f = function(e, el) {obj.selectMenuEntry(e);};
  var fover = function(e, el) {obj.mouseOver(e);};
  var fout = function(e, el) {obj.mouseOut(e);};
  var fdown = function(e, el) {obj.mouseDown(e);};
  var div;
  var className = '';
  if (this.selected) {
    className = 'menuSelected';
  }
  else {
    className = 'menuUnselected';
  }
  if (this.highlighted) {
    className += ' menuHighlighted';
  }

  if (! this.selected) {
    div = DOM.div([CLASSNAME(className),EVENTHANDLER.click(f),EVENTHANDLER.mouseover(fover),EVENTHANDLER.mouseout(fout),EVENTHANDLER.mousedown(fdown),this.attr], DOM.text(this.title));
  }
  else {
    div = DOM.div([CLASSNAME(className),EVENTHANDLER.click(f),EVENTHANDLER.mouseover(fover),EVENTHANDLER.mouseout(fout),EVENTHANDLER.mousedown(fdown),this.attr], DOM.text(this.title));
  }
  this.div = div;
  return div;
}
MenuEntry.prototype.selectMenuEntry = function(e, args) {
  if (e != null) {
    DOM.stopPropagation(e);
  }
  var old = this.root.oldMenuSelect;
  if (old != null) {
    DOM.setAttribute(old.div, CLASSNAME('menuUnselected','menuSelected'));
  }
  this.root.oldMenuSelect = this; //el;
  DOM.setAttribute(this.div, CLASSNAME('menuSelected','menuUnselected'));
  if (this.callBack != null) {
    this.callBack(e, args);
  }
}
MenuEntry.prototype.mouseOver = function(e, args) {
  if (e != null) {
    DOM.stopPropagation(e);
  }
  if (this.mouseOverFun != null) {
    this.mouseOverFun(e, args);
  }
}
MenuEntry.prototype.mouseOut = function(e, args) {
  if (e != null) {
    DOM.stopPropagation(e);
  }
  if (this.mouseOutFun != null) {
    this.mouseOutFun(e, args);
  }
}
MenuEntry.prototype.mouseDown = function(e, args) {
  if (e != null) {
    DOM.stopPropagation(e);
  }
  if (this.mouseDownFun != null) {
    this.mouseDownFun(e, args);
  }
}



// unfortunately has to be after SubMenu because of inherit function is executed
// at compile time

function SubMenu(title, status, children, attr) {
  this.MenuEntry(title);
  this.status = status;
  if (children != null) {
    this.submenu = new DynamicMenu('subMenu', children);
  }
  else {
    this.submenu = null;
  }
  this.attr = attr;
  this.subs = null; // set when rendering
}
SubMenu.STATUS_CLOSED = 0;
SubMenu.STATUS_OPEN = 1;
SubMenu.prototype = inherit('MenuEntry');
SubMenu.prototype.serialize = function() {
  return 'Sub[' + this.submenu.serialize() + ']';
}
SubMenu.prototype.init = function(root, parent, index) {
  this.root = root;
  this.parent = parent;
  this.index = index;
  if (this.submenu != null) {
    this.submenu.init(root, this, 0);
  }
}
SubMenu.prototype.render = function() {
  var div = DOM.div();
  var subs = null;
  if (this.submenu != null) {
    subs = DOM.div([STYLE.display(this.status == SubMenu.STATUS_OPEN?'block':'none')], [this.submenu.render()]);
  }
  var obj = this;
  f = function() {obj.toggleSubMenu();};
  var title = DOM.div([CLASSNAME('menuTitle'),ATTR.width('100%'),EVENTHANDLER.click(f),this.attr], DOM.text(this.title));
  DOM.appendChild(div, title);
  DOM.appendChildren(div, subs);
  this.subs = subs;
  this.div = div;
  return div;
}
SubMenu.prototype.toggleSubMenu = function(openClose) {
  var subMenuRow = this.subs;
  if (subMenuRow.style.display != 'none') {
    if (openClose == null || openClose == 'close') {
      subMenuRow.style.display = 'none';
    }
  }
  else {
    if (openClose == null || openClose == 'open') {
      subMenuRow.style.display = 'block';
    }
  }
}

function MenuResults(status, children) {
  this.SubMenu('RESULTS', status, children);
}
MenuResults.prototype = inherit('SubMenu');
MenuResults.prototype.serialize = function() {
  return 'Results[' + this.submenu.serialize() + ']';
}

function MenuChats(status, children) {
  this.SubMenu('CHATS', status, children);
}
MenuChats.prototype = inherit('SubMenu');
MenuChats.prototype.serialize = function() {
  return 'Chats[' + this.submenu.serialize() + ']';
}

function MenuBookmarks(status, children) {
  this.SubMenu('FAVORITES', status, children);
}
MenuBookmarks.prototype = inherit('SubMenu');
MenuBookmarks.prototype.serialize = function() {
  return 'Bookmarks[' + this.submenu.serialize() + ']';
}

function MenuTours(status, children) {
  this.SubMenu('GUIDED TOURS', status, children);
}
MenuTours.prototype = inherit('SubMenu');
MenuTours.prototype.serialize = function() {
  return 'Tours[' + this.submenu.serialize() + ']';
}

function MenuInventory(status, children) {
  this.SubMenu('INVENTORY', status, children, STYLE.color('#dddd00'));
}
MenuInventory.prototype = inherit('SubMenu');
MenuInventory.prototype.serialize = function() {
  return 'Inventory[' + this.submenu.serialize() + ']';
}

function MenuBooth(status, children) {
  this.SubMenu('BOOTH', status, children, STYLE.color('#dddd00'));
}
MenuBooth.prototype = inherit('SubMenu');
MenuBooth.prototype.serialize = function() {
  return 'Booth[' + this.submenu.serialize() + ']';
}

// support functions

//set the opacity for different browsers
function setOpacity(el, opacity) {
  el.opacity = (opacity / 100);
  el.MozOpacity = (opacity / 100);
  el.KhtmlOpacity = (opacity / 100);
  if (opacity == 100) {
    el.filter = null;
  }
  else {
    el.filter = "alpha(opacity=" + opacity + ")";
  }
}

function setupFadeOutIn(divOut, divIn, onComplete, time) {
  time = (time == null?0.75:time);
  // fade out div0, fade in dev1
  if (divOut != null && divOut != undefined) {
    if (divOut.style != undefined) {
      JSTweener.addTween(divOut.style, {time: time, transition: 'easeOutQuad', opacity:0, getter:{opacity:100}, setter:{opacity:setOpacity}});
    }
  }
  JSTweener.addTween(divIn.style, {time: time, transition: 'easeOutQuad', opacity:100, getter:{opacity:0}, setter:{opacity:setOpacity}, onComplete:onComplete});
}

function tweenReplace(parentDiv, newChild, time) {
  var child = DOM.getChild(parentDiv);

  setOpacity(newChild.style, 0);
  DOM.appendChild(parentDiv, newChild);

  var f = function() {DOM.removeSelf(child)};
  setupFadeOutIn(child, newChild, f, time);
}

function tweenReplaceMove(div, containerDiv, moveTo) {
  var child = DOM.getChild(div);

  setOpacity(containerDiv.style, 0);
  DOM.appendChild(div, containerDiv);

  var f = function() {DOM.removeSelf(child);moveDisplayTo(containerDiv, -moveTo)};
  setupFadeOutIn(child, containerDiv, f);
}

function moveDisplayTo(div, moveTo) {
  //alert(moveTo);
  if (div.style.left == '0pt') {
    div.style.left = '0px';
  }
  JSTweener.addTween(div.style, {time: 0.5, transition: 'easeOutQuad', left:moveTo, suffix:{left:'px'}});
}

displayScale = 0.04;
dpi = 72; // does not have to be accurate - just consistent with scaling
dpmm = dpi * 0.03937;

