/*
 * MemoryStore.java
 *
 * Created on January 15, 2002, 10:26 AM
 * Last modified  on  $Date$ by $Author$
 */

/**
 *
 * @author  Juozas Baliuka
 * @version $Revision$
 */

public  class MemoryStore implements Store {
   
    private static boolean DEBUG = false;
    
    
    static class SoftRef extends java.lang.ref.SoftReference{
        Object key;
       private  SoftRef(Object key,Object object,java.lang.ref.ReferenceQueue queue){
            super(object,queue);
            this.key = key;
            
        }
        
    }
    
    
    private Store store;
    private int maxStrongRefCount;
    private Object [] strongRefs;
    private int current = 0;
    private java.util.Map map = new java.util.HashMap();
    private java.lang.ref.ReferenceQueue queue = new java.lang.ref.ReferenceQueue();
    
    
   public static Store getInstance(Store store , int maxStrongRef){
      return new SynchronizedStore( new MemoryStore(store, maxStrongRef) );
   } 
    
    
    /** Creates new MemoryStore */
    protected MemoryStore(Store store, int maxStrongRefCount ) {
        if(store == null)
            throw new NullPointerException();
        if(maxStrongRefCount < 0)
            throw new java.lang.IllegalArgumentException();
        this.store = store;
        this.maxStrongRefCount = maxStrongRefCount;
        if(maxStrongRefCount > 0)
            strongRefs = new Object[ maxStrongRefCount ];
        
    }
    // remove keys
    private void removeSoftRef(){
        
        SoftRef ref = (SoftRef)queue.poll();
        
        while( ref != null ){
            map.remove(ref.key);
           if(DEBUG) 
            System.out.println(ref.key + " removed from queue, size" + map.size()  );
            ref = (SoftRef)queue.poll();
        }
        
        
    }
    
    private void addStrongRef(Object object){
        
        if( strongRefs != null )
            strongRefs[ ( current++ ) % maxStrongRefCount ] = object;
        
    }
    private void internalStoreObject(Object key, Object object){
        
        addStrongRef(object);
        map.put(key,new SoftRef(key,object,queue));
        
    }
    
    
    
    public void storeObject(Object key, Object object) throws StoreException {
        
        removeSoftRef();
        store.storeObject(key,object);
        internalStoreObject(key,object);
        
    }
    
    public Object createObject(Object key, Object object) throws StoreException, DublicateKeyException {
        
        removeSoftRef();
        object = store.createObject(key, object );
        internalStoreObject(key,object);
        return object;
        
    }
    
    public Object retrieveObject(Object key) throws StoreException, ObjectNotFoundException {
        
        removeSoftRef();
        
        Object object = null;
        
        java.lang.ref.Reference ref = (java.lang.ref.Reference)map.get(key);
        
        if(ref != null)
            object = ref.get();
        
        if(object == null)
            object = store.retrieveObject(key);
        
        
        internalStoreObject(key,object);
        
        return object;
    }
    
    public void removeObject(Object key) throws StoreException, ObjectNotFoundException {
        
        removeSoftRef();
        map.remove(key);
        store.removeObject(key);
        
    }
    
   //simple test
    
    public static void main(String args[])throws Exception{
        
        DEBUG = true;
        final int ITERATIONS  = 0xFF;
        final int OBJECT_SIZE = 0xFFFF;
        final int MAX_STRONG_REF = 20;
        
        MemoryStore mStore = new MemoryStore(
        
        new Store(){
            
            public Object createObject(Object key,Object object)throws StoreException,DublicateKeyException{
                return new int[OBJECT_SIZE];
            }
            
            public void removeObject(Object key)throws StoreException,ObjectNotFoundException{}
            
            public void storeObject(Object key,Object object)throws StoreException{}
            
            public Object retrieveObject(Object key)throws StoreException,ObjectNotFoundException{
                
                return  new int[OBJECT_SIZE];
            }
        }
        
        , MAX_STRONG_REF );
        
        
   System.out.println("operations ... "); 
    for(int i = 0; i < ITERATIONS ; i++ ){
        Object key = new Integer(i);
        mStore.storeObject(key,mStore.createObject(key,null));
        mStore.retrieveObject(key);
        mStore.retrieveObject(new Integer(0));
    }
     
    System.gc();
    mStore.retrieveObject(new Integer(0));
        
    java.util.Iterator i = mStore.map.keySet().iterator();
    System.out.println("iterating cache ... ");
     while(i.hasNext())
         System.out.println(i.next());
    
 }   
    
}
