package eworks.eRQL.model;

import java.util.Iterator;
import eworks.RDF.model.LiteralValue;
import eworks.RDF.model.Tuple;
import eworks.RDF.model.Tuples;
import eworks.RDF.model.UngroupedTuples;
import eworks.RQL.engine.NoDataSourceDefinedException;
import eworks.RQL.engine.ParsingException;
import eworks.RQL.engine.RqlEngine;
import eworks.RQL.engine.VariableAlreadyBoundException;
import eworks.RQL.engine.VariableNotBoundException;
import eworks.eRQL.engine.RqlExecutingException;

/**
 * <p>A specialized query class for socalled "document queries".</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class DocumentQuery extends Query {

	/**
	 * Creates an empty POI query.
	 */
	public DocumentQuery() {
		super();
	}

	/**
	 * Creates an POI query and encapsulated the given <code>value</code>.
	 */
	public DocumentQuery(Value value) {
		super(value);
	}

	/**
	 * Evaluates this query and returns the result using the given <code>rqlEngine</code>.
	 * 
	 * @return the query's result.
	 * @throws RqlExecutingException if something goes wrong.
	 */
	public Tuples query(RqlEngine rqlEngine) throws RqlExecutingException {
		Tuples result = new UngroupedTuples();
		
		Iterator tuples = this.value.query(rqlEngine).iterator();
		
		while (tuples.hasNext()) {
			Tuple tupel = (Tuple) tuples.next();
			for (int i=0; i<tupel.getSize(); i++) {
				LiteralValue lit = (LiteralValue) tupel.get(i);
				String value = lit.toString();
				
				String rql = "SELECT DISTINCT s,@p,o FROM {s}@p{o}";

				try {
					result.addAll(rqlEngine.query( rql.toString() ), true);
				} catch( VariableAlreadyBoundException e ) {
					throw new RqlExecutingException( rql, e );
				} catch( VariableNotBoundException e ) {
					throw new RqlExecutingException( rql, e );
				} catch( NoDataSourceDefinedException e ) {
					throw new RqlExecutingException( rql, e );
				} catch( ParsingException e ) {
					throw new RqlExecutingException( rql, e );
				}
				
				// we may leave now, because there cannot be more
				// than one document !
				
				return result;
			}
		}

		return result;
	}

	/**
	 * Compacts this query and returns the result.
	 * 
	 * @return the compacted query.
	 */
	public Value compact() {
		Value result = super.compact();
		
		if (result instanceof DocumentQuery)
			if (((DocumentQuery) result).value instanceof DocumentQuery)
				result = ((DocumentQuery) result).value;
	
		return result;
	}

	/**
	 * Returns this query's string representation.
	 * 
	 * @return this query's string representation.
	 */
	public String toString() {
		return "DocumentQuery[ " + this.value.toString() + " ]";
	}
}