package de.tu_darmstadt.tk.SmartHomeNetworkSim.core; import java.util.LinkedList; import java.util.Observable; import javax.swing.Timer; import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller; import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.scheduler.Schedulable; import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.scheduler.Scheduler; /** * Manages the Simulation by calling the relevant methods. * * @author Andreas T. Meyer-Berg */ public class SimulationManager extends Observable { /** * Model which should be simulated */ private Model model; /** * Controller for manipulationAlgorithms */ private Controller controller; /** * Whether the model status changed during the last simulation and the panel * should be repainted */ private boolean statusChanged = false; /** * Timer which triggers each simulation step */ private Timer timer; /** * First Timestep of the simulation */ private long startTime = 0L; /** * Last Timestep of the simulation */ private long endTime = 1000L; /** * Current TimeStep in the simulation */ private long currentTime = 0L; /** * Duration of the simulation */ private long duration = 100L; /** * ManipulationAlgorithm Instances, which should run in each timestep */ private LinkedList algos = new LinkedList(); /** * PacketCollectionManager which manages the collection of packets */ private PacketCollectionManager collectionMan; /** * PacketExportManager which handles packet export */ private PacketExportManager exportMan; /* * Peformance Eval */ //private long perfStart = 0; /** * Scheduler which stores the event queue and enables scheduling and running of further events */ private static Scheduler scheduler; /** * Creates a new Simulationmanager * * @param model * Model that should be simulated */ public SimulationManager(Model model) { this.model = model; this.controller = null; this.collectionMan = new PacketCollectionManager(model); this.exportMan = new PacketExportManager(model); timer = new Timer(0, t -> simulateTimeStep()); scheduler = new Scheduler(); } /** * Simulate the next Timestep */ private void simulateTimeStep() { // Just simulate if timer is running if (endTime <= currentTime){ stopSimulation(); return; } if (currentTime + duration <= endTime) { simulateTimeIntervall(currentTime, duration); currentTime += duration; notifyPanels(); } else { simulateTimeIntervall(currentTime, endTime - currentTime); currentTime = endTime; stopSimulation(); } } /** * Simulates one time step at a given time for a given duration * * @param startTime * Time the simulation interval starts in * System.currentTimeMillis() time * @param duration * Duration of the simulation interval in milliseconds */ public void simulateTimeIntervall(long startTime, long duration) { scheduler.setMinTime(startTime); //TODO: Fill Queue //TODO: Simulate Schedule //TODO: Export //Simulates the network boolean oldWay = false; if(oldWay) simulateNetwork(startTime, duration); else{ long maxTime = startTime + duration; scheduler.scheduleAll(model); for(Connection con:model.getConnections()){ Link l = con.getLink(); if(l!=null){ l.getPackets().clear(); l.addPackets(con.getTerminationPackages(startTime)); } } while(scheduler.hasNext(maxTime)){ Schedulable currentEvent = scheduler.getAndRemoveFirst(); //System.out.println("Event time: "+currentEvent.getEventTime()); currentEvent.simulateEvent(currentEvent.getEventTime()); } // Simulate SmartDevices - if they need some logic -> TODO: Insert as schedulable model.getDevices().forEach(d -> d.simulateTimeStep(startTime, duration)); } runAlgorithms(startTime+duration); collectionMan.collectPackets(); //Run all collectionMan.runPacketAlgorithms(); //Export Packets exportMan.exportPacketsOfLastTimeStep(); } /** * Simulates one time step of the network at a given time for a given duration * * @param startTime * Time the simulation interval starts in * System.currentTimeMillis() time * @param duration * Duration of the simulation interval in milliseconds */ private void simulateNetwork(long startTime, long duration){ //TODO: Implement Event Schedule // Nothing changed so far statusChanged = false; // Simulate all Links, and their connections model.getConnectionNetworks().forEach(d -> { d.simulateTimeInterval(startTime, duration); if (d.getStatusChanged()) { for (Connection c : d.getConnections()) { if (c.getStatus() == Connection.DONE) { model.getConnections().remove(c); } } statusChanged = true; } }); // Simulate SmartDevices - if they need some logic model.getDevices().forEach(d -> d.simulateTimeStep(startTime, duration)); // Store Packages/Export Packages etc. (for debug purposes) if (statusChanged) { model.setChanged(); model.notifyObservers(); } } /** * Start the simulation */ public void startSimulation() { //perfStart=System.currentTimeMillis(); timer.start(); notifyPanels(); } /** * Stop the simulation */ public void stopSimulation() { timer.stop(); /* long perfEnd = System.currentTimeMillis(); long duration = perfEnd - perfStart; System.out.println("Duration: "+duration/1000.0); */ notifyPanels(); } /** * Resets the Simulation to the start time */ public void resetSimulation() { timer.stop(); timer = new Timer(0, a -> simulateTimeStep()); currentTime = startTime; resetSimulation(currentTime); notifyPanels(); } /** * Reset Simulation * * @param timestep new timestep of ports after the reset */ private void resetSimulation(long timestep) { for (SmartDevice d : model.getDevices()) for (Port p : d.getPorts()) if (p.getLastTrigger() > timestep) p.setLastTrigger(timestep); scheduler.reset(timestep); /** for(Connection c: model.getConnections()) for(Port p: c.getParticipants()) if (p.getLastTrigger() > timestep) System.out.println("P without owner: "+p.toString());*/ } /** * Returns true if the simulation is running, false if not * * @return true if running */ public boolean isRunning() { return timer.isRunning(); } /** * Returns the StartTime of the simulation * * @return startTime */ public long getStartTime() { return startTime; } /** * Sets the new startTime * * @param startTime * time the simulations starts */ public void setStartTime(long startTime) { this.startTime = startTime; notifyPanels(); } /** * Returns the end time of the simulation * * @return End time of the simulation */ public long getEndTime() { return endTime; } /** * Sets the new startTime * @param endTime new EndTime */ public void setEndTime(long endTime) { this.endTime = endTime; notifyPanels(); } /** * @return the currentTime */ public long getCurrentTime() { return currentTime; } /** * @param currentTime * the currentTime to set */ public void setCurrentTime(long currentTime) { this.currentTime = currentTime; notifyPanels(); } /** * Returns the simulation step duration in milliseconds * * @return duration of each simulation step in milliseconds */ public long getStepDuration() { return duration; } /** * Sets the duration of simulation steps * * @param duration * duration in milliseconds of a step */ public void setStepDuration(long duration) { if(duration>0) this.duration = duration; else this.duration = 1; notifyPanels(); } /** * Notify the panels, which could update their GUI */ public void notifyPanels() { this.setChanged(); this.notifyObservers(); } /** * Runs all registered algorithms at the currentTimeStep * @param time currentTime of the simulation */ public void runAlgorithms(long time) { /** * Run all Algorithms */ for(NetworkManipulationAlgorithm algo:algos){ algo.runAlgorithm(controller, time); } } /** * Returns all registered algorithms of the simulation * @return all registered algorithms */ public LinkedList getAlgorithms(){ return algos; } /** * Adds an algorithm, which should be executed each timestep * @param algo new algorithm */ public void addAlgorithm(NetworkManipulationAlgorithm algo, Controller controller){ this.controller = controller; if(algo!=null) algos.add(algo); } /** * Removes algorithms from the simulation * @param algo algorithm to be removed */ public void removeAlgo(NetworkManipulationAlgorithm algo){ algos.remove(algo); } /** * Returns the PacketCollectionManager of the simulation * @return PacketCollectionManager, which contains all the different packet collectors */ public PacketCollectionManager getPacketCollectionManager(){ return collectionMan; } /** * Returns the PacketExportManager * @return the exportMan */ public PacketExportManager getPacketExportManager(){ return exportMan; } /** * Adds an event to the event queue, which will be simulated later. Returns falls, if it could not be added (e.g. timestep to low) * @param event event which should be scheduled * @return true if it was scheduled, false if not */ public static boolean scheduleEvent(Schedulable event){ return scheduler.scheduleEvent(event); } /** * Removes an event from the global event queue * @param event Event which should be removed * @return true, if it was removed, false if not */ public static boolean removeEvent(Schedulable event){ return scheduler.removeEvent(event); } }