package at.oefai.aaa.agent;

import java.io.IOException;
import java.io.Serializable;

import at.oefai.aaa.agent.jam.AbstractInterpreter;
import at.oefai.aaa.thread.IStoppable;
import at.oefai.aaa.agent.jam.ParseException;

/**
 * A stoppable version of an interpreter (for use with StoppableThread).
 * @author Stefan Rank
 */
public class StoppableInterpreter extends AbstractInterpreter implements Serializable, IStoppable {
    private static final long SLEEP_DURATION = 100;
    private volatile boolean executionDone = false;
    private long lastSimTime = 0; //time starts with 0, store at each stop
    private long lastStart = 0; //real time at last start
    private long lastStop = 0; //real time at last stop

    public StoppableInterpreter(final String name, final String[] argv) throws ParseException, IOException {
        super(name, argv);
    }

    public final boolean isCompleted() {
        return this.executionDone;
    }

    /** Execute the agent's behavior. */
    public final void runOneLoop() {
        cycleInit();
        cycleDo();
        if (! this.executionDone) {
            try { // now wait a bit to let others execute
                Thread.sleep(SLEEP_DURATION);
            } catch (InterruptedException ex) {
                // thats ok
            }
        }
    }

    public final void cycleAllGoalsDone() {
        super.cycleAllGoalsDone();
        this.executionDone = true;
    }

    //use the IStoppable hooks for keeping track of Simulation Time
    /** Records the "real time" at each start of the interpreter. */
    public final void onStart() {
        this.lastStart = System.currentTimeMillis();
    }

    /** Records the "real time" at each stop of the interpreter.
     *  and stores a checkpoint of simulation time */
    public final void onStop() {
        this.lastStop = System.currentTimeMillis();
        this.lastSimTime += (this.lastStop - this.lastStart);
    }

    /** Simple abstraction of simulation time.
     * time progression stops when the interpreter stops
     * inaccurate measure because of the pseudo-parallel pausing/starting
     */
    public final long currentSimTimeMillis() {
        if (this.lastStop >= this.lastStart) {
            return this.lastSimTime;
        } else {
            long now = System.currentTimeMillis();
            return this.lastSimTime + (now - this.lastStart);
        }
    }

}
