/*
			    Time Sharing Computer
		       Using Discrete State Simulation
				Test Program 3

			      CS509 Assignment 2
				 Winter 1995
				 G. Lindstrom

*/

import sim.*;
import random.*;

class global {

    static CPU peruvian;
    static CPU asylum;
    static CPU lal;

    static job payroll;
    static job taxes;
    static job billing;
    static job file_save;
    static job doom;

    static int jobs = 0;	// counts job processes in existence
    static int cpus = 0;	// counts cpu objects in existence

    public static void main(String av[]) {

	scheduler.activate(payroll = 
	       new my_job("payroll", new urand(10, 15), new urand(0, 10), 4));
	scheduler.activate(taxes = 
	       new my_job("taxes", new urand(20, 45), new urand(5, 15), 2));
	scheduler.activate(billing = 
	       new my_job("billing", new urand(5, 35), new urand(10, 150), 3));
	scheduler.activate(file_save = 
	       new my_job("file save", new urand(15, 45),new urand(30, 50), 2));
	scheduler.activate(doom = 
	       new my_job("doom", new urand(5, 20), new urand(20, 30), 5));

	scheduler.activate(new CPU_gen("CPU generator"));
	scheduler.activate(new CPU_retire("CPU killer", new urand(50, 150)));

	scheduler.run_simulation();

	if (peruvian != null) 
	    peruvian.remove_cpu();

	if (asylum != null)
	    asylum.remove_cpu();

	if (lal != null)
	    lal.remove_cpu();

	System.out.println(jobs + " jobs and " + cpus + " CPUs remaining");
	System.exit(0);
    }

    static boolean has_cpu(job j, CPU cpu) {
      return j != null && j.running_on_CPU != null && 
		j.running_on_CPU.equals(cpu);
    }

    static boolean is_busy(CPU cpu) {
      return has_cpu(payroll, cpu) || has_cpu(taxes, cpu) ||
	has_cpu(billing, cpu) || has_cpu(file_save, cpu) ||
	  has_cpu(doom, cpu);
    }
}

class my_job extends job {
    urand dur_rand;
    urand hold_rand;
    int cycles;

    my_job(String n, urand dr, urand hr, int c) {
	super(n);
	dur_rand = dr;
	hold_rand = hr;
	cycles = c;
	global.jobs++;
    }

    void body() {
	for (int i = 0; i<cycles; i++) {
	    run(dur_rand.draw());
	    scheduler.hold(hold_rand.draw());	// do some I/O
	}
	remove_job();
	global.jobs--;
	terminate();
    }
}

class CPU_gen extends process {

    CPU_gen(String n)
    {
	super(n);
    }

    void body()
    {
	scheduler.hold(70);
	global.cpus++;
	global.peruvian = new CPU("peruvian", 0);
	System.out.println("Time " + scheduler.clock + 
		": CPU peruvian created (no timeslicing)");
	scheduler.hold(73);

	global.cpus++;
	System.out.println("Time " + scheduler.clock + 
		": CPU asylum created (timeslice 10)");
	global.asylum = new CPU("asylum", 10);
	scheduler.hold(153);

	global.cpus++;
	System.out.println("Time " + scheduler.clock + 
		": CPU lal created (timeslice 5)");
	global.lal = new CPU("lal", 5);
	terminate();
    }
}

class CPU_retire extends process {
    urand interval;

    CPU_retire(String n, urand ival)
    {
	super(n);
	interval = ival;
    }

    void body()
    {
	while (global.jobs > 0) {
	    scheduler.hold(interval.draw());

	    if (try_retire(global.peruvian))
		global.peruvian = null;
	    if (try_retire(global.asylum))
		global.asylum = null;
	    if (try_retire(global.lal))
		global.lal = null;
	}
	terminate();
    }

    boolean try_retire(CPU cpu)
    {
	boolean can_retire = cpu != null && 
		!global.is_busy(cpu) && (global.cpus>1 || global.jobs == 0);
	if (can_retire) {
	    cpu.remove_cpu();
	    global.cpus--;
	    System.out.println("Time "+scheduler.clock+": CPU retired; "
		+global.cpus+" remain(s)");
	}
	return can_retire;
    }
}

