/**
 * Nodeklasse
 *
 * @param {Object} content Contentobjekt
 * @author Thomas Scholz
 * @created 24.11.08
 */
function Node(content)
{
	/** Liste der Kindnodes */
	var children = null;

	/**
	 * @return {Object} the content
	 */
	this.getContent = function() 
	{
		return content;
	}

	/**
	 * @return {Array} the children
	 */
	this.getChildren = function() 
	{
		return children;
	}

	/**
	 * Fügt ein Kindelement an
	 *
	 * @param {Object} node Node
	 */
	this.addChild = function(node)
	{
		if (children == null)
			children = new Array();

		children.push(node);
	}

	/**
	 * Gibt zurück, ob das Rootnode vorliegt (hat keinen Inhalt)
	 *
	 * @return {Boolean}
	 */
	this.isRoot = function()
	{
		return (content == null);
	}

	/**
	 * Gibt zurück, ob Kindelemente existieren
	 *
	 * @return {Boolean}
	 */
	this.hasChildren = function()
	{
		return (children != null && children.length > 0);
	}

	/**
	 * akkumulative toString()-Methode
	 *
	 * @param {String} indent Einrückung
	 * @param {String} result Ergebnis
	 * @return {String} akkumuliertes Ergebnis
	 */
	this._toString = function(indent, result)
	{
		result += indent + ((this.isRoot()) ? "Root" : content.toString());
		indent += "\t";
		
		if (this.hasChildren())
			for (var i = 0, ii = children.length; i < ii; i++)
				result = children[i]._toString(indent, result + "\n");
		
		return result;
	}

	/**
	 * kapselnde toString()-Methode
	 *
	 * @return {String}
	 */
	this.toString = function()
	{
		return this._toString("", "");
	}
	
	/**
	 * akkumulierende getPath()-Methode
	 *
	 * @param {Object} content Contentobjekt
	 * @param {Array} result Pfad
	 * @return {Array} akkumulierter Pfad
	 */
	this._getPath = function(content, result)
	{
		// bist Du selbst der Knoten, dann Ende
		if (!this.isRoot() && this.getContent().equals(content)) {
			result.push(content);
			return result;
		}
		
		// Kinder dieses Knotens rekursiv durchlaufen	
		if (this.hasChildren()) {
			for (var i = 0, ii = children.length; i < ii; i++) {
			
				// berechne Pfad vom Kind zum Objekt
				var path = children[i]._getPath(content, result);
				
				// wenn Kind hat einen solchen Pfad hat, diesen vorn anfügen
				if (path.length > 0) {
					path.unshift(this.isRoot() ? '' : this.getContent());
					return path;
				}
			}
		}

		return result;
	}

	/**
	 * kapselnde getPath()-Methode: Ermittelt die
	 * Kette aller Inhalte bis zum übergebenen Content
	 *
	 * @param {Object} content Contentobjekt
	 * @return {Array} Pfad
	 */
	this.getPath = function(content)
	{
		result = this._getPath(content, new Array());
		
		// erster Eintrag ist leer (Root) und wird entfernt
		result.shift();
		
		return result;
	}
	
	/**
	 * Gibt den Level des Nodes zurück (als Anzahl 
	 * der Kette der Inhalte bis zum übergebenen Content)
	 * 
	 *  @param {Object} content Contentobjekt
	 * @return {Number} Level
	 */
	this.getLevel = function(content)
	{
		return this.getPath(content).length;
	}
	
	/**
	 * Ermittelt die Kette aller Inhalte bis zum übergebenen Content
	 * und gibt das Ergebnis als assoziatives Array mit Schlüssel 
	 * = lfdNr des Inhalts und Wert = Inhaltsobjekt zurück
	 * 
	 * @param {Object} content Contentobjekt
	 * @return {Array} Pfad
	 */
	this.getAssociativePath = function(content)
	{
		var path	= this.getPath(content);
		var result	= {};
		
		for (var i = 0, ii = path.length; i < ii; i++)
			result[path[i].getLfdNr()] = path[i];
		
		return result;
	}
	
	/**
	 * Sucht ein Node per lfdNr des zugehörigen Contents
	 *
	 * @param {Number} lfdNr lfdNr eines Contents
	 * @return {Object}
	 */
	this.findNode = function(lfdNr)
	{
		// Liegt der gesuchte Content vor?
		if (!this.isRoot() && this.getContent().getLfdNr() == lfdNr)
			return this;

		// Rekursion der Methode auf alle Kinder
		if (this.hasChildren()) {
			for (var i = 0, ii = children.length; i < ii; i++) {
				var node = children[i].findNode(lfdNr);
				if (node != null)
					return node;
			}
		}

		return null;
	}
	
	/**
	 * akkumulierende asList()-Methode
	 *
	 * @param {Array} Liste
	 * @return {Array} akkumulierte Liste
	 */
	this._asList = function(result)
	{
		// dieses Node eintragen (Root gleich weglassen)
		if (!this.isRoot())
			result[this.getContent().getLfdNr()] = this;

		// Rekursion von asList() auf alle Kinder
		if (this.hasChildren())
			for (var i = 0, ii = children.length; i < ii; i++)
				children[i]._asList(result);

		return result;
	}

	/**
	 * Erzeugt eine assozative Liste aller Nodes
	 * (Schlüssel = lfdNr des Inhalts, Wert = Node)
	 *
	 * @return {Array}
	 */
	this.asList = function()
	{
		return this._asList(new Array());
	}
}
