/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.utils.querybuilder;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;

//***************************************************************************
//* Class Definition and Members                                            *
//***************************************************************************

/**
 * The Treenode class implements a node of a tree. Every node has a parent
 * property which refers to the node having the specified node as a child.
 * The only exception to this rule is the root node which doesn't refer to 
 * a parent node as it is the topmost node. Every node may have 0 to n children
 * nodes.
 * 
 * @author nico.mack@tudor.lu
 */

public class TreeNode implements Serializable
	{
	private static final long serialVersionUID = 1L;

	private TreeNode				m_Parent;
	private Collection <TreeNode> 	m_Children;
	
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************
	
//***************************************************************************
//* Constructors                                       						*
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * Creates a new Root node without children.
 */
//---------------------------------------------------------------------------

public TreeNode ()
	{
	m_Parent 	= null;
	m_Children 	= new LinkedHashSet <TreeNode> ();
	}

//---------------------------------------------------------------------------
/**
 * Creates a new node without children, i.e. a leaf node, having the specified 
 * node as a parent.
 * @param p_Parent specifies the parent node.
 */
//---------------------------------------------------------------------------

public TreeNode (TreeNode p_Parent)
	{
	super ();
	
	m_Parent 	= p_Parent;
	m_Children 	= new LinkedHashSet <TreeNode> ();
	}

//---------------------------------------------------------------------------
/**
 * Creates a node having the specified node as a parent and having the specified
 * set of nodes as children.
 * @param p_Parent specifies the parent node for this node.
 * @param pChildren specifies the set of nodes to adopt as children.
 */
//---------------------------------------------------------------------------

public TreeNode (TreeNode p_Parent, Collection <TreeNode> 	p_Children)
	{
	m_Parent 	= p_Parent;
	m_Children 	= (p_Children != null)?p_Children:new LinkedHashSet <TreeNode> ();
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Primitives                                                        *
//***************************************************************************
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body		                                                        *
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * The isRoot method checks whether this node is a root node (topmost) or not.
 * @retun the method returns <code>True</code> if the node is a root node,
 * <code>False</code> otherwise.
 */
//---------------------------------------------------------------------------

public boolean isRoot ()
	{
	return (m_Parent == null);
	}

//---------------------------------------------------------------------------
/**
 * The isLeaf method checks whether this node is a leaf node (lowest) or not.
 * A Node is said to be a leaf if it doesn't have any children.
 * @retun the method returns <code>True</code> if the node is a leaf node,
 * <code>False</code> otherwise.
 */
//---------------------------------------------------------------------------

public boolean isLeaf ()
	{
	return ((m_Children == null) || (m_Children.isEmpty()));
	}

//---------------------------------------------------------------------------
/**
 * The getNumberOfChildren method returns the number of children attached
 * to this node.
 * @return the number of child nodes
 */
//---------------------------------------------------------------------------

public int getNumberOfChildren ()
	{
	return (m_Children != null)?m_Children.size():0;
	}

//---------------------------------------------------------------------------
/**
 * The getParent method returns the parent node of this node
 * @return Parent node of this node if set, <code>NULL</code> otherwise.
 */
//---------------------------------------------------------------------------

public TreeNode getParent ()
	{
	return m_Parent;
	}

//---------------------------------------------------------------------------
/**
 * The setParent method sets the parent of this node.
 * @param p_Parent specifies the new parent node for this node
 */
//---------------------------------------------------------------------------

public void setParent (TreeNode p_Parent)
	{
	m_Parent = p_Parent;
	}

//---------------------------------------------------------------------------
/**
 * The getChildrenIterator method returns an iterator allowing to iterate over
 * this node children.
 * @return An Iterator to iterate over this node's children.
 */
//---------------------------------------------------------------------------

public Iterator <TreeNode> getChildrenIterator ()
	{
	return m_Children.iterator();
	}

//---------------------------------------------------------------------------
/**
 * The addChild method add the specified node as a child to this node's children.
 * The method furthermore sets the adopted child's parent to this node.
 * A child can only be added once.
 * @param p_Child specifies the node to add as a child.
 */
//---------------------------------------------------------------------------

public void addChild (TreeNode p_Child)
	{
	if (p_Child == null) return;
	
	if (!m_Children.contains(p_Child))
		{
		p_Child.setParent(this);
		m_Children.add(p_Child);
		}
	}

//---------------------------------------------------------------------------
/**
 * The removeChild method removes the specified from this node's list of children.
 * @param p_Child specifies the child to be removed from this node's list of
 * children
 */
//---------------------------------------------------------------------------

public void removeChild (TreeNode p_Child)
	{
	if (p_Child == null) return;
	
	if (m_Children.contains(p_Child)) m_Children.remove(p_Child);
	}

//---------------------------------------------------------------------------
/**
 * The removeAllChildren method removes all children from this node's list
 * of children, thus making this node a leaf again.
 */
//---------------------------------------------------------------------------

public void removeAllChildren ()
	{
	m_Children.clear();
	}

//---------------------------------------------------------------------------
/**
 * The getAllLeaves method returns all the leaves underneath this node. This
 * includes as well the leaves being direct children of this node as well
 * as those leaves attached to children of this node. To do so, the method
 * traverses the subtree below itself in preorder, i.e. depth-first traversal.
 * @return A collection of leaves directly or indirectly underneath this node.
 */
//---------------------------------------------------------------------------

public Collection <TreeNode> getAllLeaves ()
	{
	Collection <TreeNode> l_Leaves;
	Iterator <TreeNode>	  l_NodeIterator;
	TreeNode			  l_Node;
	
	l_Leaves = new LinkedHashSet <TreeNode> ();
	
	l_NodeIterator = this.getChildrenIterator();
	while (l_NodeIterator.hasNext())
		{
		l_Node = l_NodeIterator.next();
		if (l_Node.isLeaf()) l_Leaves.add (l_Node);
		else l_Leaves.addAll (l_Node.getAllLeaves());
		}
	
	return l_Leaves;
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* End Of Class                                                            *
//***************************************************************************
//---------------------------------------------------------------------------	
	}
