/*
 * This file is part of the Poliqarp suite.
 * 
 * Copyright (C) 2004-2009 by Instytut Podstaw Informatyki Polskiej
 * Akademii Nauk (IPI PAN; Institute of Computer Science, Polish
 * Academy of Sciences; cf. www.ipipan.waw.pl).  All rights reserved.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file gpl.txt included in the packaging
 * of this file.  (See http://www.gnu.org/licenses/translations.html for
 * unofficial translations.)
 * 
 * A commercial license is available from IPI PAN (contact
 * Michal.Ciesiolka@ipipan.waw.pl or ipi@ipipan.waw.pl for more
 * information).  Licensees holding a valid commercial license from IPI
 * PAN may use this file in accordance with that license.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

package ipipan.poliqarp.util;

import java.util.AbstractCollection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

/**
 * This class implements a capacity-constrained collection that works
 * on a <em>most recently used</em> basis. It resembles a stack with a hole in
 * the bottom: new elements are added to the beginning of the stack and
 * when the capacity limit is about to be exceeded, the least recently
 * inserted element is discarded. Inserting an element that is already
 * contained in the collection causes it to be moved to the front.
 */
public class MRUCollection<E> extends AbstractCollection<E>
{
   private static final int defaultLimit = 10;
   private int limit;
   private LinkedList<E> data;

   /**
    * Constructs an empty MRU collection with the specified capacity
    * limit.
    * 
    * @param limit the capacity limit
    */
   public MRUCollection(int limit) 
   {
      this.limit = limit;
      data = new LinkedList<E>();
   }
   
   /**
    * Creates a MRU collection with the default capacity limit (10).
    */
   public MRUCollection() 
   {
      this(defaultLimit);
   }

   /**
    * Inserts the element onto the beginning of this collection. If the
    * collection already contains an element equal (in the sense of
    * <code>equals()</code> method) to this one, moves it to the
    * beginning of the collection.
    * 
    * @param element the element to be inserted
    * @return <code>true</code> if the content of the collection changed;
    * <code>false</code> if the collection already contained this element
    * (note that its position might have been changed).
    */
   public boolean add(E element) 
   {
      ListIterator<E> i = data.listIterator();
      while (i.hasNext()) {
         E current = i.next();
         if (element.equals(current)) {
            i.remove();
            data.addFirst(current);
            return false;
         }
      }
      if (data.size() == limit) 
         data.removeLast();
      data.addFirst(element);
      return true;
   }

   /**
    * Returns the number of elements in this collection.
    */
   public int size()
   {
      return data.size();
   }

   /**
    * Returns an iterator that traverses this collection in the 'most to least
    * recently used' order.
    */
   public Iterator<E> iterator()
   {
      return data.iterator();
   }

   /**
    * Returns the element at the specified position.
    */
   public E get(int pos)
   {
      return data.get(pos);
   }
}
