/* Author: Jeff Dalton <J.Dalton@ed.ac.uk>
 * Updated: Fri Nov 24 16:29:56 2000 by Jeff Dalton
 * Copyright: (c) 2000, AIAI, University of Edinburgh
 */

package ix.examples;

import java.util.*;

import ix.util.*;
import ix.util.lisp.*;


/**
 * A simple example using an I-X framework.  This example shows one
 * way to extend PicoISim to create a simulator that treats each tick
 * of simulated time as one second of real time.
 */

public class PicoISimTest2 extends PicoISim {

    /**
     * Main program.
     */
    public static void main(String[] argv) {

	// Create the simulator.

	final IX_Simulator sim = new TestSimulator();

	sim.setStopWhenIdle(false);

	sim.setListener(new IX_SystemListener());

	// Schedule some initial events.

	sim.schedule(new SimEvent("return", "foo", 15));
	sim.schedule(new SimEvent("return", "pre-foo", 10));

	// Start the simulation.

	sim.start();

	// While the simulation is running, the user can schedule
	// a new event by hitting return.

	new Thread() {
            public void run() {
		while (true) {
		    Util.readLine(System.in);
		    sim.schedule(new SimEvent("return", "ok", 0));
		}
	    }
	}.start();

    }

    // Define a subclass instead of specifying a TestSimController
    // when creating a new IX_Simulator and instead of calling
    // addSimEventHandlers() to add the event handlers.

    static class TestSimulator extends IX_Simulator {

	TestSimulator() {
	    super(new TestSimController(), null);
	}

	Object[] makeBuiltinSimEventHandlers() {
	    return new Object[] {

		new SimEventHandler("return") {
		    void handleIssue(Issue i) {
			system.notifyListener(i.object);
		    }
		}
	    };
	}

    }

    static class TestSimController extends SimController {

	TestSimController() {}

	boolean simulateIfPossible(SimEvent e) {

	    // Here's our difference from the inherited method:
	    // wait for the time difference between the current
	    // simulated time and the est of the event (if that
	    // est is later) in a way that also allows an external
	    // event (message) to get in.

	    long real_t = System.currentTimeMillis();
	    long sim_t = getSimTime();

	    if (e.est > sim_t) {

		long sim_delay = e.est - sim_t;
		long real_delay = sim_delay;
		Debug.noteln("... sleeping " + real_delay + " seconds ...");

		if (q.waitForMessage(real_delay * 1000)) {

		    // The simulator's received a message that might
		    // schedule an event that should happen before
		    // this one.

		    // Figure out how much simulated time has passed.
		    long real_delta
			= System.currentTimeMillis() - real_t;
		    long sim_delta = Math.round(real_delta / 1000);

		    Debug.noteln("But something happened after " + sim_delta);
		    setSimTime(sim_t + sim_delta);

		    // Return false indicate no simulation occurred
		    // The simulator will then process the message.
		    return false;

		}

		// else no message and we can simulate the event

	    }

	    return super.simulateIfPossible(e);

	}

    }

}
