package eworks.eRQL.model;

import eworks.RDF.model.GroupedTuples;
import eworks.RDF.model.Tuples;
import eworks.RDF.model.UngroupedTuples;
import eworks.RQL.engine.RqlEngine;
import eworks.eRQL.engine.RqlExecutingException;

/**
 * <p>Represents a conjunction of subqueries.</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class Conjunction extends Junction {

	/**
	 * Creates a new and empty conjunction.
	 */
	public Conjunction() {
		super();
	}

	/**
	 * Creates a new conjunction and initializes it with a single <code>value</code>.
	 * 
	 * @param value The value for the initialization of the conjunction.
	 */
	public Conjunction( Value value ) {
		super(value);
	}

	/**
	 * Creates a new conjunction and initializes it with two values.
	 * 
	 * @param v1 The first value for the initialization of the conjunction.
	 * @param v2 The second value for the initialization of the conjunction.
	 */
	public Conjunction( Value v1, Value v2 ) {
		super(v1,v2);
	}
	
	/**
	 * Evaluates this disjunction and returns the result.
	 */
	public Tuples query(RqlEngine rqlEngine) throws RqlExecutingException {
		Tuples result = new GroupedTuples();
		
		Tuples[] tuples = new Tuples[this.values.length];
		
		int[] pos = new int[this.values.length];

		// do queries
		for (int i=0; i<this.values.length; i++) {
			tuples[i] = this.values[i].query(rqlEngine);
			
			if (tuples[i].getNumberOfGroups() == 0)
				return result;
		}
		
		boolean done;
		
		do {
			Tuples tmp = new UngroupedTuples();
			
			for (int i=0; i<this.values.length; i++) {
				
				Tuples conjunction=(Tuples) tmp.clone();
				Tuples group = tuples[i].getTuplesByGroup(pos[i]);
				conjunction.retainAll(group);
				
				if (i == 0 || conjunction.size() > 0) {
					tmp.addAll(group,true);
				} else {
					tmp.clear();
					break;
				}
			}
			
			// check if there is another group
			done = true;

			for (int j=0; j<this.values.length; j++) {
				if (pos[j]+1 < tuples[j].getNumberOfGroups()) {
					pos[j]++;
					done = false;
					break;					
				} else {
					pos[j] = 0;
				}
			}

			result.addAll(tmp,true);
			
		} while (! done);
		
		return result;
	}
}