// -- structure class item --

function structure_class_item(name, value) {
	this.next = null;
	this.last = null;
	this.parent = null;
	this.child = null;
	
	this.name = name;
	this.value = value;
}

structure_class_item.prototype.append_child = function(ref) {
	if (this.child == null) {
		this.child = ref;
		ref.parent = this;
	
	} else {
		var loop = this.child;
		
		while (loop.next != null) loop = loop.next;
		
		loop.next = ref;
		ref.last = loop;
		ref.parent = this;
	}
	
	return ref;
}

structure_class_item.prototype.add_child = function(name, value) {
	return this.append_child(new structure_class_item(name, value));
}

structure_class_item.prototype.get_child = function(name) {
	var founded = false;
	var loop = this.child;
	
	while (!founded && loop != null) {
		if (loop.name == name) founded = true;
		else loop = loop.next;
	}
	
	return founded ? loop : null;
}

structure_class_item.prototype.destroy = function(force) {
	if (force == null) {
		
	
	} else {
		var stack = new Array();
		var current = null;
		var loop = null;
		stack[stack.length] = this;
		
		while (stack.length > 0) {
			current = stack.pop();
			
			if (current.child == null) {
				current.last = null;
				current.next = null;
				if (current.parent != null && current.parent.child == current) current.parent.child = null;
				current.parent = null;
				
			} else {
				stack[stack.length] = current;
				loop = current.child;
				while (loop != null) {
					stack[stack.length] = loop;
					loop = loop.next;
				}
			}
		}
	}
}

structure_class_item.prototype.matchEntity = function(string) {
	string = string.replace(/&/g,'&amp;');
	string = string.replace(/</g,'&lt;');
	string = string.replace(/>/g,'&gt;');
	string = string.replace(/'/g,'&apos;');
	string = string.replace(/"/g,'&quot;');
	
	return string;
}

structure_class_item.prototype.getXMLstring = function() {
	if (typeof this.value == 'string') {
	
		return this.matchEntity(this.value);
		//return (this.value.replace('&','&amp;')).replace('<','&lt;').replace('>','&gt;').replace('\'','&apos;').replace('"','&quot;');
		
		/*
		var ch, out = '';
		
		for (f = 0; f < this.value.length; f++) {
			ch = this.value.substr(f, 1);
			
			switch (ch) {
				case '<' : out += '&' + 'lt;'; break;
				case '>' : out += '&' + 'gt;'; break;
				case '&' : out += '&' + 'amp;'; break;
				case '"' : out += '&' + 'quot;'; break;
				case '\'' : out += '&' + 'apos;'; break;
				default : out += ch; break;
			}
		}
		
		return out;
		*/
	} else return this.value;
}

// -- structure class --

function structure_class() {
	this.root = null;

	this.flush();
}

structure_class.prototype.flush = function() {
	if (this.root != null) {
		this.root.destroy();
		this.root = null;
	}
	this.root = new structure_class_item();
}

structure_class.prototype.destroy = function() {
	this.flush();
	context.object_destroy(this);
}

structure_class.prototype.path_parts = function(path) {
	var path_parts = new Array();
	var point = 0;
	
	var cur_char = '';
	var cur_str = '';
	
	for (point = 0; point <= path.length; point++) {
		cur_char = point == path.length ? '/' : path.substr(point, 1);
		
		switch (cur_char) {
			case '/' :
				path_parts[path_parts.length] = cur_str;
				cur_str = '';
				break;
				
			default :
				cur_str += cur_char;
				break;
		}
	} // for
	
	return path_parts
}

structure_class.prototype.map = function(path, value) {
	var path_parts = this.path_parts(path);
	
	if (path_parts.length > 0) {
		var current = this.root;
		var child;
		var f;
		
		for (f = 0; f < path_parts.length; f++) {
			child = current.get_child(path_parts[f]);
			if (child == null) {
				child = new structure_class_item(path_parts[f], f + 1 == path_parts.length ? value : null);
				current.append_child(child);
			} else {
				if (f + 1 == path_parts.length) child.value = value;
			}
			
			current = child;
		}
		
		return current;
	}
	
	return null;
}

structure_class.prototype.get = function(path) {
	var path_parts = this.path_parts(path);
	var founded = null;
	
	if (path_parts.length > 0) {
		var f;
		var founded = this.root;
		
		for (f = 0; f < path_parts.length && founded != null; f++)
			founded = founded.get_child(path_parts[f]);
	}
	
	return founded != null ? founded.value : null;
}

structure_class.prototype.compose = function(container_element) {
	var output = '<' + '?xml version="1.0" encoding="utf-8"?' + '><' + container_element + '>';
	var stack = new Array();
	var opened = new Array();
	var current, add, loop;
	stack[stack.length] = this.root;
	
	while (stack.length > 0) {
		current = stack.pop();
		
		if (current != this.root) {
			
			// uzavreni
			var brk = false;
			var pos = opened.length - 1;
			
			while (!brk && pos >= 0) {
				if (opened[pos] == current.parent) brk = true;
				else pos--;
			}
			
			if (brk) {
				var max;
				for (max = opened.length - 1; max > pos; max--) {
					output += '</' + opened[max].name + '>';
					opened.pop();
				}
			} else {
				var f;
				for (f = opened.length -1; f >= 0; f--) {
					output += '</' + opened[f].name + '>';
				}
				opened = new Array();
			}
				
			if (current.child != null) {
				// otevreni
				output += '<' + current.name + '>';
				opened[opened.length] = current; 
				
			}
			
			if (current.child == null) {
				output += '<' + current.name + '>' + current.getXMLstring() + '</' + current.name + '>\r\n';
			}
		}
						
		if ((loop = current.child) != null) {
			add = new Array();
			while (loop != null) {
				add[add.length] = loop;
				loop = loop.next;
			}
			
			var f;
			for (f = add.length - 1; f >= 0; f--)
				stack[stack.length] = add[f];
		}
	}
	
	var f;
	for (f = opened.length - 1; f >= 0; f--) {
		output += '</' + opened[f].name + '>';
	}
	output += '</' + container_element + '>';
	
	return output;
}

