function load_reference_tree(){

	//console.log("load_reference_tree");

	/*
		Constructor
	*/
	var ReferenceTree = function ReferenceTree(root, parent){

		//All nodes should have reference to the root node of the tree
		this.root = root ? root : this;

		//All nodes should have reference to their immediate tree parent
		this.parent = parent;
	};

	/*
		Static
	*/

	//The special character used to transform string names to arrays (ie: "a.b.c" -> ["a", "b", "c"])
	ReferenceTree.splitString = ".";

	/*
		Prototypal
	*/

	//The prototype should not inherit from anything
	ReferenceTree.prototype = Object.create(null);

	//globalReference refers to the name from the root of the tree, overridden on child definition (default root)
	ReferenceTree.prototype.globalReference = "root";
	//localReference refers to the name from relative to its parent, overridden on child definition (default root)
	ReferenceTree.prototype.localReference = "root";

	//Method to check whether or not a node has a child with a given name (to succinctly illustrate how referencing is stored) (unused)
	ReferenceTree.prototype._hasChild = function _hasChild(name){

		return this[name];
	};

	//Method to obtain the local names of the children of this.
	ReferenceTree.prototype.getChildReferences = function getChildReferences(name){

		//Obtain the keys of this
		var objectKeys = Object.keys(this);

		//Create a store to filter the keys to return
		var childNames = [];

		//Iterate the keys
		for(var i=0; i<objectKeys.length; i++){

			//If relative relational keys are included, filter them
			if(objectKeys[i] == "root"){
				continue;
			}
			else if(objectKeys[i] == "parent"){
				continue;
			}

			//Push the intended keys to the store to return
			childNames.push(objectKeys[i]);
		}

		//Return the store of intended keys
		return childNames;
	};

	//Defines child nodes recursively where necessarry to establish a relative child
	ReferenceTree.prototype.defineChild = function defineChild(names){

		//In the case that we recieve a string to split
		if(typeof names == "string"){

			//Split the name up by the class divider, usually (.)
			names = names.split(ReferenceTree.splitString);
		}

		//Get the first split name
		var firstChildName = names.shift();
	
		//Attempt to locate the first child
		var child = this[firstChildName];

		//If the child does not exist, or we have no more children to define to reach the final name
		if(!child || (names.length === 0)){

			//Define or Redefine the child
			child = this._defineChild(firstChildName);
		}

		//If there are still names remaining
		if(names.length > 0){

			//Call the method recursively, returning the youngest child
			return child.defineChild(names);
		}

		//Return the youngest child
		return child;
	};

	ReferenceTree.prototype.removeChild = function removeChild(names){

		//In the case that we recieve a string to split
		if(typeof names == "string"){

			//Split the name up by the class divider, usually (.)
			names = names.split(ReferenceTree.splitString);
		}

		//Remove the final child
		var lastChildName = names.pop();

		//Obtain the parent of the child to be removed
		var finalChildParent = this.getRelative(names);

		//Store the child to be removed so that we can return it
		var removedChild = finalChildParent[lastChildName];

		//Delete the reference to final child from the parent
		delete finalChildParent[lastChildName];

		//Return the removed child
		return removedChild;
	};

	//Returns the reference relative to this
	ReferenceTree.prototype.getRelative = function getRelative(names){

		//In the case that we recieve a string to split
		if(typeof names == "string"){

			//Split the name up by the class divider, usually (.)
			names = names.split(ReferenceTree.splitString);
		}

		//To get the relative nothing of this
		if(names.length === 0){

			//Should return this
			return this;
		}

		//Get the first split name
		var firstRelativeName = names.shift();

		//If there are no more children to search for
		if(names.length === 0){

			//Return the child
			return this[firstRelativeName];
		}
		//Else
		try{

			//Attempt to return recursively
			return this[firstRelativeName].getRelative(names);
		}
		//If at any point the child is undefined
		catch(noRelativeFound){

			//Return that the entire relative does not exist
			return undefined;
		}
	};

	//Defines a child reference and links it to both this as its parent, and the root as its root. (internal method)
	ReferenceTree.prototype._defineChild = function _defineChild(name){

		//Define the child with that name as a new node	
		var newChild = this[name] = new ReferenceTree(this.root, this);

		//Define the local reference with the child name
		newChild.localReference = name;

		//Calculate and store the global reference with the child name
		newChild.globalReference = this.globalReference + ReferenceTree.splitString + name;

		//Return the new child
		return newChild;
	};

	return ReferenceTree;
}

function test_reference_tree(){

	var root = new (load_reference_tree())();

	/*
		root
		|___a
		|	|___a
		|	|___b
		|		|___c
		|___b
	*/

	//root.b
	console.assert(root.defineChild("b"));
	//check root.b
	console.assert(root.b);
	//Check local name
	console.assert(root.b.localReference == "b");
	//Check global name
	console.assert(root.b.globalReference == "root.b");
	
	//root.a.b
	console.assert(root.defineChild("a.b"));
	//check root.b (again)
	console.assert(root.b);
	//root.a.b (copy)
	var old_a_b = root.a.b;
	//root.a.b.c
	console.assert(root.defineChild("a.b.c"));
	//old_a_b == new_b
	console.assert(root.a.b === old_a_b);
	//check root.a.b.c (all)
	console.assert(root.a && root.a.b && root.a.b.c);

	//check local name
	console.assert(root.a.b.c.localReference == "c");
	//check global name
	console.assert(root.a.b.c.globalReference == "root.a.b.c");

	//check getRelative
	console.assert(root.a.getRelative("b") === root.a.b);
	console.assert(root.a.getRelative("b.c") === root.a.b.c);
	console.assert(root.a.b.getRelative("parent") === root.a);
	console.assert(root.a.b.getRelative("root") === root);
	console.assert(!root.getRelative("c"));
	console.assert(!root.a.b.getRelative("d"));

	//root.b (copy)
	var old_b = root.b;
	//root.b (redefine)
	console.assert(root.defineChild("b"));
	//old_b != new_b
	console.assert(root.b !== old_b);
	//prune root.a.b
	console.assert(root.a.removeChild("b"));

	//root and parent should not be counted as children
	console.assert(root.getChildReferences().length === 2);

	return root;
}
