// Copyright(c) 1996,1997 ObjectSpace, Inc.
// Portions Copyright(c) 1995, 1996 Hewlett-Packard Company.

package COM.objectspace.jgl;

/**
 * A HashSetIterator is a forward iterator that allows you to iterate through
 * the contents of a HashSet.
 * <p>
 * @see COM.objectspace.jgl.ForwardIterator
 * @version 2.0.2
 * @author ObjectSpace, Inc.
 */

public final class HashSetIterator implements ForwardIterator
  {
  HashSet myHashSet;
  HashSet.HashSetNode myNode;

  /**
   * Construct myself to be an iterator with no associated data structure or position.
   */
  public HashSetIterator()
    {
    }

  /**
   * Construct myself to be a copy of an existing iterator.
   * @param iterator The iterator to copy.
   */
  public HashSetIterator( HashSetIterator iterator )
    {
    myHashSet = iterator.myHashSet;
    myNode = iterator.myNode;
    }

  /**
   * Construct myself to be positioned at a particular node in a specified Table.
   * @param node My associated node.
   * @param set My associated HashSet.
   */
  HashSetIterator( HashSet.HashSetNode node, HashSet set )
    {
    myHashSet = set;
    myNode = node;
    }

  /**
   * Return a clone of myself.
   */
  public Object clone()
    {
    return new HashSetIterator( this );
    }

  /**
   * Return true if a specified object is the same kind of iterator as me
   * and is positioned at the same element.
   * @param object Any object.
   */
  public boolean equals( Object object )
    {
    return object instanceof HashSetIterator && equals( (HashSetIterator) object );
    }

  /**
   * Return true if iterator is positioned at the same element as me.
   * @param iterator The iterator to compare myself against.
   */
  public boolean equals( HashSetIterator iterator )
    {
    return myNode == iterator.myNode;
    }

  /**
   * Return true if I'm positioned at the first item of my input stream.
   */
  public boolean atBegin()
    {
    if ( myHashSet == null )
      return false;

    for ( int i = 0; i < myHashSet.length; i++ )
      if ( myHashSet.buckets[ i ] != null )
        return myNode == myHashSet.buckets[ i ];

    return true;
    }

  /**
   * Return true if I'm positioned after the last item in my input stream.
   */
  public boolean atEnd()
    {
    return myNode == null;
    }

  /**
   * Return true if there are more elements in my input stream.
   */
  public boolean hasMoreElements()
    {
    return myNode != null;
    }

  /**
   * Advance by one.
   */
  public void advance()
    {
    myNode = ( myNode.next != null ? myNode.next : next( myNode ) );
    }

  /**
   * Advance by a specified amount.
   * @param n The amount to advance.
   */
  public void advance( int n )
    {
    if ( n < 0 )
      throw new InvalidOperationException( "Attempt to advance a ForwardIterator in the wrong direction." );
    while ( n-- > 0 )
      advance();
    }

  /**
   * Return the next element in my input stream.
   */
  public Object nextElement()
    {
    Object object = myNode.object;
    myNode = ( myNode.next != null ? myNode.next : next( myNode ) );
    return object;
    }

  /**
   * Return the object at my current position.
   */
  public Object get()
    {
    return myNode.object;
    }

  /**
   * HashSet the object at my current position to a specified value.
   * @param object The object to be written at my current position.
   */
  public void put( Object object )
    {
    myNode.object = object;
    }

  /**
   * Return the distance from myself to another iterator.
   * I should be before the specified iterator.
   * @param iterator The iterator to compare myself against.
   */
  public int distance( ForwardIterator iterator )
    {
    HashSet.HashSetNode oldNode = myNode;
    HashSet.HashSetNode node = ((HashSetIterator) iterator).myNode;
    int n = 0;

    while ( myNode != node )
      {
      ++n;
      myNode = ( myNode.next != null ? myNode.next : next( myNode ) );
      }

    myNode = oldNode;
    return n;
    }

  /**
   * Return my associated HashSet
   */
  public Container getContainer()
    {
    return myHashSet;
    }

  private HashSet.HashSetNode next( HashSet.HashSetNode node )
    {
    for ( int i = ( node.hash % myHashSet.length ) + 1; i < myHashSet.length; i++ )
      if ( myHashSet.buckets[ i ] != null )
        return myHashSet.buckets[ i ];

    return null;
    }
  }
