package eworks.RDF.model;

import java.util.Collection;

/**
 * <p>Represents a RDF statement.</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class Statement extends StaticCollection implements eworks.RDF.model.Tuple {

	private LiteralValue subject;
	private LiteralValue predicat;
	private LiteralValue object;

	/**
	 * Creates a new and empty statement.
	 */	
	public Statement() {
	}
	
	/**
	 * Creates a new statement with the given subject, predicate and object.
	 * 
	 * @param subject The statement's subject.
	 * @param predicat The statement's predicat.
	 * @param object The statement's object.
	 */
	public Statement(LiteralValue subject,LiteralValue predicat,LiteralValue object) {
		super();

		this.subject  = subject;
		this.predicat = predicat;
		this.object   = object;
	}
	
	/**
	 * Returns this statement's subject.
	 * 
	 * @return this statement's subject.
	 */
	public LiteralValue getSubject() {
		return this.subject;
	}

	/**
	 * Returns this statement's predicate.
	 * 
	 * @return this statement's predicate.
	 */
	public LiteralValue getPredicat() {
		return this.predicat;
	}

	/**
	 * Returns this statement's object.
	 * 
	 * @return this statement's object.
	 */
	public LiteralValue getObject() {
		return this.object;
	}

	/**
	 * Do not call this method, as it throws an {@link UnsupportedOperationException}.
	 * This method is implemented due to the contract with {@link StaticCollection}, but
	 * cannot be applied on instances of this class.
	 * 
	 * @throws UnsupportedOperationException always.
	 */
	public boolean add(Tuple t) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Returns the number of tuple goups, always 1 in this implementation.
	 * 
	 * @return The number of tuple groups, always 1.
	 */
	public int getNumberOfGroups() {
		return 1;
	}
	
	/**
	 * Clones this statement and returns a new instance containing the same subject,
	 * predicate and object.
	 * 
	 * @return A clone of this statement.
	 */	
	public Object clone() {
		return new Statement(this.subject,this.predicat,this.object);
	}
	
	/**
	 * Returns all tuples of a certain tuple group.
	 * 
	 * @param groupIndex The group's numerical index, has to be the value 1 in
	 *        this implementation.
	 * @return All tuples of the tuple group, that are all tuples that are
	 *         enclosed.
	 * @throws ArrayIndexOutOfBoundsException if the <code>groupIndex</code>
	 *         is unequal to 1.
	 */
	public Tuples getTuplesByGroup(int groupIndex) {
		if (groupIndex != 0)
			throw new ArrayIndexOutOfBoundsException();
		return this;
	}
	
	/**
	 * Do not call this method, as it throws an {@link UnsupportedOperationException}.
	 * This method is implemented due to the contract with {@link StaticCollection}, but
	 * cannot be applied on instances of this class.
	 * 
	 * @throws UnsupportedOperationException always.
	 */
	public boolean addAll(Collection c, boolean distinct) {
		throw new UnsupportedOperationException();
	}
	
	/**
	 * Returns a certain tuple specified by it's numerical index.
	 * 
	 * @param index The numerical index of the tuple to return, must be 0 in this
	 *        implementation.
	 * @return This tuple.
	 * @throws ArrayIndexOutOfBoundsException if <code>index</code> is unequal to 0.
	 */
	public Tuple getTuple(int index) {
		if (index != 0)
			throw new ArrayIndexOutOfBoundsException();
		return this;
	}

	/**
	 * Returns the statement's component with the given <code>index</code>,
	 * 0 will return it's subject, 1 it's predicate and 2 it's object.
	 * 
	 * @param index The index of the component to return.
	 * @return The statement's component with the given <code>index</code>.
	 * @throws ArrayIndexOutOfBoundsException if the index is not a value
	 *         between 0 and {@link #size()}.
	 */
	public Value get(int index) throws ArrayIndexOutOfBoundsException {
		if (index==0)
			return this.subject;
		else if (index==1)
			return this.predicat;
		else if (index==2)
			return this.object;
		else
			throw new ArrayIndexOutOfBoundsException();
	}

	/**
	 * Sets the statement's component with the given <code>index</code>
	 * to the given <code>value</code>. The <code>index</code> 0 will set
	 * it's subject, 1 it's predicate and 2 it's object.
	 * 
	 * @param index The index of the component to set.
	 * @param value The value to set.
	 * @throws ArrayIndexOutOfBoundsException if the index is not a value
	 *         between 0 and {@link #size()}.
	 */
	public void set(int index, LiteralValue value) {
		if (index==0)
			this.subject = value;
		else if (index==1)
			this.predicat = value;
		else if (index==2)
			this.object = value;
		else
			throw new ArrayIndexOutOfBoundsException();
	}
	
	/**
	 * Returns the statement's number of components (always 3).
	 * 
	 * @return The statement's number of components (always 3).
	 */	
	public int getSize() {
		return 3;
	}

	/**
	 * Checks if the given object <code>o</code> is equal to this statement.
	 * To do so, it is checked if <code>o</code> is an instance of the class
	 * {@link Statement}, too, and if it isn't, the result of
	 * {@link StaticCollection#equals} is returned.
	 * Otherwise the subject, predicate and object of the given statement are
	 * compared with subject, predicate and obect of this statement, and if all
	 * of them are equal, <code>true</code> is returned, <code>false</code> otherwise.
	 */
	public boolean equals( Object o ) {
		if (! (o instanceof Statement))
			return super.equals(o);
		
		Statement s = (Statement) o;

		if (! this.subject.equals(s.subject))
			return false;

		if (! this.predicat.equals(s.predicat))
			return false;

		if (! this.object.equals(s.object))
			return false;

		return true;
	}
}