package eworks.RQL.engine;

import java.net.MalformedURLException;
import java.net.URL;
import java.io.StringReader;
import java_cup.runtime.Symbol;
import gr.forth.ics.vrp.corevrp.model.*;
import eworks.RDF.model.*;
import eworks.RQL.model.*;

/**
 * <p><code>RqlEngine</code> is the rudimentary implementation of a <em>RQL</em>-processor.
 * <em>RQL</em> is a SQL-like query language for RDF, see
 * <a href="http://139.91.183.30:9090/RDF/RQL/" target="_blank">
 * http://139.91.183.30:9090/RDF/RQL/</a> for further details on <em>RQL</em> and
 * <a href="http://www.w3.org/RDF/" target="_blank">http://www.w3.org/RDF/</a> for
 * details on <em>RDF</em>.</p>
 * <pre>
 *RqlEngine RQL = new RqlEngine();
 *eworks.RDF.model.Tuples result = null;
 *try {
 *    RQL.setDataSource(new java.io.File("C:\input.rdf"));
 *    result=RQL.query("SELECT s,@p,o FROM {s}@p{o}");
 *} catch(Exception e) {
 *    System.out.println(e);
 *}
 *</pre>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class RqlEngine {
	
	private gr.forth.ics.vrp.corevrp.parser.parser vrp;
	private URL rdfFileUrl = null;

	/**
	 * Output stream for printing error- and debug-messages.
	 */
	private java.io.OutputStream output = null;

	/**
	 * Constructs a RqlEngine instance and sets the output-stream for
	 * printing error- and debug-messages to the given stream.
	 * 
	 * @param output Output-stream for printing error- and debug-messages.
	 */	
	public RqlEngine( java.io.OutputStream output ) {
		this.output = output;
	}
	
	/**
	 * Constructs a RqlEngine instance that suppresses all error- and debug-
	 * messages.
	 */	
	public RqlEngine() {
	}
	
	/**
	 * Sets a certain RDF file as data source.
	 * 
	 * @param rdfFile The data source to be used for queries.
	 */	
	public void setDataSource(java.io.File rdfFile) {
		try {
			this.rdfFileUrl = new URL("file","",rdfFile.getAbsolutePath());
		} catch( MalformedURLException e ) {
			// should not happen
			System.out.println(e);
		}
	}
	
	/**
	 * Evaluates a given RQL query and returns the query's result.
	 * 
	 * @param queryString A valid RQL query.
	 * @return The query's result, a set of tuples.
	 */	
	public Tuples query(String queryString) throws NoDataSourceDefinedException,
	ParsingException, VariableAlreadyBoundException, VariableNotBoundException {
		
		// DEBUGOUT
		System.out.println();
		System.out.println("eworks.RQL.engine.RqlEngine.query()");
		System.out.println("-----------------------------------");
		System.out.println( "\t     Query:\t" + queryString );
		
		if (this.rdfFileUrl==null) throw new NoDataSourceDefinedException();
		
		StringReader sr = new StringReader( queryString );
		
		eworks.RQL.parser.scanner s = new eworks.RQL.parser.scanner( sr );
		
		eworks.RQL.parser.parser p = new eworks.RQL.parser.parser( s );
		Symbol parse_tree = null;
		try {
			parse_tree = p.parse();
		} catch( Exception e ) {
			System.out.println( e );
			throw new ParsingException(queryString,e);
		} catch( Error e ) {
			System.out.println( e );
			throw new ParsingException(queryString,e);
		}
		
		if (! (parse_tree.value instanceof Query))
			throw new ParsingException("parse_tree is null!");
			
		Query query = (Query) parse_tree.value;

		// DEBUGOUT
		System.out.println( "\tQuery-Tree:\t" + query.toString() );

		query.compact();
		
		// DEBUGOUT
		System.out.println( "\t (reduced):\t" + query.toString() );

		// output stream defined => set VRP output stream
		// for error + debug-messages
		//if (this.output != null)
		//	Output.set_OS(this.output);
		
		
		gr.forth.ics.vrp.corevrp.Main parser = new gr.forth.ics.vrp.corevrp.Main();
		
		//vrp_main.setfetch_all(true);
		//System.out.println( "\t       URL:\t" + this.rdfFileUrl.toString() );
		Model result = parser.start(this.rdfFileUrl.toString());
				
		// get the model's tripel
		Tuples resultingTupels=null;
		if (result instanceof Model) {
			Model m = (Model) result;

			//System.out.println( "\tstatements:\t" + m.getStatements().size() );
			
			resultingTupels = query.execute(m);

			System.out.println( "\t  # tuples:\t" + resultingTupels.size() );
		} else {
			System.out.println( "\t  # tuples:\tNone - VRP did not returned a model" );
		}

		System.out.println();

		return resultingTupels;
	}
}