/*******************************************************************************
 * 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.util.Iterator;

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

/**
 * The WhereClause is basically the same as a Group, in the sense that it groups 
 * conditions and other groups. In fact, the WhereClause class extends the Group 
 * class. The only difference between the Group and the WhereClause class is that 
 * the Group class does not know how to render itself, i.e. does not override 
 * the toString() method whereas the WhereClause class does. The reason for this was 
 * motivated by the fact that a query may hold more than one group but only single 
 * WhereClause. As you can imagine, rendering a where clause entails resorting 
 * to recursion and I prefered to retain recursion in one single object.
 */

public class WhereClause extends Group
{
	private static final long serialVersionUID = 1L;

//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************
	
//***************************************************************************
//* Constructors                                       						*
//***************************************************************************
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Primitives                                                        *
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * renders the Groups and Conditions attached to specified Node, linking them
 * with the specified Operator. Rendering is a recursive process where the
 * nodes in tree will be traversed in preorder, i.e. depth-first traversal.
 * @param p_Node specifies the node to be rendered.
 * @param p_Operator specifies the operator to be used to link rendered
 * conditions and groups.
 */
//---------------------------------------------------------------------------

private String render (TreeNode p_Node, Operator p_Operator)
	{
	Iterator <TreeNode> l_Children;
	TreeNode			l_Child;
	Group				l_Group;
	Condition			l_Condition;
	StringBuilder		l_WhereClause;
	String				l_Operator;
	
	l_WhereClause = new StringBuilder();
	l_Operator	  = "";
	
	// In order to render the specified node, we have to irerator over all
	// its children.
	
	l_Children = p_Node.getChildrenIterator();
	while (l_Children.hasNext())
		{
		l_Child = l_Children.next();
		
		// How a child is handled depends on the type of child. If Child
		// is a Group, we have to recursively render it first, remembering to
		// enclose it in parantheses.
		
		if (l_Child instanceof Group)
			{
			l_Group = (Group)l_Child;
			if (l_Group.getNumberOfConditions() > 0)
				{
				l_WhereClause.append(l_Operator)
							 .append("(")
							 .append(render(l_Group,l_Group.getOperator()))
							 .append(")");
			
				// For first group, l_Operator ought to be empty, but as of now
				// it should be set.
				
				if ((l_Operator.length() == 0) && (p_Operator != null))
					l_Operator = p_Operator.toString();
				}
			}
		
		// If Child is Condition, we just simply render it

		else if (l_Child instanceof Condition)
			{
			l_Condition = (Condition)l_Child;
			
			l_WhereClause.append(l_Operator)
						 .append(l_Condition.toString());
						
			// For first condition, l_Operator ought to be empty, but as of now
			// it should be set.

			if ((l_Operator.length() == 0) && (p_Operator != null))
				l_Operator = p_Operator.toString();
			}
		}
	
	return l_WhereClause.toString();
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body		                                                        *
//***************************************************************************
//---------------------------------------------------------------------------

public String toString ()
	{
	return this.render(this,this.getOperator());
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* End Of Class                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public static void main(String[] args)
	{
	WhereClause	l_Clause;
	Condition	l_Condition;
	Group		l_Group;
	Operator	l_Operator;

	l_Clause = new WhereClause ();
	l_Operator = new HibernateOperator (Operator.c_Or);
	l_Clause.setOperator(l_Operator);
	
	l_Group  = new Group ();
	l_Operator = new HibernateOperator (Operator.c_And);
	l_Group.setOperator(l_Operator);
	
	
	l_Operator = new HibernateOperator (Operator.c_Equal);
	l_Condition = new HibernateCondition ("color.id",l_Operator,"green");
	
	l_Group.addChild(l_Condition);
	
	l_Operator = new HibernateOperator (Operator.c_NotEqual);
	l_Condition = new HibernateCondition ("m","color",l_Operator,"color1", "blue");
	
	l_Group.addChild(l_Condition);
	
	l_Operator = new HibernateOperator (Operator.c_NotEqual);
	l_Condition = new HibernateCondition ("m","color",l_Operator,"color2", "yellow");
	
	l_Group.addChild(l_Condition);

	l_Clause.addChild (l_Group);
	
	l_Operator = new HibernateOperator (Operator.c_Like);
	l_Condition = new HibernateCondition ("name",l_Operator,"'%Neckel%'");
	
	l_Clause.addChild (l_Condition);

	System.out.println (l_Clause.toString());
	}

}
