package eworks.RDF.model;

import java.util.Collection;
import java.util.Iterator;

/**
 * <p>Represents a set of grouped tuples and provides methods to manage them. Each
 * tuple is represented by an instance of a class that implements the {@link Tuple}
 * interface.</p>
 * 
 * <p>This implementation supports the grouping of tuples as defined by
 * the methods {@link Tuples#getNumberOfGroups} and {@link Tuples#getTuplesByGroup}.</p>

 * @author Fabian Wleklinski (<a href="mailto:fabian@wleklinski.de">fabian@wleklinski.de</a>)
 * @version 1.00 (2003-11-03)
 */
public class GroupedTuples extends AbstractTuples {
	
	private Tuples[] groups;

	/**
	 * Creates a new and empty set of tuples.
	 */
	public GroupedTuples() {
		super();
		this.groups = new Tuples[0];
	}

	/**
	 * Creates a new and empty set of tuples with a given initial capacity.
	 * 
	 * @param initialCapacity The initial capacity.
	 */
	public GroupedTuples(int initialCapacity) {
		super(initialCapacity);
		this.groups = new Tuples[0];
	}

	/**
	 * Creates a new set of tuples and initializes it with a given set of tuples.
	 * 
	 * @param c The set of tuples to initialize the new tuple set.
	 */
	public GroupedTuples(Collection c) {
		super(c);
		this.groups = new Tuples[0];
	}
	
	/**
	 * Returns the number of tuple groups.
	 * 
	 * @return The number of tuple groups.
	 */
	public int getNumberOfGroups() {
		return this.groups.length;
	}
	
	/**
	 * Returns all tuples of a certain tuple groups, that is specified by it's
	 * numerical index. The returned tuples are returned using a class that implements
	 * the {@link Tuples} interface as well.
	 * 
	 * @param groupIndex The group's index.
	 * @return The tuples of the tuple group <code>index</code>.
	 * @throws ArrayIndexOutOfBoundsException if this tuple group does not
	 *         exist, see {@link #getNumberOfGroups()}.
	 */
	public Tuples getTuplesByGroup( int groupIndex ) {
		return (Tuples) this.groups[groupIndex];
	}
	
	/**
	 * Adds all tuples that are contained inside the given collection <code>c</code>.
	 * A new tuple group is created, that contains all tuples given by <code>c</code>.
	 * 
	 * @param c The tuples to add.
	 * @param distinct If set to <code>true</code>, there will no duplicates be added.
	 * @return <code>true</code> if and only if at least one tuple was added.
	 */
	public boolean addAll(Collection c, boolean distinct) {
		// shortcut
		if (c.size()==0)
			return false;
		
		// add a new group
		Tuples[] groups = new Tuples[this.groups.length+1];
		System.arraycopy(this.groups, 0, groups, 0, this.groups.length);
		groups[this.groups.length] = new UngroupedTuples();
		
		Iterator i = c.iterator();
		Tuple t;
		boolean result = false;
		int pos;
		while (i.hasNext()) {
			if ((pos = this.indexOf(t = (Tuple) i.next())) < 0) {
				
				result = true;
				pos = this.size();
				this.add(t);
			} else {
				t = (Tuple) super.get(pos);
			}
			((Tuples) groups[this.groups.length]).add(t);
		}

		this.groups = groups;
		
		return result;
	}

	/**
	 * Clones this tuple set and returns a new instance containing the same tuples.
	 * 
	 * @return A clone of this tuple set.
	 */	
	public Object clone() {
		GroupedTuples result = new GroupedTuples( (Collection) super.clone() );
		result.groups = this.groups;
		return result;
	}
}
