/**
 * Miscellaneous SST utilities
 */
com_pagasg_xxapp_serialize = new es_lang.Package(true,
	/*Title*/   'Testing Package',
	/*Docs */   '-- none --',
	/*Package*/ function() {
		// Imports
		var LANG = es_lang;
		var StringBuilder = LANG.StringBuilder;

		// Constructor imports
		var Class = es_lang.Class;
		var Enum = es_lang.Enum;
		var StringBuilder = LANG.StringBuilder;

		// Function imports
		var extend = Class.extend;
		var implement = Class.implement;
		var enumerate = Enum.enumerate;

		/****** XmlAttribute ******/
		var XmlAttribute = function(ns, localName, value) {
			this.localName = localName;
			this.ns = ns;
			this.value = value;

			this.toString = function() {
				return value;
			}
		}

		/****** XmlElement ******/
		var XmlElement = function(ns, localName, attributes, children) {
			this.localName = localName;
			this.ns = ns;
			this.attributes = attributes;
			this.children = children;

			if (children.length == 1) {
				if (children[0].constructor == String) {
					this.text = children[0];
				}
			}

			for (var i = 0; i < attributes.length; i++) {
				var attr = attributes[i];
				if (attr.ns == null || attr.ns == '') {
					this['@' + attr.localName] = attr.value;
				}
			}

			function isEmpty(str) {
				return str == undefined || str == null || str == '';
			}

			// Local
			function matchName(xml1, localName, ns) {
				if (xml1) {
					if (xml1.localName == localName) {
						if (!xml1.ns && !ns) {
							return true;
						} else {
							return (xml1.ns == ns)
						}
					}
				}

				return false;
			}
			function matchNames(xml1, xml2) {
				if (xml1 && xml2) {
					if (xml1.localName == xml2.localName) {
						if (!xml1.ns && !xml2.ns) {
							return true;
						} else {
							return (xml1.ns == xml2.ns)
						}
					}
				}

				return false;
			}

			// Public
			this.rename = function(localName, ns) {
				return new XmlElement(ns, localName, attributes, children);
			};
			this.getAttributes = function() {
				arr = [];
				for (var i = 0; i < attributes.length; i++) arr.push(attributes[i]);
				return arr;
			}
			this.getChildren = function(localName, ns) {
				var arr = [];
				var child;

				for (var i = 0; i < children.length; i++) {
					child = children[i];
					if (arguments.length == 0) {
							arr.push(child);
					} else if (child.localName == localName) {
						if (isEmpty(child.ns) && isEmpty(ns)) {
							arr.push(child);
						} else if (child.ns == ns) {
							arr.push(child);
						}
					}
				}

				return arr;
			};
			this.getChildByIndex = function(index) {
				var child;
				
				// TODO: put a mod in here.
				if (children) {
					if (index < 0) index = index + children.length;
					if (index > 0 || index < children.length) {
						return children[index];
					}
				}
				return null;
			};
			this.getChildCount = function() {
				if (children) {
					return children.length;
				} else {
					return 0;
				}
			}
			this.getChild = function(localName, ns) {
				var child;

				for (var i = 0; i < children.length; i++) {
					child = children[i];
					if (child.localName == localName) {
						if (isEmpty(child.ns) && isEmpty(ns)) {
							return child;
						} else if (child.ns == ns) {
							return child;
						}
					}
				}

				return null;
			};
			this.getAttribute = function(localName, ns) {
				var attr;

				for (var i = 0; i < attributes.length; i++) {
					attr = attributes[i];
					if (attr.localName == localName) {
						if (isEmpty(attr.ns) && isEmpty(ns)) {
							return attr;
						} else if (attr.ns == ns) {
							return attr;
						}
					}
				}

				return null;
			};

			// Modify
			this.setAttribute = function(value, localName, ns) {
				var attr;
				var index;
				var found;
				var newAttr = new XmlAttribute(ns, localName, value);

				found = false;
				for (index = 0; index < attributes.length; index++) {
					attr = attributes[index];
					if (matchNames(attr, newAttr)) {
						attributes[index] = newAttr;
						found = true;
						break;
					} else {
						attr = null;
					}
				}

				if (!found) {
					attributes.push();
				}

				return attr;
			};
			this.removeChildren = function(localName, ns, max) {
				var child;
				var count = 0;
				var removals = [];

				for (var i = children.length - 1; i >= 0; i--) {
					child = children[i];
					if (matchName(child, localName, ns)) {
						count++;
						if (max && count < max) {
							removals.unshift(children.splice(i, 1));
						}
					}
				}

				return removals;
			};
			this.removeChild = function(localName, ns) {
				var pos;
				var child;

				pos = -1;
				for (var i = children.length - 1; i >= 0; i--) {
					child = children[i];
					if (matchName(child, localName, ns)) {
						children.splice(i, 1);
						break;
					}
					child = null;
				}

				return child;
			};
			this.replaceChild = function(child, newChild) {
				var oldChild;
				var pos;
				
				for (pos = 0; pos < children.length; pos++) {
					oldChild = children[pos];
					if (child === oldChild) {
						break;
					}
				}

				if (newChild) {
					children[pos] = newChild;
				} else {
					children.splice(pos, 1);
				}

				return child;
			};
			this.addChild = function(newChild, insert) {
				var child;
				var found;
				var pos;

				found = false;
				for (pos = 0; pos < children.length; pos++) {
					child = children[pos];
					if (!found) {
						found = matchNames(child, newChild);
						if (insert) break;
					} else {
						if (!matchNames(child, newChild)) {
							break;
						}
					}
				}

				if (pos >= children.length) {
					children.push(newChild);
				} else {
					children.splice(pos, 0, newChild);
				}
			};
			this.setChild = function(newChild) {
				var changed;
				var child;

				changed = false;
				for (var i = 0; i < children.length; i++) {
					child = children[i];
					if (matchNames(child, newChild)) {
						children[i] = newChild;
						child = newChild;
						changed = true;
						break;
					} else {
						child = null;
					}
				}

				if (!changed) {
					children.push(newChild);
				}

				return child;
			};

			// Object
			this.toString = function() {
				var bldr;
				var child;

				if (this.text) {
					return this.text;
				} else {
					bldr = new StringBuilder();
					for (var i = 0; i < children.length; i++) {
						child = children[i];
						if (i > 0) {
							bldr.append(',');
						}
						bldr.append(child.toString());
					}
					return bldr.toString();
				}
			};
		}
		XmlElement.rename = function(/*XmlElement*/ elm, ns, localName) {
			return new XSER.XmlElement(ns, localName, elm.attributes, elm.children);
		}

		/****** Serializer ******/
		var Serializer = function() {
			this.deserialize = function(ns, localName, attributes, value) {
				var attr;
				var node;
				var children;

				if (attributes) {
					children = [];
					for (var i = 3; i < arguments.length; i++) {
						if (arguments[i] != null) {
							children.push(arguments[i]);
						}
					}
					node = new XmlElement(ns, localName, attributes, children);
				} else {
					node = new XmlAttribute(ns, localName, value);
				}

				return node;
			}
		}

		// === PACKAGE PUBLIC ===
		this.Serializer = Serializer;
		this.XmlElement = XmlElement;
		this.XmlAttribute = XmlAttribute;
		// === PACKAGE PUBLIC ===
	}
)











