import java.util.*;
import java.text.*;

/**
 *
 * @author Grant Braught
 * @author Dickinson College
 * @version Mar 3, 2005
 */
public class FCFS implements Kernel {

	private Vector readyQueue;
	private Hashtable deviceDescriptors;
	
    public FCFS() {
        readyQueue = new Vector(5, 5);
		deviceDescriptors = new Hashtable();
    }
    
    public void systemCall(int callID, String param, SystemTimer timer) {
        if (callID == Kernel.START_PROCESS) {
            // Create a process descriptor for the new process
            // and put it in the ready queue.
            readyQueue.add(new ProcessDescriptor(param));
        }
        else if (callID == Kernel.TERMINATE_PROCESS) {
            // Remove the finished process from the
            // head of the ready queue.
            readyQueue.remove(0);
        }
        else if (callID == Kernel.IO_REQUEST) {
            // Block the currently running process on the device from
            // which it requested I/O.
            DeviceDescriptor d = (DeviceDescriptor) (deviceDescriptors
                    .get(param));
            d.block((ProcessDescriptor) (readyQueue.remove(0)));
        }
        else if (callID == Kernel.MAKE_DEVICE) {
            // Create a new device descriptor for the device and
            // add it to the pool of known devices.
            deviceDescriptors.put(param, new DeviceDescriptor(param));
        }
    }

    public void interrupt(String deviceID, SystemTimer timer) {
        if (deviceID.equals("TIMER")) {
            // This would execute if a TIMER intrrupt occurs.
            // This was just included here as an example that might help you later!
        }
        // Assume all other interrupts are for a device that
        // has been created through a MAKE_DEVICE system call.
        else {
            // Find the device descriptor for the device that generated
            // the interrupt.
            DeviceDescriptor d = (DeviceDescriptor) (deviceDescriptors
                    .get(deviceID));

            if (d != null) {
                // Assume FCFS processing for devices and
                // get the first process that is blocked on the device.
                readyQueue.add(d.unblock());
            }
            else {
                // Oops... we don't have that device!
                throw new RuntimeException("Kernel received an interrupt from "
                        + "an unknown device: " + deviceID);
            }
        }
    }

    public String running(SystemTimer timer) {
            // Simple FCFS scheduling assumes that the process at
            // the front of the ready queue is the process in the
            // running state.
            try {
                String proc = ((ProcessDescriptor) (readyQueue.firstElement()))
                        .getName();
                return proc;
            }
            catch (NoSuchElementException e) {
                return "Idle";
            }
        }

    public void terminate(SystemTimer timer) {
        System.out.println("System Time: " + timer.getSystemTime());
        System.out.println("Kernel Time: " + timer.getKernelTime());
        System.out.println("  User Time: " + timer.getUserTime());
        System.out.println("  Idle Time: " + timer.getIdleTime());

        // Compute the CPU Utilization...
        NumberFormat pctFmt = NumberFormat.getPercentInstance();
        pctFmt.setMinimumFractionDigits(2);
        pctFmt.setMaximumFractionDigits(2);
        System.out.println("CPU Utilization: "
                + pctFmt.format((double) timer.getUserTime()
                        / timer.getSystemTime()));
    }
}