package manager;
import agent.Agent;
import agent.DNAparameters;
import agent.Painter;
import agent.Tracer;
import environment.Cell;
import parameters.LocalWorldParams;
import environment.World;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;
import constants.AgentConstants;
import constants.EnvironmentConstants;
import constants.EventConstants;
import constants.GUIConstants;
import constants.TimeConstants;
import functions.ColorFunctions;
import gui.MainJFrame;
import java.awt.Color;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import parameters.UserGuiParams;
import time.TimeEventDispatcher;
import time.TimeMachine;
/**
*
* @author Marco Celesti
*/
public class God implements Observer, Runnable {
private static God instance = null;
private Thread thisThread = null;
private int minuteCount = 0;
private GUIController controller = null;
private List<World> worlds = new ArrayList<World>();
private List<Set<Agent>> agentsList = new ArrayList<Set<Agent>>();
private int lastCreated = -1;
private TimeMachine tm = null;
private final Object lock = new Object();
private boolean takeAPhoto = false;
public static God getInstance() {
if (instance == null) {
instance = new God();
}
return instance;
}
public God() {
thisThread = new Thread(this);
thisThread.setName("god");
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
if (args.length > 0) {
File fileConfig = new File(args[0]);
try {
Configurator.readConfig(fileConfig);
God.getInstance().createTime();
} catch (Exception ex) {
System.err.println("Usage: java -jar JSimv3.jar <config_file.conf>");
System.err.println(ex.getMessage());
System.exit(1);
}
} else {
System.err.println("Usage: java -jar JSimv3.jar <config_file.conf>");
}
}
protected void createGUIController() {
if (UserGuiParams.GUI) {
controller = new GUIController(EnvironmentConstants.N_WORLDS_DEF);
controller.addObserver(this);
}
}
private void createTime() {
if (tm == null) {
tm = new TimeMachine();
}
thisThread.start();
tm.startTime();
}
protected void createWorld(LocalWorldParams params) {
World world = new World(params.getIdWorld());
world.setParams(params);
try {
world.initializeEnviroinment();
} catch (IOException ex) {
Logger.getLogger(God.class.getName()).log(Level.SEVERE, null, ex);
}
worlds.add(world);
if (UserGuiParams.GUI) {
controller.addWorld(world);
world.addObserver(controller);
}
world.startThread();
}
protected void createInitialAgents(LocalWorldParams params) {
short progenitor = 0;
Set<Agent> agentsSet = new HashSet<Agent>();
agentsList.add(agentsSet);
for (lastCreated = 0; lastCreated < params.getInitNAgentsPainter(); lastCreated++) {
short i = 0;
short j = 0;
Color c = ColorFunctions.getPainterColorById(lastCreated, params.getInitNAgentsPainter(), params.getColorInUse());
int speed = (int) (Math.random() * 10 + 1);
DNAparameters dnaParams = new DNAparameters(AgentConstants.PAINTER, c, 0, speed);
boolean success;
do {
i = (short) (Math.random() * params.getCols());
j = (short) (Math.random() * params.getRows());
success = worlds.get(params.getIdWorld()).getCell(i, j).setOccupied(AgentConstants.PAINTER, true, -1);
} while (!success);
short id = worlds.get(params.getIdWorld()).getNextAgentId(progenitor);
generatePainter(params.getIdWorld(), worlds.get(params.getIdWorld()).getCell(i, j), dnaParams, id, progenitor);
progenitor++;
}
int tracerCounter;
for (tracerCounter = 0; tracerCounter < params.getInitNAgentsTracer(); tracerCounter++) {
lastCreated++;
short i = 0;
short j = 0;
short divisor = (short) (params.getInitNAgentsTracer() * 7 * EnvironmentConstants.N_WORLDS_DEF);
int mapDimension = params.getCols() * params.getRows();
if (mapDimension < 20000) {
mapDimension = 20000;
}
int lifeLenght = (int) (Math.random() * mapDimension / divisor);
int speed = (int) (Math.random() * 10 + 1);
DNAparameters dnaParams = new DNAparameters(AgentConstants.TRACER, UserGuiParams.RESOURCE_COLOR, lifeLenght, speed);
boolean success;
do {
i = (short) (Math.random() * params.getCols());
j = (short) (Math.random() * params.getRows());
success = worlds.get(params.getIdWorld()).getCell(i, j).setOccupied(AgentConstants.TRACER, true, -1);
} while (!success);
short id = worlds.get(params.getIdWorld()).getNextAgentId(progenitor);
generateTracer(params.getIdWorld(), worlds.get(params.getIdWorld()).getCell(i, j), dnaParams, id, progenitor);
progenitor++;
}
}
private void killAgent(Agent agent) {
short idWorld = agent.getWorld().getId();
synchronized (lock) {
agentsList.get(idWorld).remove(agent);
}
if (UserGuiParams.GUI) {
controller.writeInfo("<-- agent died: " + agent.toString());
}
}
private void generatePainter(short idWorld, Cell cell, DNAparameters dnaParams, short idAgent, short progenitor) {
Painter agent = new Painter(worlds.get(idWorld), dnaParams, cell, idAgent, progenitor);
decorateAgent(agent);
}
private void generateTracer(short idWorld, Cell cell, DNAparameters dnaParams, short idAgent, short progenitor) {
Tracer agent = new Tracer(worlds.get(idWorld), dnaParams, cell, idAgent, progenitor);
decorateAgent(agent);
}
private void decorateAgent(Agent agent) {
agent.addObserver(this);
if (UserGuiParams.GUI) {
controller.createAgent(agent);
agent.addObserver(controller);
}
synchronized (lock) {
agentsList.get(agent.getWorld().getId()).add(agent);
if (UserGuiParams.GUI) {
controller.writeInfo("--> new agent: " + agent.toString());
}
}
agent.startThread();
}
public void update(Observable o, Object arg) {
String event = (String) arg;
if (event.equals(EventConstants.AGENT_EVENT)) {
Agent agent = (Agent) o;
if (!agent.isAlive()) {
if (agent.getDnaParams().getSpecies() == AgentConstants.TRACER) {
if (agent.getParams().isDuplication()) {
ejectAgents(agent);
}
agent.getWorld().deleteTail(agent);
}
killAgent(agent);
} else if (agent.isDuplicating()) {
agent.setDuplicating(false);
ejectAgents(agent);
}
} else if (event.equals(GUIConstants.PHOTO)) {
takeAPhoto = true;
}
}
public void run() {
boolean alive = true;
while (alive) {
String event = TimeEventDispatcher.getInstance().getEventGod(thisThread.getName());
if (event != null && !event.isEmpty()) {
if (UserGuiParams.GUI) {
if (event.startsWith("day")) {
controller.writeInfo("\n" + event + "\n");
}
}
if (TimeConstants.STOP_TIME_IS_ACTIVE) {
minuteCount++;
if (minuteCount >= TimeConstants.STOP_COUNT_MINUTES) {
for (short i = 0; i < agentsList.size(); i++) {
for (Agent agent : agentsList.get(i)) {
agent.stopThread();
}
agentsList.get(i).clear();
}
saveMapFiles();
alive = false;
System.exit(0);
}
}
if (takeAPhoto) {
saveMapFiles();
takeAPhoto = false;
}
}
}
}
protected void packController() {
controller.pack();
}
private void saveMapFiles() {
if (UserGuiParams.ASK_FOLDER) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(MainJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new File("."));
fileChooser.setDialogTitle("Scegli la cartella:");
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
JFrame f = new JFrame();
int returnVal = fileChooser.showSaveDialog(f);
if (returnVal == JFileChooser.APPROVE_OPTION) {
StringBuilder stringBuffer = new StringBuilder();
File dir = fileChooser.getSelectedFile();
for (short i = 0; i < worlds.size(); i++) {
short cols = worlds.get(i).getParams().getCols();
short rows = worlds.get(i).getParams().getRows();
int stopTime = TimeConstants.STOP_COUNT_MINUTES;
short nTracers = worlds.get(i).getParams().getInitNAgentsTracer();
StringBuilder fileName = new StringBuilder();
fileName.append(dir.getPath()).append("\\").append(cols).append("x").append(rows).append("_").append(stopTime).append("min_").append(nTracers).append("tracers.map");
stringBuffer.append(fileName).append("\n");
File file = new File(fileName.toString());
takePhoto(file, worlds.get(i));
}
JOptionPane.showMessageDialog(f, "File salvato:\n" + stringBuffer, "File salvato", JOptionPane.INFORMATION_MESSAGE);
}
} else {
for (short i = 0; i < worlds.size(); i++) {
short cols = worlds.get(i).getParams().getCols();
short rows = worlds.get(i).getParams().getRows();
int stopTime = TimeConstants.STOP_COUNT_MINUTES;
short nTracers = worlds.get(i).getParams().getInitNAgentsTracer();
File localDir = new File(".\\images");
String fileName;
try {
fileName = localDir.getCanonicalPath() + "\\" + cols + "x" + rows + "_" + stopTime + "min" + "_" + nTracers + "tracers_" + Calendar.getInstance().getTimeInMillis() + ".map";
File file = new File(fileName);
takePhoto(file, worlds.get(i));
} catch (IOException ex) {
Logger.getLogger(God.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
private void takePhoto(File file, World world) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException ex) {
Logger.getLogger(GUIController.class.getName()).log(Level.SEVERE, null, ex);
}
PrintStream ps = new PrintStream(fos);
ps.println(world.getParams().getCols() + "x" + world.getParams().getRows());
for (short i = 0; i < world.getParams().getCols(); i++) {
for (short j = 0; j < world.getParams().getRows(); j++) {
ps.println(world.getGrid()[i][j].toStringForMap());
}
}
ps.close();
try {
fos.close();
} catch (IOException ex) {
Logger.getLogger(GUIController.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void ejectAgents(Agent tracer) {
Cell beforeDeathCell = tracer.getUnit().getLastOccupiedCell();
short xleft = beforeDeathCell.getX();
short xright = beforeDeathCell.getX();
short yleft = beforeDeathCell.getY();
short yright = beforeDeathCell.getY();
short direction = tracer.getLastDirection();
short cols = tracer.getWorld().getParams().getCols();
short rows = tracer.getWorld().getParams().getRows();
switch (direction) {
case 0:
xleft--;
xright++;
if (xleft < 0) {
xleft = (short) (cols - 1);
}
if (xright >= cols) {
xright = 0;
}
break;
case 1:
xleft--;
yleft--;
xright++;
yright++;
if (xleft < 0) {
xleft = (short) (cols - 1);
}
if (xright >= cols) {
xright = 0;
}
if (yleft < 0) {
yleft = (short) (rows - 1);
}
if (yright >= rows) {
yright = 0;
}
break;
case 2:
yleft--;
yright++;
if (yleft < 0) {
yleft = (short) (rows - 1);
}
if (yright >= rows) {
yright = 0;
}
break;
case 3:
xleft++;
yleft--;
xright--;
yright++;
if (xleft >= cols) {
xleft = 0;
}
if (xright < 0) {
xright = (short) (cols - 1);
}
if (yleft < 0) {
yleft = (short) (rows - 1);
}
if (yright >= rows) {
yright = 0;
}
break;
case 4:
xleft++;
xright--;
if (xright < 0) {
xright = (short) (cols - 1);
}
if (xleft >= cols) {
xleft = 0;
}
break;
case 5:
xleft++;
yleft++;
xright--;
yright--;
if (xright < 0) {
xright = (short) (cols - 1);
}
if (xleft >= cols) {
xleft = 0;
}
if (yright < 0) {
yright = (short) (rows - 1);
}
if (yleft >= rows) {
yleft = 0;
}
break;
case 6:
yleft++;
yright--;
if (yright < 0) {
yright = (short) (rows - 1);
}
if (yleft >= rows) {
yleft = 0;
}
break;
case 7:
xleft--;
yleft++;
xright++;
yright--;
if (xright >= cols) {
xright = 0;
}
if (xleft < 0) {
xleft = (short) (cols - 1);
}
if (yright < 0) {
yright = (short) (rows - 1);
}
if (yleft >= rows) {
yleft = 0;
}
break;
default:
break;
}
Cell rightCell = tracer.getWorld().getCell(xright, yright);
Cell leftCell = tracer.getWorld().getCell(xleft, yleft);
int leftOrRight = tracer.getLeftOrRight();
Cell internalCell = null, externalCell = null;
if (leftOrRight == -1) {
internalCell = leftCell;
externalCell = rightCell;
} else if (leftOrRight == 1) {
internalCell = rightCell;
externalCell = leftCell;
}
DNAparameters dnaPainter = null;
dnaPainter = new DNAparameters();
dnaPainter.setSpecies(AgentConstants.PAINTER);
short idPainter = tracer.getBorder();
Color c = ColorFunctions.getRandomColor(tracer.getParams().getColorInUse());
dnaPainter.setColor(c);
generatePainter(tracer.getWorld().getId(), internalCell, dnaPainter, idPainter, tracer.getProgenitor());
// settando il parametro e' possibile evitare che venga creato un agente esternamente alla curva
if (tracer.getWorld().getParams().isExternalAgent()) {
dnaPainter = new DNAparameters();
dnaPainter.setSpecies(AgentConstants.PAINTER);
idPainter++;
c = ColorFunctions.getRandomColor(tracer.getParams().getColorInUse());
dnaPainter.setColor(c);
generatePainter(tracer.getWorld().getId(), externalCell, dnaPainter, idPainter, tracer.getProgenitor());
}
}
}