package srsim.io;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonNumber;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonReader;
import srsim.domain.IActuator;
import srsim.domain.IController;
import srsim.domain.ISensor;
import srsim.domain.Room;
import srsim.domain.Simulation;
import srsim.simulator.ITimeSource;
import srsim.simulator.SimulationConfigurationException;
import srsim.simulator.SimulationContextException;
import srsim.simulator.SystemTimeTimeSource;
/**
* Reads/writes simulation configuration from/to files
*
* @author phil
*
*/
public abstract class ConfigurationManager {
private static final String FILE_ENCODING = "UTF-8";
/**
* Write a simulation to a file
*
* @param fileName
* File to which the configuration is written
* @param simulation
* The simulation to write
* @throws SimulationContextException
* @throws IOException
*/
public static void writeToFile(final String fileName,
final Simulation simulation) throws SimulationContextException,
IOException {
JsonObjectBuilder builder = Json.createObjectBuilder();
builder.add("timesource",
simulation.getContext().getTimeSource().getClass().getName())
.add("rooms", buildRoomArray(simulation))
.add("temperature", simulation.getContext().getTemperature())
.add("brightness", simulation.getContext().getBrightness())
.add("lightColor", buildColorArray(simulation))
.add("preferences",
buildPreferencesObject(simulation.getContext()
.getPreferences()));
JsonObject object = builder.build();
File cfgFile = new File(fileName);
if (!cfgFile.exists()) {
cfgFile.createNewFile();
}
PrintWriter writer = new PrintWriter(cfgFile, FILE_ENCODING);
writer.write(object.toString());
writer.close();
}
/**
* Reads a simulation configuration from a file
*
* @param url
* The file from which to read the simulation configuration
* @return
* @throws IOException
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws SimulationContextException
* @throws SimulationConfigurationException
*/
public static Simulation readFromFile(final URL url) throws IOException,
InstantiationException, IllegalAccessException,
ClassNotFoundException, SimulationContextException,
SimulationConfigurationException {
InputStream inputStream = url.openStream();
JsonReader jsonReader = Json.createReader(inputStream);
JsonObject simulationObject = jsonReader.readObject();
String timeSourceClass = simulationObject.getString("timesource");
ITimeSource timeSource = null;
if (timeSourceClass != null) {
timeSource = (ITimeSource) Class.forName(timeSourceClass)
.newInstance();
} else {
timeSource = new SystemTimeTimeSource();
}
Simulation simulation = new Simulation(timeSource);
JsonNumber resolution = simulationObject.getJsonNumber("resolution");
simulation.setResolution(resolution != null ? resolution.longValue()
: 1000L);
JsonNumber temperature = simulationObject.getJsonNumber("temperature");
if (temperature != null) {
simulation.getContext().setTemperature(temperature.doubleValue());
}
JsonNumber brightness = simulationObject.getJsonNumber("brightness");
if (brightness != null) {
simulation.getContext().setBrightness(brightness.doubleValue());
}
JsonArray colorArray = simulationObject.getJsonArray("lightColor");
if (colorArray != null && colorArray.size() == 3) {
simulation.getContext().setLightColor(
new int[] { colorArray.getInt(0), colorArray.getInt(1),
colorArray.getInt(2) });
}
JsonArray rooms = simulationObject.getJsonArray("rooms");
if (rooms != null) {
for (JsonObject roomDescription : rooms
.getValuesAs(JsonObject.class)) {
Room room = readRoom(roomDescription);
simulation.addRoom(room);
}
}
JsonObject preferencesObject = simulationObject
.getJsonObject("preferences");
if (preferencesObject != null) {
for (String key : preferencesObject.keySet()) {
simulation.getContext().setPreference(key,
preferencesObject.getString(key));
}
}
return simulation;
}
private static JsonObject buildPreferencesObject(
Map<String, List<String>> preferences) {
JsonObjectBuilder preferencesObjectBuilder = Json.createObjectBuilder();
for (String key : preferences.keySet()) {
for (String value : preferences.get(key)) {
preferencesObjectBuilder.add(key, value);
}
}
return preferencesObjectBuilder.build();
}
/**
* Builds a JsonArray out of a simulations list of Room objects
*
* @param simulation
* @return
*/
private static JsonArray buildRoomArray(Simulation simulation) {
JsonArrayBuilder roomBuilder = Json.createArrayBuilder();
for (Room room : simulation.getRooms()) {
JsonObjectBuilder roomObjectBuilder = Json.createObjectBuilder();
roomObjectBuilder.add("id", room.getId())
.add("name", room.getName())
.add("sensors", buildSensorArray(room))
.add("actuators", buildActuatorArray(room))
.add("controllers", buildControllerArray(room));
roomBuilder.add(roomObjectBuilder.build());
}
JsonArray roomArray = roomBuilder.build();
return roomArray;
}
private static JsonArray buildControllerArray(Room room) {
JsonArrayBuilder controllerArrayBuilder = Json.createArrayBuilder();
List<IController> controllers = room.getControllers();
if (controllers != null) {
for (IController controller : controllers) {
JsonObjectBuilder controllerObjectBuilder = Json
.createObjectBuilder();
controllerObjectBuilder.add("id", controller.getId()).add(
"class", controller.getClass().getName());
List<ISensor> attachedSensors = controller.getAttachedSensors();
if (attachedSensors != null) {
JsonArrayBuilder sensorArrayBuilder = Json
.createArrayBuilder();
for (ISensor sensor : attachedSensors) {
sensorArrayBuilder.add(sensor.getId());
}
controllerObjectBuilder.add("sensors",
sensorArrayBuilder.build());
}
List<IActuator> attachedActuators = controller
.getAttachedActuators();
if (attachedActuators != null) {
JsonArrayBuilder actuatorArrayBuilder = Json
.createArrayBuilder();
for (IActuator actuator : attachedActuators) {
actuatorArrayBuilder.add(actuator.getId());
}
controllerObjectBuilder.add("actuators",
actuatorArrayBuilder.build());
}
controllerArrayBuilder.add(controllerObjectBuilder.build());
}
}
return controllerArrayBuilder.build();
}
private static JsonArray buildActuatorArray(Room room) {
JsonArrayBuilder actuatorArrayBuilder = Json.createArrayBuilder();
for (IActuator actuator : room.getActuators()) {
JsonObject actuatorObject = Json.createObjectBuilder()
.add("id", actuator.getId())
.add("class", actuator.getClass().getName()).build();
actuatorArrayBuilder.add(actuatorObject);
}
return actuatorArrayBuilder.build();
}
private static JsonArray buildSensorArray(Room room) {
JsonArrayBuilder sensorArrayBuilder = Json.createArrayBuilder();
for (ISensor sensor : room.getSensors()) {
JsonObject sensorObject = Json.createObjectBuilder()
.add("id", sensor.getId())
.add("class", sensor.getClass().getName()).build();
sensorArrayBuilder.add(sensorObject);
}
return sensorArrayBuilder.build();
}
private static JsonArray buildColorArray(final Simulation simulation) {
JsonArrayBuilder colorArrayBuilder = Json.createArrayBuilder();
int[] lightColor = simulation.getContext().getLightColor();
colorArrayBuilder.add(lightColor[0]).add(lightColor[1])
.add(lightColor[2]);
JsonArray colorArray = colorArrayBuilder.build();
return colorArray;
}
private static Room readRoom(JsonObject roomDescription)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException, SimulationConfigurationException {
Map<Integer, ISensor> sensorMap = new HashMap<Integer, ISensor>();
Map<Integer, IActuator> actuatorMap = new HashMap<Integer, IActuator>();
Room room = new Room();
JsonNumber roomId = roomDescription.getJsonNumber("id");
if (roomId != null) {
room.setId(roomId.longValue());
}
String roomName = roomDescription.getString("name");
if (roomName != null) {
room.setName(roomName);
}
JsonArray sensors = roomDescription.getJsonArray("sensors");
if (sensors != null) {
for (JsonObject sensorDescription : sensors
.getValuesAs(JsonObject.class)) {
ISensor sensor = (ISensor) Class.forName(
sensorDescription.getString("class")).newInstance();
sensor.setId(sensorDescription.getJsonNumber("id").longValue());
room.addSensor(sensor);
sensorMap.put(sensorDescription.getInt("id"), sensor);
}
}
JsonArray actuators = roomDescription.getJsonArray("actuators");
if (actuators != null) {
for (JsonObject actuatorDescription : actuators
.getValuesAs(JsonObject.class)) {
IActuator actuator = (IActuator) Class.forName(
actuatorDescription.getString("class")).newInstance();
actuator.setId(actuatorDescription.getJsonNumber("id")
.longValue());
room.addActuator(actuator);
actuatorMap.put(actuatorDescription.getInt("id"), actuator);
}
}
JsonArray controllers = roomDescription.getJsonArray("controllers");
if (controllers != null) {
for (JsonObject controllerDescription : controllers
.getValuesAs(JsonObject.class)) {
IController controller = (IController) Class.forName(
controllerDescription.getString("class")).newInstance();
controller.setId(controllerDescription.getJsonNumber("id")
.longValue());
JsonArray sensorArray = controllerDescription
.getJsonArray("sensors");
if (sensorArray != null) {
for (JsonNumber sensorId : sensorArray
.getValuesAs(JsonNumber.class)) {
controller.attachSensor(sensorMap.get(sensorId
.intValue()));
}
}
JsonArray actuatorArray = controllerDescription
.getJsonArray("actuators");
if (actuatorArray != null) {
for (JsonNumber actuatorId : actuatorArray
.getValuesAs(JsonNumber.class)) {
controller.attachActuator(actuatorMap.get(actuatorId
.intValue()));
}
}
room.addController(controller);
}
}
return room;
}
}