
var TreeElement = Class.create();
TreeElement.prototype = {
	
	initialize: function(element_data, tree) {
		this.tree = tree;
		this.expanded = false;
		this.merge(element_data);
		this.children = new Array;
	},
	
	merge: function(element_data) {
		for(i in element_data) {
			this[i] = element_data[i];
		}
	},
	
	addChild: function(element) {
		this.tree.element_list.set(element['id'], element);
		this.children.push(element);
	},
	
	getAncestors: function() {
		var ancestors = new Array;
		var the_element = this;
		while(the_element['parent']) {
			ancestors.push(the_element['parent']);
			the_element = the_element['parent'];
		}
		
		return ancestors;
	},
	
	getDescendants: function() {
		var descendants = new Array;
		this['children'].each(function(element) {
			descendants.push(element);
			element.getDescendants().each(function(element) {
				descendants.push(element);
			});
		});
		
		return descendants;
	},

	getDescendantIds: function() {
		return this.getDescendants().pluck('id');
	},
	
	getAncestorIds: function() {
		return this.getAncestors().pluck('id');
	},
	
	getSiblings: function() {
		return this['parent']['children'].without(this);
	},
	
	getSiblingIds: function() {
		return this.getSiblings().pluck('id');
	},
	
	sortChildrenByName: function(sort_function) {
		this['children'].sort(sort_function);
	},

	expand: function() {
		this.expanded = true;
	},
	
	collapse: function() {
		this.expanded = false;
	},
	
	template: function() {
		// fill
	}
	
	
}

var Tree = Class.create();
Tree.prototype = {
	
	initialize: function() {
		this.element_list = new Hash;
	},
	
	$E: function(id) {
		return this.element_list.get(id);
	},
	
	loadInitialData: function(input_array) {
		
		// add all items to the element_list
		for (var i = 0, len = input_array.length; i < len; ++i) {
			var item = input_array[i];
			
			// shortcuts
			var element_id  = item['id'];
			var the_element = new TreeElement(item, this);
			this.element_list.set(element_id, the_element);
		}
		
		// build references to parents and children
		this.element_list.each(function(pair) {
			var element_id  = pair.key;
			var the_element = pair.value;
			
			if(the_element['parent'] != undefined) {
				if(! this.$E(the_element['parent'])) {
					console.log('NO SUCH PARENT! ' + the_element['parent']);
				} else {
					// add a reference to the parent element
					the_element['parent'] = this.$E(the_element['parent']);
					
					// add the element to the parent elements children
					the_element['parent']['children'].push(the_element);
				}
			}
		}, this);
		
	},

	expand: function(id) {
		this.$E(id).expand();
	},
	
	collapse: function(id) {
		this.$E(id).collapse();
	},

	expandToId: function(id) {
		this.$E(id).getAncestorIds().each(function(ancestor_id) {
			this.expand(ancestor_id);
		}, this);
	},
	
	collapseAll: function() {
		this.element_list.each(function(pair) {
			this.collapse(pair.key);
		}, this);
	}
	
}
