/*
 * THIS IS A SHARED LIBRARY INSTALLED BY ONE OF EDITME'S MODULES
 *
 * Provides simple JavaScript object conversion to and from XML.
 *
 * Version History
 *    3. Add readObject(key, className), saveObject(key, obj) and 
 *       version property
 *    2. Add combine(..) method.
 *    1. Initial release.
 *
 * Usage: 
 *
 *   // create native JavaScript object (could also use a class, though
 *   //  functions are not persisted)
 *   var obj = new Object();
 *   obj.name = 'Fred';
 *   obj.age = 10;
 *   obj.lastUpdate = new Date();
 *   obj.children = new Array();
 *   obj.children[0] = 'Sandy';
 *
 *   var xml = o2x.objectToXml(obj);
 *   // xml can now be stored or passed through a form post as a string
 *
 *   // get the object back from the XML string
 *   var readback = o2x.xmlToObject(xml);
*/

function O2X() {
  this.version = 3;
}

O2X.prototype.objectToElement = function (o, name) {
  var el;
  try {
    var type = typeof o;
  } catch (e) {
    var type = 'Java Object';
  }
  if (type == 'number' || o instanceof Number) {
    el = Packages.org.dom4j.DocumentHelper.createElement("n");
    el.text = o;
  } 
  else if (type == 'string' || o instanceof String || type == 'Java Object') {
    el = Packages.org.dom4j.DocumentHelper.createElement("s");
    el.text = o;
  } 
  else if (type == 'boolean' || o instanceof Boolean) {
    el = Packages.org.dom4j.DocumentHelper.createElement("b");
    el.text = o?'1':'0';
  } 
  else if (o instanceof Date) {
    el = Packages.org.dom4j.DocumentHelper.createElement("d");
    el.text = util.formatDate(o, 'yyyy-MM-dd hh:mm:ss SSS');
  } 
  else if (o instanceof Array || o instanceof Object) {
    if (o instanceof Array) {
      el = Packages.org.dom4j.DocumentHelper.createElement("a");
    } else {
      el = Packages.org.dom4j.DocumentHelper.createElement("o");
    }
    var i;
    for (i in o) {
      var sel = this.objectToElement(o[i], i);
      el.add(sel);
    }
  }
  else {
     el = Packages.org.dom4j.DocumentHelper.createElement("u");     
  }
  if (name!=undefined) el.addAttribute("i", name);
  return el;
}

O2X.prototype.objectToXml = function (o) {
  return this.objectToElement(o).asXML();
}

O2X.prototype.elementToObject = function (el) {
  var type = el.name;
  if (type == 's') {
    return el.text;
  } 
  else if (type == 'n') {
    return Number(el.text);
  } 
  else if (type == 'b') {
    return el.text == '1';
  }
  else if (type == 'd') {
    return util.parseDate(el.text, 'yyyy-MM-dd hh:mm:ss SSS');
  }
  else if (type == 'a' || type == 'o') {
    var ret = (type=='a')? new Array() : new Object();
    var elements = el.elements();
    var i;
    for (i=0; i<elements.length; i++) {
      var sel = elements[i];
      var name = sel.attributeValue('i');
      if (name == null) name = i;
      ret[name] = this.elementToObject(sel);
    }
    return ret;
  }
  else if (type == 'u') {
    // ignore
  } 
  else {
    throw 'Unsupported tag name: ' + type;
  }
}

// converts the given XML string to a JavaScript object
O2X.prototype.xmlToObject = function (xml) {
  var doc = util.parseXML(xml);
  if (doc == null) throw 'Invalid XML';
  return this.elementToObject(doc.rootElement);
}

// accepts an array of data entries and combines 
// the values into an xml document, which is then
// parsed into an array - this is MUCH faster than
// calling xmlToObject on each individual value.
O2X.prototype.combine = function (entries) {
  var sb = new Packages.java.lang.StringBuffer();
  sb.append('<a>');
  for (var i in entries) {
    sb.append(entries[i].value);
  }
  sb.append('</a>');
  return this.xmlToObject(sb.toString());
}

// reads the data entry identified by 'key'
// and returns object, or creates new instance
// of 'className' (should be a function pointer)
// if the entry isn't found.
O2X.prototype.readObject = function (key,className) {
  var de = data.get(key);
  if (de==null) return new className();
  else return this.xmlToObject(de.value);
}

// saves the given object to a new or existing
// data entry identified by 'key'
O2X.prototype.saveObject = function (key,obj) {
  var de = data.get(key);
  if (de==null) {
    de = data.newEntry();
    de.key = key;
  }
  de.value = this.objectToXml(obj);
  de.save();
}

var o2x = new O2X();

