import java.util.*;


/**
 * Used to dispatch vehicles in a fleet (e.g., emergency
 * response vehicles).
 *
 * In this version, dispatch() does not return true/false, it waits until
 * a vehicle is available.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 6.0a
 */
public class Dispatcher
{
    protected int                    numberOfVehicles;
    protected LinkedList<Integer>    availableVehicles;

    private   Object                 lock;    

    /**
     * Construct a new Dispatcher
     *
     * @param n   The number of vehicles in the fleet
     */
    public Dispatcher(int n)
    {
       int     i;

       lock = new Object();

       numberOfVehicles = n;
       availableVehicles = new LinkedList<Integer>();

       for (i=0; i < n; i++)
       {
          makeVehicleAvailable(i);
       }
    }

    /**
     * Dispatch an available vehicle.
     *
     * @param  task  The task to be handled
     * @return       true (to be consistent with earlier versions)
     */
    public boolean dispatch(String task)
    {
        boolean ok;
        
        synchronized(lock)
        {
            do
            {
                ok = attemptToDispatch(task);

                if (!ok)
                {
                    try
                    {
                        lock.wait();                
                    }
                    catch (InterruptedException ie)
                    {
                        // Ignore
                    }
            } 
            while (ok == false);
        }
        
        return true;        
    }

    /**
     * Attempt to dispatch a vehicle.
     *
     * @param task  The task.
     * @return      true if the dispatch was successful; false otherwise
     */ 
    private boolean attemptToDispatch(String task)
    {
        boolean  ok;
        int      vehicle;
        Integer  v;

        ok = false;
        if (availableVehicles.size() > 0)
        {
            v = availableVehicles.removeFirst();
            vehicle = v.intValue();
            sendMessage(vehicle, task);
            ok = true;            
        }

       return ok;
    }

    /**
     * Makes a vehicle available for future dispatching
     *
     * @param vehicle  The number of the vehicle
     */
    public void makeVehicleAvailable(int vehicle)
    {
        synchronized(lock)
        {
            availableVehicles.addLast(new Integer(vehicle));
            lock.notifyAll();
        }
    }

    /**
     * Sends a message to a vehicle
     *
     * @param vehicle  The number of the vehicle
     * @param message  The message to send
     */
    private void sendMessage(int vehicle, String message)
    {

       // This method would normally transmit the message 
       // to the vehicle.  For simplicity, it now writes it 
       // to the screen instead.

       System.out.println(vehicle+"\t"+message+"\n");
       System.out.flush();       
    }
}
