

/* CSS */

function i_(name) {
  return name;
} 

function c_(name) {
  return name;
} 

/* Inheritance */

Function.prototype.inherits = function(clazz) {
  this.prototype = new clazz;
  this.superclass = clazz.prototype;
  this.prototype.constructor = this;
} 

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}

var Class = {
  create: function() {
    var constructor = function() { 
      if (this.initialize)
        this.initialize.apply(this, arguments);
    }
    constructor.prototype.extend = function(object) {
      return Object.extend.apply(this, [this, object]);
    }
    return constructor;
  }
}

/* Array */

if (!Array.prototype.push) {
  Array.prototype.push = function() {
    var startLength = this.length;
    for (var i=0; i<arguments.length; i++) {
      this[startLength+i] = arguments[i];
    } 
    return this.length;
  } 
} 

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(elt) {
    for (var i = 0; i<this.length; i++) {
      if (this[i] == elt)
        return i;
    } 
    return -1;
  }; 
}

/* Hashtable */

var Hashtable = function() {};
Hashtable.serialize = function(hashtable) {
  var result = "{";
  var count = 0;
  for (var key in hashtable) {
    if (count != 0) result += ", ";
    var quote = '';
    if(typeof hashtable[key] == "string")
      quote = '"';
    result += key+': '+quote+hashtable[key]+quote;
    count++;
  } 
  result += "}";
  return result;
}

Hashtable.deserialize = function(str) {
  eval("var result = "+str+";");
  return result;
} 

/* Cross-browser DOM */

function Event(event) {
  var self = event;
  if (!self.preventDefault) {
      self.preventDefault = function() { self.returnValue = false; };
  }
  if (!self.stopPropagation) {
    self.stopPropagation = function() { self.cancelBubble = true; };
  }
  self.stop = function() { self.preventDefault(); self.stopPropagation();};
  if ((!self.target) && self.srcElement) {
    self.target = self.srcElement;
  } 
  return self;
} 

function Node(element) {
  var self = element;
  if (!self.addEventListener) {
    self.addEventListener = function(event, callback, useCapture) {
      return self.attachEvent("on"+event, callback);
    };
  } 
  if (!self.removeEventListener) {
    self.removeEventListener = function(event, callback, useCapture) {
      return self.detachEvent("on"+event, callback);
    }; 
  }

  self.hasClassName = function(className) {
    var classNames = self.getClassNames();
    for (var i=0; i<classNames.length;i++) {
      if (className == classNames[i]) return true;
    } 
    return false;
  }; 

  self.getClassNames = function() {
    var classString = self.className;
    var classNames = classString.split(" ");
    return classNames;
  }; 

  self.addClassName = function(className) {
    var classNames = self.getClassNames();
    for (var i=0; i<classNames.length;i++) {
      if (className == classNames[i]) return;
    } 
    self.className += " "+className;
  }; 

  self.removeClassName = function(className) {
    var classNames = self.getClassNames();
    var newClass = "";
    for (var i=0; i<classNames.length;i++) {
      if (className != classNames[i]) {
        newClass += " "+classNames[i];
      } 
    }; 
    self.className = newClass;
  } 

  self.getText = function() { return self.textContent ? self.textContent : self.innerText;};
  return self;
} 

Document(document);

function Document(document) {
  var self = new Node(document);

  //get elements by class name: classname is the css class,
  //node is the root node of the search (defaults to document),
  //tagname is also optional and limits the search to tags of a certain type.
  document.getElementsByClassName = function(classname, node, tagname) {
    var topnode = node ? node : this;
    var result = new Array();
    var processnode = function(aNode, recurse) {
      var cname = ""+aNode.className;
      var classes = cname.split(" ");
      for (var j=0; j<classes.length; j++) {
        if (classes[j] == classname) {
          result[result.length] = aNode;
        } 
      } 
      if (recurse) {
        for (var i=0; i<aNode.childNodes.length; i++) {
          processnode(aNode.childNodes[i], recurse);
        } 
      } 
    }; 
    var nodesToProcess;
    var recurse = false;
    if (tagname) {
      nodesToProcess = topnode.getElementsByTagName(tagname);
    } else {
      recurse = true;
      nodesToProcess = topnode.childNodes;
    } 
    for (var i=0; i<nodesToProcess.length; i++) processnode(nodesToProcess[i], recurse);
    return result;
  };
  return self;
} 

/* Cookies */

if (!window.Cookie) {
  var Cookie = new Object();
} 
Cookie.getValue = function (name) {
  if (document.cookie.length>0) {
    var start = document.cookie.indexOf(name+"=");
    if (start != -1) { 
      start = start + name.length + 1 ;
      end = document.cookie.indexOf(";",start);
      if (end == -1)
        end = document.cookie.length;
      return unescape(document.cookie.substring(start,end));
    } 
  }
  return null;
} 

Cookie.setValue = function (name, value, daysDuration, path) {
  var exdate=new Date();
  exdate.setDate(daysDuration); 
  document.cookie=name+ "=" +escape(value)+";expires="+exdate+";path="+(path ? path : "/");
} 

/* User Interface interactive elements */

function Border(element,width,side,zIndex) {
  //See parasitic inheritance at http://www.crockford.com/javascript/inheritance.html
  var node = new Node(element);
  var self = new Node(document.createElement("div"));
  self.setPosition = function(node,width,side,zIndex) {
    if (zIndex) {
      self.style.zIndex = zIndex;
    } else {
      self.style.zIndex = 4;
    }
    self.style.position = "absolute";
    if (side == "right") {
      self.style.top = node.offsetTop+"px";
      self.style.left = (node.offsetLeft + node.offsetWidth - width ) + "px";
      self.style.width = width+"px";
      self.style.height = node.clientHeight+"px";
    } else if (side == "left") {
      self.style.top = node.offsetTop+"px";
      self.style.height = node.clientHeight+"px";
      self.style.left = node.offsetLeft+"px";
      self.style.width = width+"px";
    } else if (side == "top") {
      self.style.top = node.offsetTop+"px";
      self.style.width = node.clientWidth+"px";
      self.style.left = node.offsetLeft+"px";
      self.style.height = width+"px";
    } else if (side == "bottom") {
      self.style.top = (node.offsetTop + node.offsetHeight - width) + "px";
      self.style.width = node.clientWidth+"px";
      self.style.left = node.offsetLeft+"px";
      self.style.height = width+"px";
    } 
  }
  self.setPosition(node,width,side,zIndex);
  node.parentNode.insertBefore(self,node);
  Node(window).addEventListener("resize", function(event){
                                self.setPosition(node,width,side,zIndex);
                                self.setPosition(node,width,side,zIndex);//do it twice for mozilla that doesnt have final values the first time.
                                }, true);
  return self;
}

function Draggable(element) {
  var self = Node(element);
  self.onStartDrag = function(event) {};
  self.onStopDrag = function(event) {};
  self.onDrag = function(event) {};
  self.isDragged = false;
  self.mousedown =  function(event) {
                          Event(event);
                          self.isDragged = true;
                          self.onStartDrag(event);
                          event.preventDefault();
                          event.stopPropagation();
                        };

  self.mouseup = function(event) {
                          Event(event);
                          if (!self.isDragged)
                            return;
                          self.isDragged = false;
                          self.onStopDrag(event);
                          event.preventDefault();
                          event.stopPropagation();
                        };

  self.mousemove = function(event) {
                              Event(event);
                              if (!self.isDragged)
                                return;
                              self.onDrag(event);
                              event.preventDefault();
                              event.stopPropagation();
                            };
  self.addEventListener("mousedown", self.mousedown, false);
  document.addEventListener("mouseup", self.mouseup, false);
  document.addEventListener("mousemove", self.mousemove, false);
  for (var i=0; i<window.frames.length; i++) {
    var f = window.frames[i];
    try {
    Document(f.document);
    f.document.addEventListener("mouseup", self.mouseup, false);
    f.document.addEventListener("mousemove", self.mousemove, false);
    } catch(e) {
      //frames dont point to the same domain: security exception
    }
  }
  return self;
}

function consoleLog(text) {
  var consoleWindow = window.open("", "javascriptConsole", 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=500,height=100');
  consoleWindow.document.body.innerHTML += "<xmp>"+text+"</xmp>\n";
}

/* XMLHttpRequest */

if (!window.XMLHttpRequest) {
  window.XMLHttpRequest = function() { return new ActiveXObject("Msxml2.XMLHTTP"); };
} 

/* XML NodeSerializer */

if (window.XMLSerializer && new XMLSerializer().serializeToString(document.createElement("div"))) {
  window.NodeSerializer = window.XMLSerializer;
} else {
  window.NodeSerializer = function () {};
  window.NodeSerializer.prototype.serializeToString = function(node) {
    if (node.xml)
      return node.xml;
    if (node.nodeName == "#text")
      return node.data;
    var result = "<"+node.nodeName;
    for (var i=0; i<node.attributes.length; i++) {
      if (node.attributes[i].specified)
        result += " "+node.attributes[i].name+"=\""+node.attributes[i].value+"\"";
    } 
    result += ">"+node.innerHTML+"</"+node.nodeName+">";
    return result;
  };
}

/* Ajax Actions */

var AjaxAction = Class.create();

AjaxAction.observeId = function(cssId, callback) {
  if (!AjaxAction.observers)
    AjaxAction.observers = new Array();
  AjaxAction.observers.push({cssId: cssId, callback: callback});
} 
AjaxAction.update = function(ajaxEnvelope) {
  var objXMLSerializer = new NodeSerializer;
  var xhtmlcontents = ajaxEnvelope.getElementsByTagName("XhtmlContent");
  for (var i=0; i<xhtmlcontents.length; i++) {
    var xhtmlcontent = xhtmlcontents.item(i);
    var slot = document.getElementById(xhtmlcontent.getAttribute("dest"));
    var slotcontent = "";
    for (var j=0; j<xhtmlcontent.childNodes.length; j++) {
      //alert(objXMLSerializer.serializeToString(xhtmlcontent.childNodes.item(j)));
      var strXML = objXMLSerializer.serializeToString(xhtmlcontent.childNodes.item(j));
      slotcontent += strXML;
    } 
    slot.innerHTML = slotcontent;
    for (var j=0; AjaxAction.observers && j<AjaxAction.observers.length; j++) {
      if (AjaxAction.observers[j].cssId == slot.id) {
        AjaxAction.observers[j].callback(slot);
      } 
    } 
  } 
} 

AjaxAction.prototype.extend({

initialize: function() {
  this.uiActions = new Array();
  this.callbacks = new Array();
  this.arguments = new Object();
},

setUrl: function(url) {
  this.url = function() {return url;};
  return this;
}, 

addUiAction: function(uiAction) {
  this.uiActions.push(uiAction);
  return this;
},

addArguments: function(hashtable) {
  for (var name in hashtable) {
    this.arguments[name] = hashtable[name];
  } 
  return this;
},

addFormElements: function(elements) {
  for(var i=0; i<elements.length; i++) {
    var element = elements[i];
    if(element.name != 'uia') {
      this.arguments[element.name] = element.value;
    }
  }
  return this;
},

addCallback: function(callback) {
  this.callbacks.push(callback);
  return this;
}, 

url: function() {
  var tokens = new Array();
  for (var i=0; i<this.uiActions.length; i++) {
    tokens.push('uia'+'='+encodeURIComponent(this.uiActions[i]));
  } 
  for (var name in this.arguments) {
    if (Function.prototype.isPrototypeOf(this.arguments[name]))
      continue;
    tokens.push(encodeURIComponent(name)+"="+encodeURIComponent(this.arguments[name]));
  } 
  return '?'+tokens.join('&');
},

execute: function() {
  var req = new XMLHttpRequest();
  var callbacks = this.callbacks;
  var url = this.url();
  req.open('GET', url, true);
  req.onreadystatechange = function() {
    if(req.readyState == 4 && req.status == 200) {
      //consoleLog(req.responseText);
      AjaxAction.update(req.responseXML);
      for (var i=0; i<callbacks.length; i++)
        callbacks[i]();
    } 
  }; 
  if(req.overrideMimeType)
    req.overrideMimeType('text/xml');
  req.send(null);
  return false;
} 
});

/* Client Session */

var ClientSession = new Object();
ClientSession.COOKIE_NAME = "ClientSession";
ClientSession.COOKIE_DURATION = 100; //100 days

ClientSession.get = function(key) {
  return ClientSession.read()[key];
};

ClientSession.read = function() {
  var cookieval = Cookie.getValue(ClientSession.COOKIE_NAME);
  if (cookieval != null)
    ClientSession.session = Hashtable.deserialize(cookieval);
  else
    ClientSession.session = new Hashtable();
  return ClientSession.session;
} 

ClientSession.getInt = function(key) { return parseInt(ClientSession.get(key)); };

ClientSession.getFloat = function(key) { return parseFloat(ClientSession.get(key)); };

ClientSession.set = function(key, value) {
  ClientSession.read()[key] = value;
  Cookie.setValue(ClientSession.COOKIE_NAME, Hashtable.serialize(ClientSession.session), ClientSession.COOKIE_DURATION);
};

