package eworks.eRQL.model;

import java.util.Hashtable;
import java.util.Iterator;
import eworks.RDF.model.GroupedTuples;
import eworks.RDF.model.LiteralValue;
import eworks.RDF.model.Tuple;
import eworks.RDF.model.Tuples;
import eworks.RDF.model.UriLiteralValue;
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 "POI" ("Point of interest") queries.</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class PoiQuery extends Query {

	private static String[] fields = {"s","o"};

	private static Hashtable expandedUris = new Hashtable();
		
	/**
	 * Creates an empty POI query.
	 */
	public PoiQuery() {
		super();
	}

	/**
	 * Creates an POI query and encapsulated the given <code>value</code>.
	 */
	public PoiQuery(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 GroupedTuples();
		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);
				
				Tuples rqlResult = (Tuples) expandedUris.get(lit);
				
				if (rqlResult == null) {
					String value = lit.toString();
					
					StringBuffer rql = new StringBuffer(
						"SELECT DISTINCT s,@p,o FROM {s}@p{o} WHERE " );
	
					if (lit instanceof UriLiteralValue) {
						java.net.URI uri = ((UriLiteralValue) lit).getURI();
						
						rql.append("(s=&");
						rql.append(uri.toString());
						rql.append(" OR o=&");
						rql.append(uri.toString());
						rql.append(")");
					} else {
						rql.append( Literal.toSelectionString(value, PoiQuery.fields) );
					}
					
					try {
						rqlResult = rqlEngine.query( rql.toString() );
					} catch( VariableAlreadyBoundException e ) {
						throw new RqlExecutingException( rql.toString(), e );
					} catch( VariableNotBoundException e ) {
						throw new RqlExecutingException( rql.toString(), e );
					} catch( NoDataSourceDefinedException e ) {
						throw new RqlExecutingException( rql.toString(), e );
					} catch( ParsingException e ) {
						throw new RqlExecutingException( rql.toString(), e );
					}
					
					expandedUris.put(lit,rqlResult);
				}

				result.addAll( rqlResult, true);
			}
		}

		return result;
	}

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