/* Copyright (C) 2009  CSE,IIT Bombay  http://www.cse.iitb.ac.in

This file is part of the ConStore open source storage facility for concept-nets.

ConStore is free software and distributed under the 
Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Unported License;
you can copy, distribute and transmit the work
with the work attribution in the manner specified by the author or licensor.
You may not use this work for commercial purposes and may not alter, 
transform, or build upon this work.

Please refer the legal code of the license, available at
http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode

ConStore 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.  */

package iitb.con.caching;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * LRU cache. The least recently used objects are replaced when the 
 * cache is full.
 * 
 * @author Prathab K
 *
 */
public class LRUCache<K> implements Cache<K> {

    /** Cache size */
    private long cacheSize;
    
    /** Current cache size */
    private long currentSize;
    
    /** Maximum entries in the cache */
    public int MAX_ENTRIES = 1000;
    
    /** Hash map structure for cache */
    private Map<K, CacheObject> cache;
    
    public LRUCache() {
        create();
    }
    
    public LRUCache(int maxEntries) {
        this.MAX_ENTRIES = maxEntries;
        create();
    }
    
    /**
     * Creates the cache as Linked Hash Map structure and 
     * remove method is overridden when the size exceeds the 
     * maximum entries, the eldest entry is removed and the new 
     * entry is added.
     */
    private void create() {
        cache = new LinkedHashMap<K,CacheObject>(MAX_ENTRIES+1, .75F, true) {
            // This method is called just after a new entry has been added
            public boolean removeEldestEntry(Map.Entry<K, CacheObject> eldest) {
                return size() > MAX_ENTRIES;
            }
        };
    }
    
    /**
     * Places the cache object in the cache using the key
     * @param key key used to place the object 
     * @param object cache object
     * @return <tt>true</tt> on success
     * @see CacheObject
     */
    public boolean put(K key, CacheObject object) {
        if(cache.put(key, object) != null)
            return true;
        return false;
    }
    
    /**
     * Returns the cached object for the given key
     * @param key key used to retrieve the object
     * @return cached object if present, else returns <tt>NULL</tt>
     */
    public CacheObject get(K key) {
        return cache.get(key);
    }
    
    /**
     * Returns the size of cache in bytes
     */
    public long getSize() {
        return cacheSize;
    }
    
    /**
     * Returns the available free space
     * @return cache free space
     */
    public long freeSpace() {
        return (cacheSize - currentSize);
    }
    
    /**
     * Clears the cache
     */
    public void clear() {
        cache.clear();
    }
}