package org.jboss.cache.search;

import org.jboss.cache.Cache;

import java.util.List;
import java.util.NoSuchElementException;

/**
 * This is the implementation class for the interface QueryResultIterator which extends ListIterator. It is what is
 * returned when the iterator() method is run on a CacheQuery instance.
 *
 * @author Navin Surtani  - navin@surtani.org
 */
public class QueryResultIteratorImpl implements QueryResultIterator
{
   private int index = 0;
   //private final int size;
   private List<CacheEntityId> idList;
   private CacheEntityLoader entityLoader;
   private int lowerLimit = 0;
   private int upperLimit = 0;

   public QueryResultIteratorImpl(List<CacheEntityId> idList, CacheEntityLoader entityLoader)
   {
      this.idList = idList;
      this.entityLoader = entityLoader;
      upperLimit = idList.size() - 1;
   }

   /**
    * Jumps to a given index in the list of results.
    *
    * @param index to jump to
    * @throws IndexOutOfBoundsException
    */

   public void jumpToResult(int index) throws IndexOutOfBoundsException
   {
      if (index > idList.size() || index < 0)
      {
         throw new IndexOutOfBoundsException("The index you entered is either greater than the size of the list or negative");
      }
      this.index = index;
   }

   /**
    * Jumps to first element in the list.
    */

   public void first()
   {
      index = 0;
   }

   /**
    * Jumps to last element in the list.
    */

   public void last()
   {
      index = idList.size() - 1;
   }

   /**
    * Jumps to second element in the list.
    */

   public void afterFirst()
   {
      index = 1;
   }

   /**
    * Jumps to penultimate element in the list.
    */

   public void beforeLast()
   {
      index = idList.size() - 2;
   }

   /**
    * @return true if the current element is the first in the list.
    */

   public boolean isFirst()
   {
      return idList.get(index) == idList.get(0);
   }

   /**
    * @return true if the current result is the last one.
    */

   public boolean isLast()
   {
      return index == idList.size() - 1;

   }

   /**
    * @return true if the current result is one after the first.
    */

   public boolean isAfterFirst()
   {
      return idList.get(index) == idList.get(1);
   }

   /**
    * @return true if the current result is one before the last
    */

   public boolean isBeforeLast()
   {
      return idList.get(index) == idList.get(idList.size() - 2);
   }

   /**
    * Returns true if the list has more elements when traversing the list in the forward direction.
    *
    * @return true if the list has more elements when traversing the list in the forward direction.
    */

   public boolean hasNext()
   {
      return index <= upperLimit;
   }

   /**
    * Returns the next element in the list
    *
    * @return The next element in the list.
    */
   public Object next()
   {
      if (!hasNext()) throw new NoSuchElementException("Out of boundaries");
      Object toReturn = entityLoader.load(idList.get(index));
      index++;
      return toReturn;
   }

   /**
    * Returns true if the list has more elements when traversing the list in the reverse direction.
    *
    * @return true if the list iterator has more elements when traversing the list in the reverse direction
    */
   public boolean hasPrevious()
   {
      return index >= lowerLimit;
   }

   /**
    * Returns the previous element in the list.
    *
    * @return The previous element in the list.
    */

   public Object previous()
   {
      if (!hasPrevious()) throw new NoSuchElementException("Out of boundaries");
      Object toReturn = entityLoader.load(idList.get(index));
      index--;
      return toReturn;
   }

   /**
    * Returns the index of the element that would be returned by a subsequent call to next.
    *
    * @return Index of next element.
    */

   public int nextIndex()
   {
      if (!hasNext()) throw new NoSuchElementException("Out of boundaries");
      return index + 1;

   }

   /**
    * Returns the index of the element that would be returned by a subsequent call to previous.
    *
    * @return Index of previous element.
    */

   public int previousIndex()
   {
      if (!hasPrevious()) throw new NoSuchElementException("Out of boundaries");
      return index - 1;
   }

   /**
    * This method is not supported and should not be used. Use cache.remove() instead.
    */
   public void remove()
   {
      throw new UnsupportedOperationException("Not supported as you are trying to change something in the cache");
   }

   /**
    * This method is not supported in and should not be called. Use cache.put() instead.
    *
    * @param o
    * @throws UnsupportedOperationException
    */
   public void set(Object o) throws UnsupportedOperationException
   {
      throw new UnsupportedOperationException("Not supported as you are trying to change something in the cache");
   }

   /**
    * This method is not supported in and should not be called. Use cache.put() instead.
    *
    * @param o
    * @throws UnsupportedOperationException
    */

   public void add(Object o)
   {
      throw new UnsupportedOperationException("Not supported as you are trying to change something in the cache");
   }
}
