// @topic S-0314-10-03-20 Java object pool design pattern
// @brief class ReusablePool

package objectpooldemo;

import java.util.ArrayList;

public class ReusablePool {
    public static final int DEFAULT_POOL_SIZE = 10;
    
    // data attributes
    private ArrayList< ReusableVisitor > reusables;
    private int maxPoolSize = DEFAULT_POOL_SIZE;

    protected static ReusablePool instance = null;
    //private static Singleton instance = new Singleton();

    // constructors and instance management
    // are disabled outside of this class
    protected ReusablePool()
    {
        reusables = new ArrayList< ReusableVisitor >();
    }
    
    // operations
    public int getMaxPoolSize() {
        return maxPoolSize;
    }

    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }
        
    
    public ReusableVisitor acquireVisitor()
    {
        Lock criticalSection = new Lock();
        // search for an reusable object which already exists:
        for ( ReusableVisitor visitor : reusables) {
            if ( !visitor.isInUse() ) {
                visitor.setInUse(true);
                criticalSection.release();
                return visitor;
            }
        }
        // create and add it to the pool:
        if ( reusables.size() >= getMaxPoolSize() ) {
            // the pool limit is reached, we fail:
            criticalSection.release();
            return null;
        }
        ReusableVisitor visitor = new ReusableVisitor();
        visitor.setInUse(true);
        reusables.add(visitor);
        
        criticalSection.release();
        return visitor;
    }
    
    public void releaseVisitor( ReusableVisitor subject )
    {
        Lock criticalSection = new Lock();
        int idx  = reusables.indexOf( subject );
        if ( idx == -1 ) {
            // nothing to do - this subject is not in the pool
            criticalSection.release();
            return;
        }
        ReusableVisitor visitor = reusables.get( idx );
        visitor.setInUse(false);
        criticalSection.release();
    }
    
    // singleton implementation
    public static ReusablePool getInstance()
    {
        Lock criticalSection = new Lock();
        // critical section begins
        
        if ( instance == null ) {
            instance = new ReusablePool();
        }
        
        criticalSection.release();
        // critical section ends
        
        return instance;
    }

}//class ReusablePool