/*
 * Team 1
 * CS 575: Software Design
 * All styles
 * ObjectCollection.java
 *
 * Created on October 22, 2001, 1:04 PM
 */

import java.util.Vector;
import java.util.Iterator;

/**
 * <p>This is the class the maintains a collection of KWICRow object for use by the
 * KWIC system.  This structure is also responsible for implicitly storing shifts
 * performed on the data.
 *
 * @author  Diana Tetelman
 *          Erik Hayes
 * @version 
 */
public class ObjectCollection {
    /**
    * @param args the command line arguments
    */
    public static void main (String args[]) {
    
        System.out.println("This is a test of the ObjectCollection object!");
        
        try{
            ObjectCollection collection = new ObjectCollection();
            collection.addKWICRow(new String[] { "The", "Cat"});

            collection.addKWICRow(new String[] { "in", "the", "Hat" });

            collection.addKWICRowAt(1, new String[]{ "is" });
            
	    collection.addKWICShift(2, 1);
	    collection.swapKWICRows(3,0);

            System.out.println("The size should be 4, it is " + collection.size());

            collection.startKWICRowIterator();
            while( collection.hasNextKWICRow() == true )
            {
                Object[] temp = collection.getNextKWICRow();
                int count = temp.length;
                for( int i=0; i<count; i++ )
                {
                    System.out.print(temp[i].toString() + " ");
                }
                System.out.println();
            }
            
            collection.removeKWICRowAt(2);
            collection.removeKWICRowAt(1);
	}
        catch( KWICException e )
        {
            e.printStackTrace();
        }
    }
    
    private Vector KWICRowVector;
    public Vector shiftVector;
    private Iterator iterator;
    
   
    /** Creates new KWICRows */
    public ObjectCollection() {
        KWICRowVector = new Vector();
	shiftVector = new Vector();
    }
    
    /**
     * Returns true if this collection contains no elements. 
     */
    public boolean isEmpty() 
    {
        if( KWICRowVector.size() > 0 )
            return false;
        else
            return true;
    }

    /**
     * adds a new KWICRow with the specified array of object
     * at the end of the collection
     * to pass in an array do something like 
     * (new Object[] { new String("One"), new String("Two") })
     */
    public void addKWICRow(Object[] KWICObjects) throws KWICException
    {
        KWICRow s = new KWICRow();
        
        for( int index = 0; index < KWICObjects.length; index ++ )
	{
            s.addKWICObject(KWICObjects[index]); //.clone());
	}
        
        if( s.isEmpty() != true ) {
            KWICRowVector.addElement(s);
	    int[] temp = new int[2];
	    temp[0] = KWICRowVector.size()-1;
	    temp[1] = 0;
	    shiftVector.addElement(temp);
	}
    }

    /**
     * adds a new KWICRow with the specified array of object
     * at the specified location
     * to pass in an array do something like (new String[] { "One", "Two" })
     */
    public void addKWICRowAt(int sIndex, Object[] KWICObjects) throws KWICException
    {
        if( sIndex > -1 && sIndex <= shiftVector.size() )
        {	    
            KWICRow s = new KWICRow();

            for( int wIndex = 0; wIndex < KWICObjects.length; wIndex ++ )
            {
                s.addKWICObject(KWICObjects[wIndex]); //.clone());
            }

            KWICRowVector.addElement(s);
	    int[] temp = new int[2];
	    temp[0] = KWICRowVector.size()-1;
	    temp[1] = 0;
	    shiftVector.add(sIndex, temp);
            return;
	}
        
        throw new KWICException("Index out of bounds in addKWICRowAt!");
    }

    /**
     * adds a shifted KWICRow at the end of the collection
     * @params    index      specifies the index of the row being shifted
     *            offset     specifies the position of the first object of shift
     */
    public void addKWICShift(int index, int offset) throws KWICException
    {
	if( index < shiftVector.size() )
	{
	    int[] temp = new int[2];
	    temp[0] = ((int[])(shiftVector.elementAt(index)))[0];
	    temp[1] = offset;
	    shiftVector.addElement(temp);
	    return;
	}

        throw new KWICException("Index out of bounds in addKWICShift!");
    }

    /**
     * adds a shifted KWICRow at the specified location
     * @params    index     specifies the index of the row being shifted
     *            offset    specifies the position of the first object of shift
     *            pos       position the shift is to be inserted
     */
    public void addKWICShiftAt(int index, int offset, int pos) throws KWICException
    {
	if( index < shiftVector.size() && pos < shiftVector.size() )
	{
	    int[] temp = new int[2];
	    temp[0] = ((int[])(shiftVector.elementAt(index)))[0];
	    temp[1] = offset;
	    shiftVector.add(pos, temp);
	    return;
	}

        throw new KWICException("Index out of bounds in addKWICShift!");
    }
 
    /**
     * Removes the object at the index location
     */
    public boolean removeKWICRowAt(int index)
    {
        if( index > -1 && index < shiftVector.size() )
        {
            shiftVector.removeElementAt(index);
            return true;
        }
        else
            return false;
    }        
    
    /**
     * This must be called before getNextKWICRow.  
     * It sets the internal iterator to the first object in the collection.
     * Once this is called, use getNextKWICRow() X number of times in 
     * conjunction with the hasNextKWICRow().
     */
    public void startKWICRowIterator()
    {
        iterator = shiftVector.iterator();
    }
     
    /**
     * must be called only after startKWICRowIterator,
     * retruns the next object in the list
     * if no more objects in the list throws KWICException
     */
    public Object[] getNextKWICRow() throws KWICException
    {
        try{
	    int[] positionShift = ((int[])(iterator.next()));
            KWICRow s = (KWICRow)(KWICRowVector.elementAt(positionShift[0]));
            int count = s.size();
            Object[] array = new Object[count];

      	    int j = positionShift[1];
            for( int index = 0; index < count; index++ )
            {
                array[index] = s.getKWICObjectAt(j); //.clone();
		if( ++j >= count)
		    j = 0;
            }
	   
            return array;
        }
        catch( Exception e )        
        {
            throw new KWICException("Array Index out of Bounds in getNextKWICRow");
        }
    }
    
    /**
     * can only be called after getFirstKWICRow or getNextKWICRow
     * returns true if there are more objects in the list
     * false if the list is done
     */
    public boolean hasNextKWICRow()
    {
        return iterator.hasNext();
    }
    
    /**
     * returns the number of objects currently in the list
     */
    public int size()
    {
        return shiftVector.size();
    }
    
    /** 
     * returns an object from the list at the specified index
     * if index is improper, throw exception
     */
    public Object[] getKWICRowAt(int sIndex)throws KWICException
    {
        KWICRow s;
        if( sIndex >= 0 && sIndex < shiftVector.size() )
        {
	    int[] positionShift = ((int[])(shiftVector.elementAt(sIndex)));
            s = (KWICRow)(KWICRowVector.elementAt(positionShift[0]));
            int count = s.size();
            Object[] array = new Object[count];

	    int j = positionShift[1];
            for( int wIndex = 0; wIndex < count; wIndex++ )
            {
                array[wIndex] = s.getKWICObjectAt(j); //.clone();
		if( ++j >= count)
		    j = 0;
            }
            return array;
        }
        
        throw new KWICException("Array Index out of Bounds in getNextKWICRow");
    } 

    /**
     * takes in the index of the KWICRow to examine
     * returns the number of KWICObjects that KWICRow has
     */
    public int getNumberOfKWICObjects(int sIndex)
    {
        if( sIndex >= 0 && sIndex < shiftVector.size() )
	{
	    int[] positionShift = ((int[])(shiftVector.elementAt(sIndex)));
            return ((KWICRow)(KWICRowVector.elementAt(positionShift[0]))).size();
	}
        else
            return 0;
    }
    
    /**
     * Returns the specified KWICObject of the specified KWICRow.
     * Parameters:
     * sIndex - KWICRow index 
     * wIndex - KWICObject to return index 
     * Return:
     * KWICObject if found, throws exception if indexes is incorrect
     */
    public Object getKWICObjectAt(int sIndex, int wIndex) throws KWICException
    {
        if( sIndex >= 0 && sIndex < shiftVector.size() )
	{
	    int[] positionShift = ((int[])(shiftVector.elementAt(sIndex)));
	    int position = positionShift[0];
	    int size = ((KWICRow)(KWICRowVector.elementAt(position))).size();
	    int newPos = positionShift[1] + wIndex;
	    if( newPos >= size)
		newPos = newPos - size;
	    
            return ((KWICRow)(KWICRowVector.elementAt(position))).getKWICObjectAt(newPos);
        }
        throw new KWICException("KWICRow index out of bounds in getKWICObjectAt!");
    }
    
    /**
     * Removes all the objects from the KWICRow collection
     * size of collection should be 0 after this operation if successful.
     * If not successfull, throws KWICExceptions
     */
    public boolean removeAllKWICRows() throws KWICException
    {
        try{     
            KWICRowVector.removeAllElements();
	    shiftVector.removeAllElements();
            return true;
        }
        catch( Exception e)
        {
            throw new KWICException("Problem removing all");
        }
    }
    
    public void swapKWICRows(int index1, int index2) throws KWICException
    {	    
        Object[] temp = getKWICRowAt(index1);
        removeKWICRowAt(index1);
        addKWICRowAt(index1, getKWICRowAt(index2));
        removeKWICRowAt(index2);
        addKWICRowAt(index2, temp);
    }       
    
}
