package eworks.eRQL.model;

import eworks.RDF.model.SingleGroupedTuples;
import eworks.RDF.model.Tuples;
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>Represents literal values.</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class Literal extends Value {

	private static String[] fields = {"s","@p","o"};
	private static String[] fields2 = {"s","@p","o","a","@b","c"};

	private String value;

	/**
	 * Creates a new value with the given string.
	 * 
	 * @param value The string literal to encapsulate.
	 */
	public Literal(String value) {
		this.value=value;
	}

	/**
	 * Returns the value's string representation.
	 * 
	 * @return the value's string representation.
	 */
	public String toString() {
		return "Literal('" + this.value + "')";
	}

	/**
	 * Creates a case-insensitive regular expression according to the
	 * given <code>value</code>.
	 * 
	 * @param value The string to convert into a regular expression.
	 * @return The regular expression.
	 */	
	private static String toRegularExpression( String value ) {
		StringBuffer result = new StringBuffer(value.length()*4);
		
		char[] chars = value.toCharArray();
		for (int i=0; i<chars.length; i++) {
			if (Character.isLetter(chars[i])) {
				result.append('[');
				result.append(Character.toUpperCase(chars[i]));
				result.append(Character.toLowerCase(chars[i]));
				result.append(']');
			} else {
				if (chars[i]=='"')
					result.append("\\\"");
				else if (chars[i]=='.')
					result.append("\\.");
				else if (chars[i]=='*')
					result.append("\\*");
				else if (chars[i]=='[')
					result.append("\\[");
				else if (chars[i]==']')
					result.append("\\]");
				else
					result.append(chars[i]);
			}
		}
		
		return result.toString();
	}
	
	
	static String toSelectionString(String value, String[] fields) {
		StringBuffer result = new StringBuffer();
		
		int count = fields.length;
		if (count == 0)
			return result.toString();
		
		result.append('(');
		for (int i=0; i<count; i++) {
			if (i > 0)
				result.append( " OR " );

			result.append( fields[i] );
			result.append( " LIKE \"*" );

			result.append( Literal.toRegularExpression(value) );
			
			result.append( "*\"" );
		}
		result.append(')');
		
		return result.toString();
	}
	
	/**
	 * Evaluates this literal.
	 */
	public Tuples query(RqlEngine rqlEngine) throws RqlExecutingException {
		return this.query(rqlEngine,false);
	}
	
	/**
	 * Evaluates this literal.
	 */
	public Tuples query(RqlEngine rqlEngine, boolean poiMode) throws RqlExecutingException {
		
		String rql;
		Tuples result;
		// shortcut for poimode deactivated right now
		/*
		if (poiMode) {
			result = new Tuples();
			rql = "SELECT DISTINCT s,@p,o FROM {s}@p{o}, {a}@b{c} WHERE " +
				Literal.toSelectionString(this.value, Literal.fields2) +
				" AND (s=a OR s=c OR o=a OR o=c)";
		} else {
		*/
			result = new SingleGroupedTuples();
			rql = "SELECT DISTINCT s,@p,o FROM {s}@p{o} WHERE " +
				Literal.toSelectionString(this.value, Literal.fields);
		/*
		}
		*/
		
		try {
			result.addAll(rqlEngine.query( rql ), true);
		} 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 );
		}

		return result;
	}
}