// -- 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.getXMLstring = function() {
	if (typeof this.value == 'string') {
		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 += '&apos;'; break;
				case '"' : out += '&quot;'; 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.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;
}

