package org.lucci.madhoc.simulation;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
import org.lucci.madhoc.network.Application;
import org.lucci.madhoc.network.Connection;
import org.lucci.madhoc.network.Network;
import org.lucci.madhoc.network.Station;
import org.lucci.madhoc.simulation.measure.MeasureHistory;
import org.lucci.madhoc.simulation.measure.MeasureUtility;
import org.lucci.madhoc.simulation.measure.Sensor;
import org.lucci.madhoc.simulation.projection.Projection;
import org.lucci.util.Timer;
public class MadhocSimulation extends Simulation implements Configurable
{
private Network network;
private boolean enableMobileStationLocation = true;
private boolean enableStationActivity = true;
private boolean supportExitAndJoin = false;
private boolean enableMeasures = true;
private int garbageCollectionIterations = 10;
private long measurementDuration = -1;
private long mobilityUpdateDuration = -1;
private long connectionsUpdateDuration = -1;
private long stationActivityDuration = -1;
private long messageTransferDuration = -1;
private Collection<SimulationListener> simulationListeners = new Vector<SimulationListener>();
private boolean mobility_write_xy_files;
public Collection<SimulationListener> getSimulationListeners()
{
return simulationListeners;
}
public Collection<Monitor> findRunningApplications()
{
Collection<Monitor> v = new Vector<Monitor>();
for (Monitor monitor : getNetwork().getSimulationApplicationMap().values())
{
if (!monitor.hasCompleted())
{
v.add(monitor);
}
}
return v;
}
public boolean isEnableMeasures()
{
return enableMeasures;
}
public void setEnableMeasures(boolean enableMeasures)
{
this.enableMeasures = enableMeasures;
}
public boolean isEnableMobileStationLocation()
{
return enableMobileStationLocation;
}
public void setEnableMobileStationLocation(boolean enableMobileStationLocation)
{
this.enableMobileStationLocation = enableMobileStationLocation;
}
public boolean isEnableStationActivity()
{
return enableStationActivity;
}
public void setEnableStationActivity(boolean enableStationActivity)
{
this.enableStationActivity = enableStationActivity;
}
public void iterate()
{
iterate(true);
}
public void iterate(boolean reset)
{
System.out.println(getIteration());
for (SimulationListener l : getSimulationListeners())
l.iterationStarting(this);
if (getIteration() == 0)
{
setStartDate(System.currentTimeMillis());
}
Timer timer = new Timer();
if (getIteration() % getGarbageCollectionIteration() == 0)
{
System.gc();
}
if (isEnableMobileStationLocation())
{
for (SimulationListener l : getSimulationListeners())
l.beforeTheStationsMove(this);
timer.initialize();
for (Station station : getNetwork().getStations())
{
station.getMobilityModel().moveStation(getResolution(), getSimulatedTime());
if (this.mobility_write_xy_files)
{
station.getMobilityModel().saveLocation();
}
}
mobilityUpdateDuration = timer.getElapsedMillis();
for (SimulationListener l : getSimulationListeners())
l.afterTheStationsMove(this);
for (Station station : getNetwork().getStations())
{
if (station.getVolatilityModel() != null)
{
station.setSwitchedOn(station.getVolatilityModel().stationIsEnabled());
}
}
Collection<Connection> removedConnections = getNetwork().removeInvalidConnections();
for (SimulationListener l : getSimulationListeners())
l.connectionsHaveVanished(this, removedConnections);
Collection<Connection> addedConnections = getNetwork().createNewConnections();
for (SimulationListener l : getSimulationListeners())
l.connectionsHaveAppeared(this, addedConnections);
connectionsUpdateDuration = timer.getElapsedMillis();
}
else
{
mobilityUpdateDuration = -1;
connectionsUpdateDuration = -1;
}
if (isEnableStationActivity())
{
for (SimulationListener l : getSimulationListeners())
l.beforeStationsDo(this);
timer.initialize();
giveLifeToStations();
stationActivityDuration = timer.getElapsedMillis();
for (SimulationListener l : getSimulationListeners())
l.afterStationsDo(this);
}
for (SimulationListener l : getSimulationListeners())
l.beforeDataTransfer(this);
timer.initialize();
getNetwork().flushOutgoingMessageQueues();
messageTransferDuration = timer.getElapsedMillis();
for (SimulationListener l : getSimulationListeners())
l.afterDataTransfer(this);
for (SimulationListener l : getSimulationListeners())
l.beforeSensing(this);
timer.initialize();
setIteration(getIteration() + 1);
if (isEnableMeasures())
{
takeMesures();
}
this.measurementDuration = timer.getElapsedMillis();
for (SimulationListener l : getSimulationListeners())
l.afterSensing(this);
for (SimulationListener l : getSimulationListeners())
l.iterationHasCompleted(this);
if (reset)
{
resetIterationScopedValues();
}
{
++iterationCounter;
double iterationCountDuration = System.currentTimeMillis() - iterationCountStartDate;
if (iterationCountDuration >= 1000)
{
setIterationFrequency((1000d * iterationCounter) / iterationCountDuration);
iterationCountStartDate = System.currentTimeMillis();
iterationCounter = 0;
}
}
}
public void resetIterationScopedValues()
{
getNetwork().resetIterationScopedValues();
for (Monitor monitor : getNetwork().getMonitorMap().values())
{
monitor.resetIterationScopedValues();
}
}
public Network getNetwork()
{
return network;
}
public void setNetwork(Network network)
{
this.network = network;
}
public int convertBytesPerIterationToKilobitsPerSecond(int byteCount)
{
return (int) (getResolution() * byteCount / 100);
}
private void giveLifeToStations()
{
List<Application> stationApplications = new Vector<Application>(getNetwork().getStationApplications());
Collections.shuffle(stationApplications, getRandomNumberGenerator().getRandom());
for (Application app : stationApplications)
{
app.doIt(getResolution());
}
}
public long getConnectionsUpdateDuration()
{
return connectionsUpdateDuration;
}
public long getMeasurementDuration()
{
return measurementDuration;
}
public long getMessageTransferDuration()
{
return messageTransferDuration;
}
public long getMobilityUpdateDuration()
{
return mobilityUpdateDuration;
}
public long getStationActivityDuration()
{
return stationActivityDuration;
}
public void configure() throws Throwable
{
super.configure();
Network net = new Network();
net.setSimulation(this);
net.configure();
setNetwork(net);
this.mobility_write_xy_files = getConfiguration().getBoolean("mobility_write_xy_files");
setGarbageCollectionIteration(getConfiguration().getInteger("garbage_collection_iterations"));
this.simulationListeners.addAll((Collection<SimulationListener>) getConfiguration().getInstantiatedClasses("simulation_listeners"));
for (Monitor monitor : (Collection<Monitor>) getConfiguration().getInstantiatedClasses("monitors_class"))
{
monitor.setNetwork(net);
monitor.configure();
getNetwork().deployApplication(monitor);
}
if (enableMeasures)
{
takeMesures();
}
}
public boolean isSupportExitAndJoin()
{
return supportExitAndJoin;
}
public void setSupportExitAndJoin(boolean supportExitAndJoin)
{
this.supportExitAndJoin = supportExitAndJoin;
}
private void takeMesures()
{
for (Projection projection : getNetwork().getProjectionMap().values())
{
for (MeasureHistory repository : projection.getMeasureHistoryMap().values())
{
try
{
repository.addValue(repository.getSensor().takeNewValue(projection), getIteration());
}
catch (Throwable ex)
{
ex.printStackTrace();
repository.addValue(null, getIteration());
System.err.println("Warning! Cannot take measure " + repository.getSensor().getName() + " on projection " + projection.getName());
}
}
projection.setProjectionResult(null);
}
}
public Collection<Sensor> findAllSensors()
{
Collection<Sensor> c = new Vector<Sensor>();
for (Monitor monitor : getNetwork().getMonitorMap().values())
{
c.addAll(monitor.getSensorMap().values());
}
return c;
}
public Sensor findSensor(Class clazz)
{
for (Monitor monitor : getNetwork().getMonitorMap().values())
{
Sensor sensor = monitor.getSensorMap().get(clazz);
if (sensor != null)
{
return sensor;
}
}
return null;
}
public Sensor findSensorByMeasureName(String s)
{
for (Sensor sensor : findAllSensors())
{
if (sensor.getName().equals(s))
{
return sensor;
}
}
return null;
}
public int getGarbageCollectionIteration()
{
return this.garbageCollectionIterations;
}
public void setGarbageCollectionIteration(int garbageCollectionIterations)
{
this.garbageCollectionIterations = garbageCollectionIterations;
}
public String getOutputAsText()
{
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PrintStream pos = new PrintStream(bos);
MeasureUtility.saveNumericalMeasuresToGNUPlotStream(this, pos, true);
byte[] output = bos.toByteArray();
pos.close();
bos.close();
return new String(output);
}
catch (IOException ex)
{
ex.printStackTrace();
throw new IllegalStateException();
}
}
public String getOutputAsBytes()
{
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PrintStream pos = new PrintStream(bos);
MeasureUtility.saveNumericalMeasuresToGNUPlotStream(this, pos, true);
byte[] output = bos.toByteArray();
pos.close();
bos.close();
return new String(output);
}
catch (IOException ex)
{
ex.printStackTrace();
throw new IllegalStateException();
}
}
}