package eworks.RDF.model;

import java.util.Collection;

/**
 * <p>Represents a tuple of instances of {@link LiteralValue}.</p>
 * 
 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class TupleImpl extends StaticCollection implements Tuple {

	private LiteralValue[] values;
	
	/**
	 * Creates a new and empty tuple.
	 */
	public TupleImpl() {
		this(0);
	}

	/**
	 * Creates a new tuple and initializes it with some <code>values</code>.
	 * 
	 * @param values The values to initialize the tuple.
	 */
	public TupleImpl(LiteralValue[] values) {
		super();
		this.values = values;
	}

	/**
	 * Creates a new tuple and initializes it with some <code>values</code>.
	 * 
	 * @param values The values to initialize the tuple.
	 */
	public TupleImpl(Collection values) {
		super();
		this.values = (LiteralValue[]) values.toArray(new LiteralValue[values.size()]);
	}

	/**
	 * Creates a new and empty tuple and initializes it with a certain <code>size</code>.
	 * 
	 * @param size The initial size of the tuple.
	 */
	public TupleImpl(int size) {
		super();
		this.values = new LiteralValue[size];
	}

	/**
	 * Clones this tuple and returns a new instance containing the same values.
	 * 
	 * @return A clone of this tuple.
	 */	
	public Object clone() {
		return new TupleImpl(this.values);
	}
	
	/**
	 * Do not call this method, because it raises an {@link UnsupportedOperationException}.
	 * This method is specified by {@link Tuples#add} in interface {@link Tuples},
	 * but cannot be used on this class.
	 * 
	 * @throws UnsupportedOperationException always.
	 * @return Nothing because an exception is thrown in every case.
	 */
	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;
	}
	
	/**
	 * 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, because it raises an {@link UnsupportedOperationException}.
	 * This method is specified by {@link Tuples#addAll} in interface {@link Tuples},
	 * but cannot be used on this class.
	 * 
	 * @throws UnsupportedOperationException always.
	 * @return Nothing because an exception is thrown in every case.
	 */
	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 tuple's component with the given <code>index</code>.
	 * 
	 * @param index The index of the component to return.
	 * @return The tuple's component with the given <code>index</code>.
	 */
	public Value get(int index) {
		return this.values[index];
	}

	/**
	 * Sets the tuple's component with the given <code>index</code>
	 * to <code>value</code>.
	 * 
	 * @param index The index of the component to set.
	 * @param value The component's new value.
	 */
	public void set(int index, LiteralValue value) {
		this.values[index] = value;
	}
	
	/**
	 * Returns the tupel's number of components.
	 * 
	 * @return The tupel's number of components.
	 */	
	public int getSize() {
		return this.values.length;
	}

	/**
	 * Checks the tuple for equality with a given object <code>o</code>. That
	 * is done by checking if <code>o</code> implements the interface
	 * {@link Tuple}. If not, <code>false</code> is returned. Otherwise the
	 * lengths of both tuples are compared, if they are unequal,
	 * <code>false</code> is returned. If they are equal, every component's
	 * (each one an instance of {@link LiteralValue}) {@link LiteralValue#equals}
	 * method is called. If one of the values does not match, <code>false</code>
	 * is returned, <code>true</code> otherwise.
	 * 
	 * @param o The object the tuple to compare to.
	 */
	public boolean equals( Object o ) {
		if (! (o instanceof Tuple))
			return false;
		
		if (o instanceof TupleImpl) {
			TupleImpl t = (TupleImpl) o;

			if (t.values.length != this.values.length)
				return false;
				
			for (int j=this.values.length-1;j>=0;j--)
				if (! this.values[j].equals(t.values[j]))
					return false;
		} else {
			Tuple t = (Tuple) o;

			if (t.getSize() != this.values.length)
				return false;
				
			for (int j=this.values.length-1;j>=0;j--)
				if (! this.values[j].equals(t.get(j)))
					return false;
		}
		return true;
	}
}
