package eworks.RQL.model;

/**
 * <p>Represents a condition that is composed out of a couple of other conditions.</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 * @see <a href="http://139.91.183.30:9090/RDF/RQL/" target="_blank">
 *      The RDF Query Language (RQL)</a>
 */
public abstract class CompositionCondition extends Condition {
	
	/**
	 * A field holding the subconditions.
	 */
	protected Condition[] subConditions;
	
	/**
	 * Creates an empty, composed condition (with no subconditions). 
	 */
	public CompositionCondition() {
		this.subConditions=new Condition[0];
	}

	/**
	 * Creates a composed condition using certain subconditions.
	 * 
	 * @param subConditions This condition's subconditions.
	 */	
	public CompositionCondition( Condition[] subConditions ) {
		this.subConditions=subConditions;
	}

	/**
	 * Creates a composed condition using one certain subcondition.
	 * 
	 * @param subCondition This condition's only subcondition.
	 */	
	public CompositionCondition( Condition subCondition ) {
		this.subConditions=new Condition[] { subCondition };
	}
	
	/**
	 * Adds a new subcondition to this condition.
	 * 
	 * @param subCondition The subcondition to add.
	 */
	public void add( Condition subCondition ) {
		Condition[] res = new Condition[this.subConditions.length+1];
		System.arraycopy(this.subConditions,0,res,0,this.subConditions.length);
		res[this.subConditions.length] = subCondition;
		this.subConditions=res;
	}

	/**
	 * Returns this condition's string representation.
	 * 
	 * @return This condition's string representation.
	 */
	public String toString() {
		String result = " " + super.toString() + "[";
		
		for (int i=this.subConditions.length-1; i>=0; i--) {
			result += this.subConditions[i].toString();
		}
		
		result += " ]";
		
		return result;
	}

	/**
	 * Returns a copy of this condition that is compacted. To do so this method
	 * calls iteratively the <code>compact()</code>-method of each contained
	 * subcondition.
	 * 
	 * @return A compacted copy of this condition, or <code>null</code> if this
	 *         condition is not needed (because it always evaluates to true). 
	 */
	public Condition compact() {
		int removedSubConditions = 0;; 
		 
		// call recursively
		for (int i=this.subConditions.length-1; i>=0; i--)
			if ((this.subConditions[i] = ((Condition) this.subConditions[i]).compact()) == null)
				removedSubConditions++;
		
		if (removedSubConditions > 0) {
			Condition[] newSubConditions = new Condition[this.subConditions.length-removedSubConditions];
			
			int dest = newSubConditions.length-1; 
			for (int src=this.subConditions.length-1; src>=0; src--) {
				if (this.subConditions[src]!=null)
					newSubConditions[dest--]=this.subConditions[src];
			}
			this.subConditions = newSubConditions;
		}
		
		if (this.subConditions.length == 0) {
			return null;
		} else if (this.subConditions.length == 1) {
			return (Condition) this.subConditions[0];
		} else {
			return this;
		}
	}
}
