package eworks.eRQL.model;

/**
 * <p>Abstract base class for combining operators like a conjunction or a disjunction.</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public abstract class Junction extends Value {

	/**
	 * The operands that are associated with this junction.
	 */
	protected Value[] values;
	
	/**
	 * Creates a new and empty junction.
	 */
	public Junction() {
		this.values=new Value[0];
	}
	
	/**
	 * Creates a new junction and initializes it with some <code>values</code>.
	 * 
	 * @param values The values for the initialization of the junction.
	 */
	public Junction( Value[] values ) {
		this.values=values;
	}

	/**
	 * Creates a new junction and initializes it with a single <code>value</code>.
	 * 
	 * @param value The value for the initialization of the junction.
	 */
	public Junction( Value value ) {
		this.values=new Value[] { value };
	}
	
	/**
	 * Creates a new junction and initializes it with two single values.
	 * 
	 * @param value1 The first value for the initialization of the junction.
	 * @param value2 The first value for the initialization of the junction.
	 */
	public Junction( Value value1, Value value2 ) {
		this.values=new Value[] { value1, value2 };
	}
	
	/**
	 * Adds a new value to this junction.
	 * 
	 * @param value The first value for the initialization of the junction.
	 */
	public void add( Value value ) {
		Value[] res = new Value[this.values.length+1];
		System.arraycopy(this.values,0,res,0,this.values.length);
		res[this.values.length] = value;
		this.values=res;
	}

	/**
	 * Compacts this junction and returns the result.
	 * 
	 * @return the compacted junction.
	 */
	public Value compact() {
		int removedValues = 0;
		 
		// call recursively
		for (int i=this.values.length-1; i>=0; i--)
			if ((this.values[i] = this.values[i].compact()) == null)
				removedValues++;
		
		if (removedValues > 0) {
			Value[] newValues = new Value[this.values.length-removedValues];
			
			int dest = newValues.length-1; 
			for (int src=this.values.length-1; src>=0; src--) {
				if (this.values[src]!=null)
					newValues[dest--]=this.values[src];
			}
			this.values = newValues;
		}
		
		if (this.values.length == 0) {
			return null;
		} else if (this.values.length == 1) {
			return (Value) this.values[0];
		} else {
			return this;
		}
	}

	/**
	 * Returns a string representation of this junction.
	 * 
	 * @return a string representation of this junction.
	 */
	public String toString() {
		String result = super.toString() + "[ ";
		
		for (int i=this.values.length-1; i>=0; i--) {
			result += this.values[i].toString();
			if (i > 0)
				result += " ";
		}
		
		result += " ]";
		
		return result;
	}
}