/*


    ========== licence begin GPL
    Copyright (C) 2002-2003 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end


*/


package com.sap.dbtech.util.cache;

import java.util.*;

/**
 *
 */
public class LruCache
{
    /**
     *
     */
    private static class Association
        extends DListElement
    {
        Object key;

        Association (
            Object key,
            Object value)
        {
            super (value);
            this.key = key;
        }
        final Object getKey ()
        {
            return this.key;
        }
    }
    private Dictionary lookup;
    private Association lruTop;
    private Association lruBottom;
    private int currentSize;
    private int maxSize;
    static Object[] templateForClear=new Object[0];
    
    /**
     * creates a new LruCache
     */
    public
    LruCache (
        int cacheSize)
    {
        this.maxSize = cacheSize;
        this.clear ();
    }
    /**
     *
     */
    public void
    clear ()
    {
        this.currentSize = 0;
        this.lookup = new Hashtable (this.maxSize);
        this.lruTop = null;
        this.lruBottom = null;
    }
    /**
     *
     */
    public Object
    get (
        Object key)
    {
        Object result = null;
        Association entry;

        entry = (Association) this.lookup.get (key);
        if (entry != null) {
            result = entry.getObject ();
            this.moveToTop (entry);
        }
        return result;
    }
    /**
     *
     */
    public void
    put (
        Object key,
        Object value)
    {
        Association newEntry = new Association (key, value);

        this.lookup.put (key, newEntry);
        if (this.lruTop != null) {
            this.lruTop.prepend (newEntry);
        }
        this.lruTop = newEntry;
        if (this.lruBottom == null) {
            this.lruBottom = newEntry;
        }
        ++this.currentSize;
        if (this.currentSize > this.maxSize) {
            this.removeLast ();
        }
    }
    /**
     *
     */
    private void
    moveToTop (
        Association entry)
    {
        if (entry == this.lruTop) {
            return;
        }
        if (entry == this.lruBottom) {
            this.lruBottom = (Association) entry.previous ();
        }
        entry.remove ();
        this.lruTop.prepend (entry);
        this.lruTop = entry;
    }
    /**
     *
     */
    private void
    removeLast ()
    {
        Association toDelete = this.lruBottom;

        this.lruBottom = (Association) toDelete.previous ();
        this.lookup.remove(toDelete.getKey ());
        this.removeHook (toDelete);
        --this.currentSize;
    }
    /**
     *
     */
    protected void
    removeHook (
        Object value)
    {
    }

    /**
     * Returns all values and afterwards clears this cache.
     * @return an array of the stored <i>values</i>.
     */
    public Object[] clearAll()
    {
        Object[] result=((Hashtable)lookup).values().toArray(templateForClear);
        clear();
        return result;
    }
}
