package JThread.examples.crew;

import java.util.*;
import JThread.stream.*;

/**
 * Implements Concurrent Read, Exclusive Write synchronization
 * protocol.
 * 
 * @author Gary Lindstrom
 * @version 1.0
 * @since February 1, 2000
 */

public class Crew implements Crewable
{
    /**
     * Constructor.
     *
     */
     public Crew() 
    { 
        readerCapabilities = new Hashtable();
    }
    
    /**
     * Current thread requests a read lock; waits until it
     * can be created.
     *
     * @return An object representing a capability to unlock
     * the granted lock.
     */
    synchronized public Lock readLock() throws ShutdownException
    {
        while ( writerLock != null )
        {
         //System.out.println(Thread.currentThread().getName() + "=> wait for read lock");
           //ShutdownManager.addWaitThread(this, Thread.currentThread());
           try {
                wait();
            } catch ( InterruptedException e ) {
                System.out.println( "Catch of " + e.toString() );
            }
            //ShutdownManager.removeWaitThread(this, Thread.currentThread());
        }
                
        // no writer running and we have lock on this crew object
       // System.out.println(Thread.currentThread().getName() + "=> ready to read");
        Lock capability = new Lock();
        readerCapabilities.put( capability, capability );
       // ShutdownManager.checkStop();
        return capability;
    }
    
    /**
     * Current thread requests a write lock; waits until it
     * can be created.
     *
     * @return An object representing a capability to unlock
     * the granted write lock.
     */
    synchronized public Lock writeLock() throws ShutdownException
    {
        while ( writerLock != null || readerCapabilities.size() > 0 )
        {
        //System.out.println(Thread.currentThread().getName() + "=> wait for write lock"); 
           //ShutdownManager.addWaitThread(this, Thread.currentThread());
            try {
                    wait();
            } catch ( InterruptedException e ) {
                System.out.println( "Catch of " + e.toString() );
            }
             //ShutdownManager.removeWaitThread(this, Thread.currentThread());
       }
        
        // no reader or writer running
        //System.out.println(Thread.currentThread().getName() + "=> ready to write");
        writerLock = new Lock();
       // ShutdownManager.checkStop();
        return writerLock;
    }
    
    /**
     * Current thread performs an unlock, authenticated by
     * the capability presented.
     *
     * @param capability An object representing a capability to 
     * perform this unlock.  Should have been returned as the
     * result of a prior readLock() or writeLock(), and never
     * previously presented as an unlock parameter.
     */
    synchronized public void unlock( Lock capability ) throws 
                InvalidUnlock, ShutdownException
    {
        // is this an unlock from the current writer (if any)?
        if ( capability == writerLock )
        {
        //System.out.println(Thread.currentThread().getName() + "=> unlock from current write");
            // writer unlock
            writerLock = null;
            // let waiting readers and writers fight it out
            ShutdownManager.checkStop();
           // System.out.println("notify all waiting threads");
            notifyAll();
        } else
        // otherwise, should be an unlock from a current reader
        {
            if ( readerCapabilities.get( capability ) != null )
            {
               // System.out.println(Thread.currentThread().getName() + "=> unlock from reader");
                // reader unlock
                readerCapabilities.remove( capability );
                if ( readerCapabilities.size() == 0 )
                {
                    // let waiting readers and writers fight it out
                    ShutdownManager.checkStop();
                    //System.out.println("notify all waiting threads");
                    notifyAll();
                }
            }
            else
            // neither the current writer, nor a current reader
            // complain!
            {
                throw new InvalidUnlock( capability.toString() );
            }
        }
    }
    
    // holds capability of current writer
    private Lock writerLock = null;
    
    // holds capabilities of current readers
    private Hashtable readerCapabilities;
}