Package eas.simulation

Source Code of eas.simulation.SimulationTime

/*
* Dateiname:        SimulationTime.java
* Autor(en):        Lukas König
* Java-Version:     6
* Erstellt (vor):   14.05.2009
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
*   author or licensor (but not in any way that suggests that they endorse
*   you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
*   distribute the resulting work only under the same or a similar license to
*   this one.
*
* + Detailed license conditions (Germany):
*   http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
*   http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/

package eas.simulation;

import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;

import eas.miscellaneous.StaticMethods;
import eas.miscellaneous.system.windowFrames.GeneralDialog;
import eas.plugins.Plugin;
import eas.plugins.masterScheduler.MasterScheduler;
import eas.simulation.event.ConstantEventFilterTrue;
import eas.simulation.event.EASEvent;
import eas.simulation.event.EventFilter;
import eas.startSetup.GlobalVariables;
import eas.startSetup.ParCollection;

/**
* Implementation of the simulation engine.
*
* Note that the terms 'plugin' and 'scheduler' are used synonymously. The
* master scheduler is a special type of plugin.
*
* @author Lukas König
*/
public class SimulationTime<RunnableType extends EASRunnable> implements Runnable, Serializable {
   
    /**
     * Serialization ID as of 27 May 2014.
     */
    private static final long serialVersionUID = -5072984671932777494L;

    /**
     * The parameters of this simulation run.
     */
    private ParCollection pars;

    /**
     * Simulation time passed so far.
     */
    private Wink currentTime;

    /**
     * Flag that states if the simulation should stop at the next possible
     * point.
     */
    private boolean stopSim;

    /**
     * List of plugin objects to manipulate simulation. First plugin is master
     * scheduler.
     */
    private LinkedList<Plugin<?>> plugins;
   
    /**
     * The environment being simulated.
     */
    private RunnableType runnable;

//    /**
//     * The thread for the simulation time to run in.
//     */
//    private Thread simThread;
   
    /**
     * If ticks are requested by any plugin.
     */
    private boolean isRequestedTicks;
   
    /**
     * For every plugin the information if ticks are requested or not.
     */
    private HashMap<Plugin<?>, Boolean> requestedTicks
        = new HashMap<Plugin<?>, Boolean>();
   
    /**
     * For requested notification time the plugin that requested it.
     * Keys are sorted.
     */
    private TreeMap<Double, LinkedList<Plugin<?>>> requestedNotif
        = new TreeMap<Double, LinkedList<Plugin<?>>>();

    /**
     * Set of plugins that are notified at all notifications that
     * occur for any other plugin - NOT at events.
     * This influences only the invokation of the method runDuringSim.
     * The plugins in this set are invoked AFTER the invokation of other
     * plugins at the same time step.
     * Note: plugins that have already been invoked at a time step are not invoked
     * in the same time step for a second time.
     */
    private HashSet<Plugin<?>> toBeNotifiedAtAllNotifications
        = new HashSet<Plugin<?>>();
   
    /**
     * A list of all plugins that are requesting events. Every plugin is
     * assigned to an event filter deciding if the plugin should be notified
     * for a specific event broadcast.
     */
    private HashMap<Plugin<?>, EventFilter> eventRequestingPlugins;

    /**
     * Konstruktor, benutzt von Starterklasse während der Simulation.
     *
     * @param params  Die Parameter für den Lauf.
     * @param plug  Plugin-Objekte, die in jedem Zyklus die Simulation
     *                 beeinflussen können.
     */
    public SimulationTime(
            final RunnableType env,
            final LinkedList<Plugin<?>>  plug,
            final ParCollection params) {
        this.pars = params;
        this.plugins = plug;
        if (this.plugins != null) {
            for (Plugin<?> p : this.plugins) {
                this.requestTicks(p);
            }
        }
        this.eventRequestingPlugins = new HashMap<Plugin<?>, EventFilter>();
        this.runnable = env;
        this.reset();
        this.checkRequiredPlugins();
    }
   
    /**
     * Resets the simulation time to the beginning.
     */
    public void reset() {
        this.stopSim = false;
       
        // A negative currentTime indicates a simulation before the start of time.
        this.currentTime = new Wink(-1, true, this);
       
        StaticMethods.log(
                StaticMethods.LOG_INFO,
                "<SimulationTime> Simulation time has been set to the initial state.",
                this.pars);
    }
   
    /**
     * Runs the complete simulation cycle.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public void run() {
        StaticMethods.log(
                StaticMethods.LOG_INFO,
                "<SimulationTime> Course of time started for runnable " + this.runnable.id() + ".",
                this.pars);

        if (this.simulationResumed) {
            // Starting the plugin method to resume simulation.
            for (Plugin p : this.plugins) {
                try {
                    this.pars.log(StaticMethods.LOG_INFO, "<SimulationTime> resuming plugin '" + p.id() + "'...");
                    if (!this.neverNotify.contains(p)) {
                        p.onSimulationResumed(this.runnable, this.currentTime, this.pars);
                    }
                } catch (Exception e) {
                    // Handle uncaught exception.
                    this.handleExceptionInMainLoop(e, p);
                }
            }
        } else {
            // Starting the plugin method before Simulation.
            for (Plugin p : this.plugins) {
                try {
                    if (!this.neverNotify.contains(p)) {
                        runBeforeSimulation(p);
                    }
                } catch (Exception e) {
                    // Handle uncaught exception.
                    this.handleExceptionInMainLoop(e, p);
                }
            }
        }
       
        boolean fortsetzen = this.setNextNotificationTime();

        // Main loop generating time and event notifications for plugins.
        while (fortsetzen) {
//            while (this.globalPause) {
//                try {Thread.sleep(100);} catch (InterruptedException e) {}
//            }
           
            this.step();
            fortsetzen = this.setNextNotificationTime();
            this.simulationResumed = false;
        }

        // Starting the plugin after Simulation.
        for (Plugin p : this.plugins) {
            try {
                this.pars.log(StaticMethods.LOG_INFO, "<SimulationTime> finalizing plugin '" + p.id() + "'...");
                if (!this.neverNotify.contains(p)) {
                    p.runAfterSimulation(this.runnable, this.pars);
                }
            } catch (Exception e) {
                // Handle uncaught exception.
                this.handleExceptionInMainLoop(e, p);
            }
        }

        StaticMethods.log(
                StaticMethods.LOG_INFO,
                "<SimulationTime> Course of time ended for runnable " + this.runnable.id() + ".",
                this.pars);
       
        this.timeTerminated = true;
    }

    @SuppressWarnings("unchecked")
    public void runBeforeSimulation(@SuppressWarnings("rawtypes") Plugin p) {
        this.pars.log(StaticMethods.LOG_INFO, "<SimulationTime> initializing plugin '" + p.id() + "'...");
        p.runBeforeSimulation(this.runnable, this.pars);
    }
   
    private boolean timeTerminated = false;
   
    /**
     * @return Returns the timeFinished.
     */
    public boolean isTimeTerminated() {
        return this.timeTerminated;
    }

    /**
     * Checks if all (by any plugin) required plugins are existing and throws
     * a RuntimeException if some are missing.
     */
    private void checkRequiredPlugins() {
        boolean gefunden;
       
        if (this.plugins == null) {
            return;
        }
       
        for (Plugin<?> p : this.plugins) {
            if (p.getRequiredPlugins() != null) {
                for (String prStr : p.getRequiredPlugins()) {
                    gefunden = false;
                    for (Plugin<?> p2 : this.plugins) {
                        if (prStr.equals(p2.id())) {
                            gefunden = true;
                            break;
                        }
                    }
                    if (!gefunden) {
                        throw new RuntimeException(
                                "Plugin '" + p.id()
                                + "' requires plugin(s) '" + prStr
                                + "' which could not be found.");
                    }
                }
            }
        }
    }

    /**
     * Sets the current time to the next time step that is relevant for
     * notifications if there exists such a time step within simulation
     * time. If the flag stopSim is true, nothing is done and
     * <code>false</code> is returned.
     *
     * @return  Returns <code>true</code> as long as some plugin is still to
     *          be notified, <code>false</code> otherwise.
     */
    private boolean setNextNotificationTime() {
        if (!this.stopSim &&
                (this.isRequestedTicks || this.requestedNotif.size() > 0)) {
            long nextTick = this.currentTime.getLastTick() + 1;
            double nextNot = Double.POSITIVE_INFINITY;
           
            if (this.requestedNotif.size() > 0) {
                nextNot = this.requestedNotif.firstKey();
            }

            // Do nothing if time is terminated.
            if (this.getMasterScheduler().isTerminationRequested(this.runnable, this.currentTime, this.pars)) {
                return false;
            }
           
            if (this.isRequestedTicks && nextTick < nextNot) {
                // isTick wird automatisch gesetzt.
                this.currentTime.nextTick();
            } else {
                this.currentTime.setCurrentTime(nextNot);
                this.currentTime.setTick(false);
            }
           
            return true;
        }
       
        return false;
    }
   
    /**
     * The plugins that have to be notified in the current time step are
     * notified. If there are notifications left to do within simulation time,
     * the current simulation time is set to the next time step that is
     * associated to a notification; otherwise, <code>false</code> is returned
     * meaning that the simulation should be stopped. Note that  
     *
     * @return  Returns <code>true</code> as long as some plugin is still to
     *          be notified, <code>false</code> otherwise.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void step() {
        HashSet<Plugin<?>> invoked = new HashSet<Plugin<?>>();
       
        if (this.currentTime.isTick()) {
            for (Plugin p : this.plugins) {
                if (this.requestedTicks.get(p)) {
                   
                    try {
                        p.runDuringSimulation(
                                this.runnable,
                                this.currentTime,
                                this.pars);
                    } catch (Exception e) {
                        // Handle uncaught exception.
                        this.handleExceptionInMainLoop(e, p);
                    }
                   
                    invoked.add(p);
                }
            }
        } else { // Time step is no tick, i.e. a requested notification.
            for (Plugin p : this.requestedNotif.get(
                    this.currentTime.getCurrentTime())) {
               
                try {
                    p.runDuringSimulation(
                            this.runnable,
                            this.currentTime,
                            this.pars);
                } catch (Exception e) {
                    // Handle uncaught exception.
                    this.handleExceptionInMainLoop(e, p);
                }
               
                invoked.add(p);
            }
           
            this.requestedNotif.remove(this.currentTime.getCurrentTime());
        }

        /*
         * Invoke all plugins that want to be notified every time anything
         * happens.
         */
        if (invoked.size() > 0) {
            for (Plugin p : this.toBeNotifiedAtAllNotifications) {
                if (!invoked.contains(p)) {
                   
                    try {
                        p.runDuringSimulation(
                                this.runnable,
                                this.currentTime,
                                this.pars);
                    } catch (Exception e) {
                        // Handle uncaught exception.
                        this.handleExceptionInMainLoop(e, p);
                    }
                }
            }
        }

        /*
         * Register new waiting plugins.
         */
        for (Plugin p : this.pluginsToRegisterAfterExecutionOfCurrentStep) {
            registerPluginSynchronized(p);
        }
        this.plugins.addAll(this.pluginsToRegisterAfterExecutionOfCurrentStep);
        this.pluginsToRegisterAfterExecutionOfCurrentStep.clear();
    }
   
    private boolean ignoreAllExceptions = false;
   
    /**
     * Handles cases where an uncaught exception occurred in a plugin
     * / scheduler.
     *
     * @param e  The uncaught exception.
     * @param p  The plugin / scheduler that caused the exception.
     */
    private void handleExceptionInMainLoop(Exception e, Plugin<?> p) {
        String time = "" + this.currentTime.getCurrentTime();
       
        if (ignoreAllExceptions) {
            return;
        }
       
        if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_ASK_WHAT_TO_DO)) {
            ArrayList<String> buttons = new ArrayList<String>(10);
            buttons.add("Ignore");
            buttons.add("Ignore all");
            buttons.add("Log and ignore all");
           
            if (!this.getMasterScheduler().id().equals(p.id())) {
                buttons.add("Remove Plugin '" + p.id() + "'");
            }
           
            buttons.add("Terminate");
            buttons.add("Halt immediately!");
            buttons.add("Throw exception!");
           
            GeneralDialog dia = new GeneralDialog(
                    null,
                    null,
                    "Handle uncaught exception at time step " + time + ".",
                    buttons,
                    "The plugin \n'"
                            + p.id()
                            + "'\nhas caused an exception that has been raised to the main simulation loop.\n\nDetails:\n"
                            + e.toString()
                            + "\nat "
                            + Arrays.deepToString(e.getStackTrace()).replace('[', '\n').replace(']', '\n').replace(',', '\n'));
            dia.setVisible(true);
           
            if (dia.getResult().equals("Throw exception!")) {
                throw new RuntimeException(e);
            }
           
            if (dia.getResult().equals("Halt immediately!")) {
                // Halt immediately.
                StaticMethods.logInfo("User request: Simulation is being HALTED immediately. Goodbye!", this.pars);
                System.exit(0);
            } else if (dia.getResult().equals("Terminate")) {
                // Terminate simulation immediately in a regular way.
                StaticMethods.logInfo("User request: Simulation is being TERMINATED at end of current cycle.", this.pars);
                this.timeTerminate();
            } else if (dia.getResult().equals("Ignore all")) {
                this.ignoreAllExceptions = true;
            } else if (dia.getResult().equals("Log and ignore all")) {
                this.pars.setActionOnUncaughtException(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_PRINT_AND_RECOVER);
            } else if (dia.getResult().startsWith("Remove Plugin")) {
                this.neverNotifyAgain(p);
                StaticMethods.logInfo("User request: Scheduler '" + p.id() + "' has been removed from simulation.", this.pars);
            } else {
                StaticMethods.logInfo("User request: Course of time has recovered from an ancaught exception.", this.pars);
            }
           
            return;
        }
       
        // Do nothing.
        if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_DO_NOTHING)) {
            return;
        }
       
        String master = "";
       
        if (p.id().equalsIgnoreCase(this.getMasterScheduler().id())) {
            master = " (MASTER SCHEDULER)";
        }
       
        // Log message.
        if (!this.pars.getActionOnUncaughtException().equalsIgnoreCase(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_DO_NOTHING)) {

            StaticMethods
                    .log(StaticMethods.LOG_ERROR,
                            "<SimulationTime> Main simulation loop caught at time step "
                                    + time
                                    + " an unhandled exception thrown by scheduler '"
                                    + p.id()
                                    + "'"
                                    + master
                                    + ": \n---\n"
                                    + e.toString()
                                    + "\nat "
                                    + Arrays.deepToString(e.getStackTrace())
                                            .replace('[', '\n')
                                            .replace(']', '\n')
                                            .replace(',', '\n') + "---",
                            this.pars, "", e);
        }
       
        // Ignore plugin in future (except master scheduler).
        if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(
                ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_REMOVE_SCHEDULER_AND_RECOVER)) {
            if (master.length() == 0) {
                this.neverNotifyAgain(p);
                StaticMethods.logInfo("<SimulationTime> Scheduler '" + p.id() + "' has been removed from simulation.", this.pars);
            }
            StaticMethods.logInfo("<SimulationTime> Course of time has recovered from an ancaught exception.", this.pars);
        } else if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(
                ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_PRINT_AND_TERMINATE)) {
            // Terminate simulation immediately in a regular way.
            StaticMethods.logInfo("<SimulationTime> Simulation is being TERMINATED at end of current cycle.", this.pars);
            this.timeTerminate();
        } else if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(
                        ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_PRINT_AND_HALT)) {
            // Halt immediately.
            StaticMethods.logInfo("<SimulationTime> Simulation is being HALTED immediately. Goodbye!", this.pars);
            System.exit(0);
        } else {
            StaticMethods.logInfo("<SimulationTime> Course of time has recovered from an ancaught exception.", this.pars);
        }
    }
   
    /**
     * @return Returns the environment.
     */
    public EASRunnable getEnvironment() {
        return this.runnable;
    }
   
//    /**
//     * @return Returns the simThread.
//     */
//    public Thread getSimThread() {
//        return this.simThread;
//    }

    private boolean simulationResumed = false;

    public void resumeLoadedSimulation() {
        this.pars.onSimulationResumed();
        this.simulationResumed = true;
        this.pars.logInfo("<SimulationTime> Resuming simulation '"
                + this.getEnvironment().getClass().getSimpleName().toString()
                + "' at time instant " + this.getCurrentTime() + ".");
        this.timeStart();
    }
   
    /**
     * Startet den Zeitablauf mit automatischem Weiterlaufen.
     */
    public void timeStart() {
        Thread simThread;
        simThread = new Thread(this);
        simThread.start();
    }
   
    /**
     * Requests a termination of simulation time. This will occur in the next
     *
     */
    public void timeTerminate() {
        this.stopSim = true;
    }

    /**
     * @param id  Der Name des Plugins.
     *
     * @return  Das (erste) Plugin, das den Namen hat.
     *          null, falls es kein Plugin dieses Namens gibt.
     */
    public Plugin<?> getPluginObject(final String id) {
        if (this.plugins == null) {
            return null;
        }
       
        for (Plugin<?> p : this.plugins) {
            if (p.id().equals(id)) {
                return p;
            }
        }
       
        return null;
    }
   
    /**
     * @return Returns the currentTime.
     */
    public Wink getCurrentTime() {
        return this.currentTime;
    }
   
    /**
     * Gives a notification to the given Plugin at every tick from now on
     * until the neglectTicks-method is called.
     *
     * @param requester  The plugin that should be notified.
     */
    public void requestTicks(final Plugin<?> requester) {
        this.requestedTicks.put(requester, true);
        this.isRequestedTicks = true;
    }
   
    /**
     * Stops notifying the given plugin at every tick until the requestTicks-
     * method is called.
     *
     * @param requester  The plugin to ignore at ticks.
     */
    public void neglectTicks(final Plugin<?> requester) {
        this.requestedTicks.put(requester, false);
        for (boolean b : this.requestedTicks.values()) {
            if (b) {
                return;
            }
        }
        this.isRequestedTicks = false;
    }
   
    /**
     * Requests a notification for the requesting plugin at a specific
     * time step in the future. CAUTION! Note that time steps requested using
     * this method are NOT CONSIDERED TICKS - even if they happen to point at
     * a time simultaneous to a tick.
     *
     * @param requester  The plugin to be notified.
     * @param time       The time of notification.
     */
    public void requestNotification(
            final Plugin<?> requester,
            final double time) {
        if (time <= this.currentTime.getCurrentTime()) {
            return;
        }
       
//        if (time > this.pars.getExperimentLength()) {
//            StaticMethods.log(
//                    StaticMethods.LOG_WARNING,
//                    "Requested notification time "
//                    + time + " (for " + requester.id() + ") "
//                    + "is greater than the total simulation time ("
//                    + this.pars.getExperimentLength() + ").",
//                    this.pars);
//        }
       
        if (time < 0) {
            throw new RuntimeException("Requested notification time "
                    + time + " (for " + requester.id()
                    + ") is below 0.");
        }
       
        LinkedList<Plugin<?>> currList
            = this.requestedNotif.get(time);
       
        if (currList == null) {
            currList = new LinkedList<Plugin<?>>();
            this.requestedNotif.put(time, currList);
        }
       
        if (!currList.contains(requester)) {
            currList.add(requester);
        }
    }

    /**
     * Gives a notification to this SimulationTime's master scheduler
     * at every tick from now on until the neglectTicks-method is called.
     *
     * @param requester  The plugin that should be notified.
     */
    public void requestTicks() {
        this.requestTicks(this.getMasterScheduler());
    }
   
    /**
     * Stops notifying this SimulationTime's master scheduler
     * at every tick until the requestTicks-method is called.
     *
     * @param requester  The plugin to ignore at ticks.
     */
    public void neglectTicks() {
        this.neglectTicks(this.getMasterScheduler());
    }
   
    /**
     * Requests a notification for this SimulationTime's master scheduler at
     * a specific time step. CAUTION! Note that time steps requested using
     * this method are NOT CONSIDERED TICKS - even if they happen to point at
     * a time simultaneous to a tick.
     *
     * @param requester  The plugin to be notified.
     * @param time       The time of notification.
     */
    public void requestNotification(final double time) {
        this.requestNotification(this.getMasterScheduler(), time);
    }
   
    /**
     * Requests a notification for any time step a notification occurs in
     * the simulation.
     * This influences only the invokation of the method runDuringSim.
     * The given plugin is invoked AFTER the invokation of other
     * plugins at the same time step.
     * Note: plugins that have been invoked at a time step are not invoked
     * in the same time step a second time.
     *
     * @param requester  The requesting plugin. Note that there is no separate
     *                   method for the master scheduler as master schedulers
     *                   typically will not need this functionality. If a
     *                   master scheduler M should need this, the method can be
     *                   invoked as requestAllNotifications(M).
     */
    public void requestAllNotifications(final Plugin<?> requester) {
        this.toBeNotifiedAtAllNotifications.add(requester);
    }
   
    /**
     * Neglects notifications for all time steps a notification occurs in
     * the simulation (cf. method requestAllNotifications).
     *
     * @param requester  The neglecting plugin. Note that there is no separate
     *                   method for the master scheduler as master schedulers
     *                   typically will not need this functionality. If a
     *                   master scheduler M should need this, the method can be
     *                   invoked as requestAllNotifications(M).
     */
    public void neglectAllNotifications(final Plugin<?> requester) {
        this.toBeNotifiedAtAllNotifications.remove(requester);
    }
   
    public void requestAllNotifications() {
        this.requestAllNotifications(this.getMasterScheduler());
    }

    public void neglectAllNotifications() {
        this.neglectAllNotifications(this.getMasterScheduler());
    }
   
    private HashSet<Plugin<?>> neverNotify = new HashSet<Plugin<?>>();
   
    /**
     * Ignores the plugin for all future notifications including events. The
     * plugin cannot recover by itself from this state. Another scheduler,
     * however, can request future notifications for this scheduler.
     *
     * @param requester  The scheduler (plugin) to be ignored.
     */
    public void neverNotifyAgain(final Plugin<?> requester) {
        this.neverNotify.add(requester);
        this.neglectAllNotifications(requester);
        this.neglectTicks(requester);
        this.eventRequestingPlugins.remove(requester);
        for (Double d : this.requestedNotif.keySet()) {
            List<Plugin<?>> list = this.requestedNotif.get(d);
            list.remove(requester);
        }
    }
   
    /**
     * @return  This SimulationTime's master scheduler.
     */
    @SuppressWarnings("unchecked")
    public MasterScheduler<RunnableType> getMasterScheduler() {
        return (MasterScheduler<RunnableType>) this.plugins.get(0);
    }

    /**
     * Broadcasts the given event to all registered plugins.
     *
     * @param e  The event causing the broadcast.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void broadcastEvent(final EASEvent e) {
        for (Plugin p : this.eventRequestingPlugins.keySet()) {
            if (eventRequestingPlugins.get(p).isAcceptable(e)) {
                p.handleEvent(e, this.runnable, this.currentTime, this.pars);
            }
        }
    }

    /**
     * Requests events for the specified plugin filtered by the specified
     * event filter.
     *
     * @param plugin  The plugin to be notified.
     * @param filter  The event filter.
     */
    public void requestEvents(
            final Plugin<?> plugin,
            final EventFilter filter) {
        this.eventRequestingPlugins.put(plugin, filter);
    }
   
    /**
     * Requests events for the master scheduler filtered by the specified
     * event filter.
     *
     * @param filter  The event filter.
     */
    public void requestEvents(final EventFilter filter) {
        this.requestEvents(this.getMasterScheduler(), filter);
    }
   
    /**
     * Requests ALL events for the specified plugin (filtered by the constant
     * event filter <code>ConstantEventFilterTrue</code>).
     *
     * @param plugin  The plugin to be notified.
     */
    public void requestAllEvents(final Plugin<?> plugin) {
        this.requestEvents(plugin, new ConstantEventFilterTrue());
    }
   
    /**
     * Requests ALL events for the master scheduler (filtered by the constant
     * event filter <code>ConstantEventFilterTrue</code>).
     */
    public void requestAllEvents() {
        this.requestEvents(new ConstantEventFilterTrue());
    }
   
    private LinkedList<Plugin<?>> pluginsToRegisterAfterExecutionOfCurrentStep = new LinkedList<>();
   
    /**
     * Add a plugin to the list of registered plugins. The plugin is put at
     * the end of the list and therefore notified last. Ticks are automatically
     * requested for the new plugin, and as a first action, the plugin's
     * <code>runBeforeSimulation</code> method is called. Everything else has
     * to be done from outside.  (The complementary method to remove a plugin
     * is called <code>neverNotifyAgain</code>.)
     *
     * @param plugin  The plugin to register.
     * @return  If the plugin has been registered (if not, probably a required
     *          plugin is missing).
     */
    public boolean registerPlugin(Plugin<?> plugin) {
        if (plugin.getRequiredPlugins() != null) {
            for (String pID : plugin.getRequiredPlugins()) {
                boolean gefunden = false;
                for (Plugin<?> p : this.plugins) {
                    if (pID.equals(p.id())) {
                        gefunden = true;
                    }
                }
               
                if (!gefunden) {
                    GlobalVariables.getPrematureParameters().logWarning(
                            "Plugin '" + plugin.id()
                                    + "' NOT registered as the required plugin '"
                                    + pID + "' is not registered.");
                    return false;
                }
            }
        }

        if (this.pluginsToRegisterAfterExecutionOfCurrentStep.size() == 0) {
            this.pluginsToRegisterAfterExecutionOfCurrentStep.add(plugin);
            return true;
        } else {
            GlobalVariables
                    .getPrematureParameters()
                    .logWarning(
                            "Plugin '"
                                    + plugin.id()
                                    + "' NOT registered because another plugin ('"
                                    + this.pluginsToRegisterAfterExecutionOfCurrentStep
                                            .get(0).id()
                                    + "') is waiting to be registered.");
            return false;
        }
    }

    private void registerPluginSynchronized(@SuppressWarnings("rawtypes") Plugin plugin) {
        this.pars.addPluginIncludingParameters(plugin.id());
        this.requestTicks(plugin);
        runBeforeSimulation(plugin);
    }
   
    /**
     * Save the current simulation state to disc.
     *
     * @param f  The path to store the simState.
     *
     * @return  If the simState was successfully saved.
     */
    public boolean serializeSimState(File f) {
        try {
            new SerializableSimulationState(this, f).save();
            return true;
        } catch (SimStateUnserializableException e) {
            return false;
        }
    }
   
    public LinkedList<Plugin<?>> getPlugins() {
        return this.plugins;
    }
   
    public LinkedList<Plugin<?>> getAllSleepingPlugins() {
        LinkedList<Plugin<?>> sleeping = new LinkedList<>();
       
        for (Plugin<?> p : this.plugins) {
            if (this.isPluginSleeping(p)) {
                sleeping.add(p);
            }
        }
       
        return sleeping;
    }
   
    private boolean isPluginSleeping(Plugin<?> p) {
        return this.neverNotify.contains(p) && this.eventRequestingPlugins.get(p) == null;
    }
   
//    private boolean globalPause = false;
//
//    /**
//     * Pauses the simulation at the core of the main simulation cycle.
//     *
//     * @param globalPause  Activate (true) or deactivate (false) global pause.
//     */
//    public void setGlobalPause(boolean globalPause) {
//        this.globalPause = globalPause;
//    }
}
TOP

Related Classes of eas.simulation.SimulationTime

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.