package eworks.RQL.model;

import java.net.URISyntaxException;
import java.util.NoSuchElementException;
import gr.forth.ics.vrp.corevrp.model.*;
import eworks.RQL.engine.*;
import eworks.RQL.engine.SymbolTable;

/**
 * <p>An abstract base class for classes that represent RQL ranges.</p>
 * <p>A RQL range is used to define a query's &quot;data source&quot;, that's the
 * expression after &quot;FROM&quot; according to the RQL syntax. A range is compareable
 * to the list of table names (after &quot;FROM&quot; as well) according to the SQL
 * syntax.</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 Range {

	/**
	 * This range's expression, used for <code>toString()</code>.
	 * 
	 * @see #toString()
	 */
	protected String expression = "";
	
	/**
	 * The RDF model to which this range is bound.
	 */
	protected Model model;
	
	/**
	 * Creates a new range that is defined by the given expression.
	 * 
	 * @param expression The expression that defines this range according to
	 *        the RQL syntax.
	 */
	public Range(String expression) {
		this.expression = expression;
	}

	/**
	 * Returns this range's string representation.
	 * 
	 * @return This range's string representation.
	 */
	public String toString() {
		return " Range[" + this.expression + "]";
	}
	
	/**
	 * Binds this range to a certain model.
	 * 
	 * @param model The model this range is bound to.
	 */
	public void bindModel( Model model ) {
		this.model = model;
		try {
			this.reset();
		} catch( NoModelBoundException e ) {
		}
	}

	/**
	 * Resets this range so that a succeeding call of <code>nextHit()</code>
	 * will return the first hit (if any).
	 *
	 * @throws NoModelBoundException if no model has been bound using
	 *         <code>bindModel()</code>.
	 * @see #nextHit()
	 * @see #bindModel(Model)
	 */	
	public abstract void reset() throws NoModelBoundException;
	
	/**
	 * Checks if there are more hits that can be iteratively retrieved using
	 * <code>nextHit()</code>.
	 *
	 * @return <code>true</code> if and only if there are more hits.
	 * @throws NoModelBoundException if no model has been bound using
	 *         <code>bindModel()</code>.
	 * @see #nextHit()
	 * @see #bindModel(Model)
	 */	
	public abstract boolean hasMoreHits() throws NoModelBoundException;
	
	/**
	 * Gets the next hit, if any. Callers should use <code>hasMoreHits()</code>
	 * before to ensure that there is a further hit. After calling this method
	 * <code>bindSymbols()</code> can be used to bind the next hit's values to
	 * some symbols.
	 *
	 * @throws NoModelBoundException if no model has been bound using
	 *         <code>bindModel()</code>.
	 * @throws NoSuchElementException if there is no further hit.
	 * @see #hasMoreHits()
	 * @see #bindSymbols(SymbolTable)
	 * @see #bindModel(Model)
	 */	
	public abstract void nextHit()throws NoModelBoundException,
	NoSuchElementException;
	
	/**
	 * Binds the current hit's values to some symbols. A caller should use
	 * <code>hasMoreHits()</code> and <code>nextHit()</code> to ensure that
	 * there is are some hits and to navigate iteratively forward trough them.
	 *
	 * @throws NoModelBoundException if no model has been bound using
	 *         <code>bindModel()</code>.
	 * @throws NoSuchElementException if there is no current hit.
	 * @throws VariableAlreadyBoundException if the used variable has already
	 *         been bound to another value.
	 * @throws URISyntaxException if a ressource is no valid URI, see
	 *         <a href="http://www.w3.org/Addressing/URL/uri-spec.html" target="_blank">
	 *         Universal Resource identifiers in WWW</a>.
	 * @see #hasMoreHits()
	 * @see #nextHit()
	 * @see #bindModel(Model)
	 */	
	public abstract void bindSymbols(SymbolTable symbols) throws NoModelBoundException,
	VariableAlreadyBoundException, URISyntaxException;
}
