// Created by Lawrence PC Dol.  Released into the public domain.
//
// Source is licensed for any use, provided this copyright notice is retained.
// No warranty for any purpose whatsoever is implied or expressed.  The author
// is not liable for any losses of any kind, direct or indirect, which result
// from the use of this software.

package <your-package-here>;

/**
 * A Most-recently-used cache. Each get or set of an object places that object at the bottom of the cache. When the size
 * limit is reached each new object added removes the (last used) object at the top of the cache.
 * <p>
 * This implementation is NOT thread-safe.  If multiple threads are to access the cache use the inner Threadsafe class.
 * <p>
 * Threading Design : [x] Single Threaded  [ ] Threadsafe  [ ] Immutable  [ ] Isolated
 *
 * @author          Lawrence Dol
 * @since           Build 2006.1231.2359
 */

public class MruCache
extends Object
{

// *****************************************************************************
// INSTANCE PROPERTIES
// *****************************************************************************

private int                             limit;                                  // size limit for the cache
private LinkedTree                      cache;                                  // insertion tree

// *****************************************************************************
// INSTANCE CONSTRUCTION/INITIALIZATON/FINALIZATION, OPEN/CLOSE
// *****************************************************************************

public MruCache(int lmt) {
    super();

    if(lmt<1) { throw new IllegalArgumentException("Cannot specify a cache limit less than 1 for MruCache"); }
    limit=lmt;
    cache=new InsertionLinkedTree();
    }

// *****************************************************************************
// INSTANCE METHODS - ACCESSORS
// *****************************************************************************

public int size() {
    return cache.size();
    }

// *****************************************************************************
// INSTANCE METHODS - PRINCIPLE IMPLEMENTATION
// *****************************************************************************

/**
 * Clear all values from the cache.
 */
public void clear() {
    cache.clear();
    }

/**
 * Get a value from the cache. If the key is found, the node is automatically moved to the end of the cache (that is
 * "freshened" in the cache).
 */
public Object get(Comparable key) {
    LinkedTree.Node                         nod;                                // node in cache

    if((nod=cache.findNode(key))!=null) {
        cache.putNode(nod,true);                                                // move node to end of the linked list ("freshen").
        return nod.getValue();
        }
    else {
        return null;
        }
    }

/**
 * Put a value into the cache, using a single object as the key and value.
 * The new value replaces any existing value.
 * This method simply calls put(keyval,null).
 */
public void put(Comparable keyval) {
    put(keyval,null);
    }

/**
 * Put a value into the cache.
 * If the value is null, the key is used as the value.
 * The new value replaces any existing value.
 */
public void put(Comparable key, Object val) {
    if(val==null) { val=key; }
    cache.putNode(new LinkedTree.MapNode(key,val),true);
    if(cache.size()>limit) { cache.removeNode(cache.getFirstNode().getKey()); }
    }

/**
 * Remove a value from the cache.
 */
public void remove(Comparable key) {
    cache.removeNode(key);
    }

// *****************************************************************************
// INSTANCE INNER CLASSES
// *****************************************************************************

// *****************************************************************************
// STATIC NESTED CLASSES
// *****************************************************************************

    static public class Threadsafe
    extends MruCache
    {
    public Threadsafe(int lmt) {
        super(lmt);
        }

    public synchronized int     size()                              { return super.size();             }
    public synchronized void    clear()                             {        super.clear();            }
    public synchronized Object  get(Comparable key)                 { return super.get(key);           }
    public synchronized void    put(Comparable keyval)              {        super.put(keyval);        }
    public synchronized void    put(Comparable key, Object val)     {        super.put(key,val);       }
    public synchronized void    remove(Comparable key)              {        super.remove(key);        }
    }


// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************

// *****************************************************************************
// STATIC INIT & MAIN
// *****************************************************************************

// *****************************************************************************
// STATIC METHODS
// *****************************************************************************

} // END PUBLIC CLASS

