var Ant = {};
Ant.Serializer = function () {
this._classMap = new Ant.Serializer.ClassMap();
};
Ant.Serializer.setDefaultStorage = function (storage)
{
Ant.Serializer._defaultStorage = storage;
};
Ant.Serializer.getDefaultStorage = function ()
{
if (null == Ant.Serializer._defaultStorage) {
Ant.Serializer._defaultStorage = new Ant.Serializer[Ant.Serializer._defaultStorageName];
}
return Ant.Serializer._defaultStorage;
};
Ant.Serializer._defaultStorage = null;
Ant.Serializer._defaultStorageName = 'XmlStorage';
with (Ant.Serializer)
{
prototype.register = function (name, constr)
{
this._classMap.register(name, constr);
};
prototype.getClassMap = function ()
{
return this._classMap;
};
prototype.save = function (object, writer)
{
if (!writer) {
writer = Ant.Serializer.getDefaultStorage().createWriter(this);
}
this._saveObject(object, writer);
return writer;
};
prototype._saveObject = function (object, writer)
{
var objectWriter = writer.writeObject(object);
for (var p in object) {
this._saveProperty({ 'name' : p }, object[p], objectWriter);
}
return objectWriter;
};
prototype._saveProperty = function (property, value, objectWriter)
{
if ('object' == typeof value && null != value) {
var propObjectWriter = this._saveObject(value, objectWriter.getWriter());
objectWriter.writeProperty(property, propObjectWriter.getObjectRef());
} else {
objectWriter.writeProperty(property, value);
}
};
prototype.load = function (arg)
{
if (arg instanceof Ant.Serializer.IReader) {
return this._loadObject(arg);
}
return this._loadObject(Ant.Serializer.getDefaultStorage().createReader(arg, this));
};
prototype._loadObject = function (reader, ref)
{
var objectReader;
if ('undefined' == typeof ref) {
objectReader = reader.readObject()
} else {
objectReader = reader.readObject(ref);
}
var object = objectReader.getObject();
for (var p in object) {
this._loadProperty({ 'name' : p }, object, objectReader);
}
return object;
};
prototype._loadProperty = function (property, object, objectReader)
{
var ref = objectReader.tryGetObjectRef(property);
if (null == ref) {
objectReader.readProperty(property, object);
} else {
object[property.name] = this._loadObject(objectReader.getReader(), ref);
}
};
}
Ant.Serializer.IReader = function ()
{};
Ant.Serializer.IObjectRef = function ()
{};
Ant.Serializer.ClassMap = function ()
{
this._nameConstructorMap = {};
this._constructorNameMap = {};
this.register('Date', new Date().constructor);
};
with (Ant.Serializer.ClassMap)
{
prototype.register = function (name, constr)
{
this._nameConstructorMap[name] = constr;
this._constructorNameMap[constr] = name;
};
prototype.constr = function (name)
{
return this._nameConstructorMap[name];
};
prototype.name = function (obj)
{
var constructor = obj.constructor;
var constr = constructor.toString().replace(/^\s*/, '');
var type = constr.substr(8, constr.indexOf('(') - 8).replace(/[\s\n\r]*/g, '');
if ('' == type) {
return this._constructorNameMap[constructor.toString()];
}
return type;
};
}
/**
* Xml Storage incapsulates logic, specific to
* saving objects to XML string.
*/
Ant.Serializer.XmlStorage = function ()
{
this._adapter = null;
};
with (Ant.Serializer.XmlStorage)
{
prototype.createWriter = function (serializer)
{
return new Ant.Serializer.XmlStorage.Writer(this, serializer);
};
prototype.createReader = function (data, serializer)
{
return new Ant.Serializer.XmlStorage.Reader(data, this, serializer);
};
prototype._createAdapter = function ()
{
var adapter = '';
if ('undefined' != typeof ActiveXObject) {
adapter = 'MS';
} else if ('undefined' != typeof document
&& document.implementation
&& document.implementation.createDocument
&& 'undefined' != typeof DOMParser)
{
adapter = 'default';
}
switch (adapter) {
case 'MS':
return new (function () {
this.createDocument = function () {
var names = ["Msxml2.DOMDocument.6.0",
"Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument",
"MSXML.DOMDocument", "Microsoft.XMLDOM"];
for (var key in names) {
try {
return new ActiveXObject(names[key]);
} catch (e) {}
}
throw new Error('Unable to create DOMDocument');
};
this.serialize = function (doc) {
return doc.xml;
};
this.parseXml = function (xml) {
var doc = this.createDocument();
if (!doc.loadXML(xml)) {
throw new Error('Parse error');
}
return doc;
};
})();
case 'default':
return new (function () {
this.createDocument = function () {
return document.implementation.createDocument("", "", null);
};
this.serialize = function (doc) {
return new XMLSerializer().serializeToString(doc);
};
this.parseXml = function (xml) {
var doc = new DOMParser().parseFromString(xml, "text/xml");
if ("parsererror" == doc.documentElement.nodeName) {
throw new Error('Parse error');
}
return doc;
};
})();
default:
throw new Error('Unable to select the DOM adapter');
}
};
prototype.getDomAdapter = function ()
{
if (null == this._adapter) {
this._adapter = this._createAdapter();
}
return this._adapter;
};
}
Ant.Serializer.XmlStorage.Writer = function (storage, serializer)
{
this._serializer = serializer;
this._storage = storage;
this._document = this._storage.getDomAdapter().createDocument();
};
with (Ant.Serializer.XmlStorage.Writer)
{
prototype.writeObject = function (obj)
{
var name = this._serializer.getClassMap().name(obj);
var node = this._document.createElement(name);
if (!this._document.documentElement) {
this._document.appendChild(node);
}
if ('Date' == name) {
node.setAttribute('value', obj.getUTCFullYear() + '-'
+ obj.getUTCMonth() + '-' + obj.getUTCDate()
+ 'T' + obj.getUTCHours() + ':' + obj.getUTCMinutes()
+ ':' + obj.getUTCSeconds() + '.' + obj.getUTCMilliseconds());
}
return new Ant.Serializer.XmlStorage.ObjectWriter(this, node);
};
prototype.toString = function ()
{
return this._storage.getDomAdapter().serialize(this._document);
};
}
Ant.Serializer.XmlStorage.ObjectWriter = function (writer, node)
{
this._writer = writer;
this._node = node;
};
with (Ant.Serializer.XmlStorage.ObjectWriter)
{
prototype.writeProperty = function (property, value)
{
var doc = this._node.ownerDocument;
var element = this._node.appendChild(doc.createElement(property.name));
if (value instanceof Ant.Serializer.IObjectRef) {
element.appendChild(value._data);
} else if (null != value) {
if (!property.type) {
element.setAttribute('type', typeof value);
}
element.appendChild(doc.createTextNode(value.toString()));
}
};
prototype.getWriter = function ()
{
return this._writer;
};
prototype.getObjectRef = function ()
{
var ref = new Ant.Serializer.IObjectRef();
ref._data = this._node;
return ref;
};
}
Ant.Serializer.XmlStorage.Reader = function (data, storage, serializer)
{
this._serializer = serializer;
this._storage = storage;
this._document = this._storage.getDomAdapter().parseXml(data);
};
with (Ant.Serializer.XmlStorage.Reader)
{
prototype = new Ant.Serializer.IReader();
prototype.readObject = function (ref)
{
if ('undefined' == typeof ref) {
return new Ant.Serializer.XmlStorage.ObjectReader(this, this._document.documentElement);
}
return new Ant.Serializer.XmlStorage.ObjectReader(this, ref._data);
};
prototype.getSerializer = function ()
{
return this._serializer;
};
}
Ant.Serializer.XmlStorage.ObjectReader = function (reader, node)
{
this._reader = reader;
this._node = node;
var name = this._node.nodeName;
var constr = this._reader.getSerializer().getClassMap().constr(this._node.nodeName);
this._object = new constr();
if ('Date' == name) {
var parts = this._node.getAttribute('value').split(/[\-\T\:\.]/);
with (this._object) {
setUTCFullYear(parts[0]);
setUTCMonth(parts[1]);
setUTCDate(parts[2]);
setUTCHours(parts[3]);
setUTCMinutes(parts[4]);
setUTCSeconds(parts[5]);
setUTCMilliseconds(parts[6]);
}
}
};
with (Ant.Serializer.XmlStorage.ObjectReader)
{
prototype.getObject = function ()
{
return this._object;
};
prototype.tryGetObjectRef = function (property)
{
var propertyNode = this.getChildNodeByName(this._node, property.name);
if (null != propertyNode.firstChild && 1 /*=ELEMENT*/ == propertyNode.firstChild.nodeType) {
var ref = new Ant.Serializer.IObjectRef();
ref._data = propertyNode.firstChild;
return ref;
}
return null;
};
prototype.readProperty = function (property, object)
{
var node = this.getChildNodeByName(this._node, property.name);
if (node) {
if (0 == node.childNodes.length) {
object[property.name] = null;
} else {
var type = (property.type) ? type = property.type : node.getAttribute('type');
switch (type) {
case 'number':
object[property.name] = Number(node.childNodes[0].nodeValue);
break;
case 'boolean':
object[property.name] = ('true' == node.childNodes[0].nodeValue);
break;
case 'undefined':
// do nothing
break;
default:
object[property.name] = node.childNodes[0].nodeValue;
break;
}
}
}
};
prototype.getReader = function ()
{
return this._reader;
};
prototype.getChildNodeByName = function (node, name) {
var nl = node.childNodes;
for (var i = 0; i < nl.length; i++) {
if (nl.item(i).nodeName == name) {
return nl.item(i);
}
}
return null;
};
}