/*-----------------------------------------------------------------------
* Copyright (C) 2001 Green Light District Team, Utrecht University
*
* This program (Green Light District) is free software.
* You may redistribute it and/or modify it under the terms
* of the GNU General Public License as published by
* the Free Software Foundation (version 2 or later).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* See the documentation of Green Light District for further information.
*------------------------------------------------------------------------*/
package gld.sim;
import gld.Controller;
import gld.GLDException;
import gld.GLDToolBar;
import gld.InvalidFilenameException;
import gld.PopupException;
import gld.Selectable;
import gld.algo.dp.DPFactory;
import gld.algo.tlc.Colearning;
import gld.algo.tlc.TLCFactory;
import gld.algo.tlc.TLController;
import gld.edit.EditController;
import gld.edit.EditModel;
import gld.edit.Validation;
import gld.infra.Drivelane;
import gld.infra.EdgeNode;
import gld.infra.InfraException;
import gld.infra.Infrastructure;
import gld.infra.Junction;
import gld.infra.LessSimpleInfra;
import gld.infra.NetTunnelTest1;
import gld.infra.NetTunnelTest2;
import gld.infra.Node;
import gld.infra.SimpleInfra;
import gld.sim.stats.StatisticsController;
import gld.sim.stats.StatisticsOverlay;
import gld.sim.stats.TrackerFactory;
import gld.sim.sync.SyncSignalReceiver;
import gld.sim.sync.SyncSignalReceiverFactory;
import gld.sim.sync.SynchronizationProtocolKeys;
import gld.utils.Arrayutils;
import gld.xml.XMLCannotSaveException;
import gld.xml.XMLElement;
import gld.xml.XMLInvalidInputException;
import gld.xml.XMLLoader;
import gld.xml.XMLSaver;
import gld.xml.XMLTreeException;
import gld.xml.XMLUtils;
import java.awt.CheckboxMenuItem;
import java.awt.Choice;
import java.awt.MenuBar;
import java.awt.PopupMenu;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;
import java.util.ResourceBundle;
import java.util.Vector;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* The main controller for the simulation part of the application.
*
* @author Group GUI
* @version 1.0
*/
public class SimController extends Controller implements Observer
{
protected EditController editController = null;
protected SimMenuBar menuBar;
public static final String[] speedTexts = { "Low", "Medium", "High", "Maximum" };
public static final int[] speedSettings = { 1000, 400, 50, 10 };
protected Choice speedChoice;
protected StatisticsOverlay statsOverlay;
protected SimModelSpawnFreqsUpdate threadSpawnFreq;
protected LinkedList spawnFreqsList = null;
//protected HashMap spawnFreqsHM = null;
/**
* Creates the main frame.
*
* @param m The <code>SimModel</code> to be controlled.
*/
public SimController(SimModel m, boolean splash) {
super(m, splash);
setSimModel(m);
speedChoice=new Choice();
Enumeration e=Arrayutils.getEnumeration(speedTexts);
while (e.hasMoreElements())
speedChoice.add((String)(e.nextElement()));
setSpeed((int)(speedTexts.length / 2));
setCycleCounterEnabled(true);
statsOverlay = new StatisticsOverlay(view,m.getInfrastructure());
//setTLC(0, 1); // Random
setTLC(0, 4); // IAtracos
setDrivingPolicy(0);
}
/*============================================*/
/* GET and SET methods */
/*============================================*/
/** Returns the current <code>SimModel</code> */
public SimModel getSimModel() { return (SimModel)model; }
/** Sets a new <code>SimModel</code> to be controlled */
public void setSimModel(SimModel m) { model = m; }
/** Enables or disables the cycle counter. */
public void setCycleCounterEnabled(boolean b)
{
if(b) {
getSimModel().addObserver(this);
} else {
setStatus("Cycle counter disabled at cycle " + getSimModel().getCurCycle() + ".");
getSimModel().deleteObserver(this);
}
}
/*============================================*/
/* Load and save */
/*============================================*/
public void load(XMLElement myElement,XMLLoader loader)
throws XMLTreeException, IOException, XMLInvalidInputException
{ super.load(myElement,loader);
// TODO restore menu options/choices in GUI
statsOverlay = new StatisticsOverlay(view,getSimModel().getInfrastructure());
if (XMLUtils.getLastName(statsOverlay).equals(loader.getNextElementName()))
{ System.out.println("Loading stats");
loader.load(this, statsOverlay);
}
}
public XMLElement saveSelf() throws XMLCannotSaveException
{ XMLElement result = super.saveSelf();
/* This code is buggy
result.addAttribute(new XMLAttribute("saved-by", "simulator"));
result.addAttribute(new XMLAttribute("tlc-category",
menuBar.getTLCMenu().getCategory()));
result.addAttribute(new XMLAttribute("tlc-number",
menuBar.getTLCMenu().getTLC()));
result.addAttribute(new XMLAttribute("driving-policy",
menuBar.getDPMenu().getSelectedIndex()));
result.addAttribute(new XMLAttribute("speed",
speedChoice.getSelectedIndex()));
*/
return result;
}
public void saveChilds (XMLSaver saver) throws XMLTreeException,IOException,XMLCannotSaveException
{ saver.saveObject(statsOverlay);
}
public void doSave(String filename) throws InvalidFilenameException, Exception
{ if(!filename.endsWith(".sim") )
throw new InvalidFilenameException("Filename must have .sim extension.");
setStatus("Saving simulation to " + filename);
XMLSaver saver=new XMLSaver(new File(filename));
saveAll(saver,getSimModel());
saver.close();
setStatus("Saved simulation to " + filename);
}
public void doLoad(String filename) throws InvalidFilenameException, Exception
{
if(!filename.endsWith(".infra") && !filename.endsWith(".sim"))
throw new InvalidFilenameException("You can only load .infra and .sim files.");
stop();
new WaitSynchronizationSignal().start();
TrackerFactory.purgeTrackers();
XMLLoader loader=new XMLLoader(new File(filename));
System.out.println("Filename: " + filename);
loadAll(loader,getSimModel());
newInfrastructure(model.getInfrastructure());
loader.close();
//GASTON: AGREGUE ESTE CODIGO PARA CARGAR TODOS LOS NODOS DISPONIBLES CUANDO CARGA LA RED EL GLDSIM
Infrastructure infra = model.getInfrastructure();
Node[] nodos = infra.getAllNodes();
for (int i=0;i<nodos.length;i++){
if (nodos[i] instanceof Junction){
((Junction)nodos[i]).updateAllAvailableRoads();
}
}
}
public class WaitSynchronizationSignal extends Thread implements SynchronizationProtocolKeys{
private String sessionId = null;
private boolean alive = true;
public void run(){
HashMap signalInfo = null;
ResourceBundle rb = getSimModel().getResourceBundle();
SyncSignalReceiver receiver = SyncSignalReceiverFactory.getSignalReceiver(rb);
while(alive)
{
try {
signalInfo = receiver.getSignalInfo(sessionId,rb);
if (threadSpawnFreq != null){
System.out.println("Preparing to re-synchronize");
threadSpawnFreq.destroy();
}
getSimModel().restartSpawnFreqs();
threadSpawnFreq = new SimModelSpawnFreqsUpdate();
long interval = Long.parseLong((String)signalInfo.get(INTERVAL));
if (sessionId == null)
sessionId = (String)signalInfo.get(SESSIONID);
if (interval > 0)
threadSpawnFreq.setSleep_time(interval);
else
System.out.println("Error in the information received by the Synchronization signal");
threadSpawnFreq.start();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class SimModelSpawnFreqsUpdate extends Thread
{
protected long sleep_time = 0;
protected boolean alive = true;
public SimModelSpawnFreqsUpdate(){
}
public void run( ) {
while (alive){
try {
getSimModel().updateSpawnFreqs();
sleep(sleep_time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* @return
*/
public long getSleep_time() {
return sleep_time;
}
/**
* @param i
*/
public void setSleep_time(long i) {
sleep_time = i;
}
public void destroy(){
alive = false;
}
}
/* Iterator iFreqs = spawnFreqsList.iterator();
HashMap spawnFreqs = null;
int nroFranja = 0;
while (true) {
try {
System.out.println("Se levanto el Thread!!");
if (!iFreqs.hasNext()){
iFreqs = spawnFreqsList.iterator();
nroFranja = 0;
}
nroFranja ++;
System.out.println("Franja Horaria: " + nroFranja);
spawnFreqs = (HashMap)iFreqs.next();
Infrastructure infra = model.getInfrastructure();
Node[] nodos = infra.getAllNodes();
int k = 0;
for (int i=0;i<nodos.length;i++){
if (nodos[i] instanceof EdgeNode){
EdgeNode en = ((EdgeNode)nodos[i]);
String[] freqs = (String[])spawnFreqs.get(Integer.toString(en.getId()));
((SimModel)model).setSpawnFrequency(en,1,Float.parseFloat(freqs[0]));
((SimModel)model).setSpawnFrequency(en,2,Float.parseFloat(freqs[1]));
((SimModel)model).setSpawnFrequency(en,3,Float.parseFloat(freqs[2]));
}
}
sleep(30000);
} catch (Exception e) {
System.out.println("Se lanzó una excepción");
e.printStackTrace();
}
}
}*/
/*============================================*/
/* Miscellanous */
/*============================================*/
/** Called by observable SimModel (if view enabled). */
public void update(Observable o, Object arg)
{ int cycle=((SimModel)o).getCurCycle();
if (cycle!=0)
setStatus("Cycle: " + cycle);
}
/** Returns the name of this controller extension. */
protected String appName() { return "simulator"; }
protected MenuBar createMenuBar() {
menuBar = new SimMenuBar(this, speedTexts);
return menuBar;
}
protected GLDToolBar createToolBar() {
return new SimToolBar(this);
}
/*============================================*/
/* Invoked by Listeners */
/*============================================*/
/**
* Opens the statistics viewer.
*/
public void showStatistics()
{
new StatisticsController(getSimModel(), this);
}
/**
* Shows the tracking window.
*/
public void showTracker(int type)
{
try
{
TrackerFactory.showTracker(getSimModel(), this, type);
}
catch(GLDException e)
{
reportError(e.fillInStackTrace());
}
}
/** Enables the statistics overlay */
public void enableOverlay() {
statsOverlay = new StatisticsOverlay(view, getSimModel().getInfrastructure());
getSimModel().addObserver(statsOverlay);
view.addOverlay(statsOverlay);
}
/** Enables the statistics overlay */
public void disableOverlay() {
getSimModel().deleteObserver(statsOverlay);
view.remOverlay(statsOverlay);
}
public void setDrivingPolicy(int dp)
{ try
{ getSimModel().setDrivingPolicy(
(new DPFactory(getSimModel(),getSimModel().getTLController())).getInstance
(dp));
}
catch (Exception e)
{ reportError(e);
}
}
public void setTLC(int cat, int nr)
{ setColearningEnabled(cat == 1);
try {
SimModel sm = getSimModel();
TLCFactory tlcf = new TLCFactory(sm.getInfrastructure(), sm.getRandom());
TLController tlc = tlcf.genTLC(cat, nr);
tlc.showSettings(this);
sm.setTLController(tlc);
setColearningEnabled((tlc instanceof Colearning));
}
catch (GLDException e) {
reportError(e.fillInStackTrace());
}
}
private void setColearningEnabled(boolean b) {
if (!b && menuBar.getDPMenu().getSelectedIndex() == DPFactory.COLEARNING) {
menuBar.getDPMenu().select(DPFactory.SHORTEST_PATH);
}
((CheckboxMenuItem)menuBar.getDPMenu().getItem(DPFactory.COLEARNING)).setEnabled(b);
}
/** Shows the file properties dialog */
public void showFilePropertiesDialog()
{
String simName = getSimModel().getSimName();
Infrastructure infra = getSimModel().getInfrastructure();
String comments = infra.getComments();
SimPropDialog propDialog = new SimPropDialog(this, simName, comments);
propDialog.show();
if(propDialog.ok())
{
getSimModel().setSimName(propDialog.getSimName());
infra.setComments(propDialog.getComments());
}
this.setStatus("Simulation \"" + getSimModel().getSimName() + "\".");
}
/** Creates a right-click popup-menu for the given object */
public PopupMenu getPopupMenuFor(Selectable obj) throws PopupException {
SimPopupMenuFactory pmf = new SimPopupMenuFactory(this);
return pmf.getPopupMenuFor(obj);
}
/** Returns the filename of the currently loaded file */
public String getCurrentFilename() {
return currentFilename;
}
/** Sets the speed of the simulation */
public void setSpeed(int speed) {
((SimToolBar)toolBar).getSpeed().select(speed);
menuBar.getSpeedMenu().select(speed);
getSimModel().setSpeed(speedSettings[speed]);
}
/** Makes model do one step */
public void doStep() { getSimModel().doStep(); }
/** GASTON: CUTS THE TRAFFIC */
public void disableTraffic(Drivelane lane) {
this.pause();
getSimModel().disableTraffic(lane);
if (!validateInfra()){
enableTraffic(lane);
}
this.unpause();
}
/** GASTON: ALLOW TRAFFIC */
public void enableTraffic(Drivelane lane) {
this.pause();
getSimModel().enableTraffic(lane);
if (!validateInfra()){
disableTraffic(lane);
}
this.unpause();
}
/** Paues the simulation */
public void pause() {
setStatus("Paused at cycle " + getSimModel().getCurCycle() + ".");
getSimModel().pause();
}
/** Resumes or starts the simulation */
public void unpause() {
setStatus("Simulation running.");
getSimModel().unpause();
}
/** Stops the simulation and resets the infrastructure */
public void stop() {
int cycle=getSimModel().getCurCycle() ;
if (cycle!=0)
setStatus("Stopped at cycle " + ".");
try {
getSimModel().pause();
getSimModel().reset();
}
catch (SimulationRunningException ex) {
reportError(ex.fillInStackTrace());
getSimModel().unpause();
}
}
/** Opens the editor */
public void openEditor() {
if (editController == null) editController = new EditController(new EditModel(), false);
editController.show();
editController.requestFocus();
}
/** Set temp debug infra */
protected void setInfra(int nr)
{ Infrastructure infra;
switch (nr)
{ case 1 : infra=new SimpleInfra(); break;
case 2 : infra=new LessSimpleInfra(); break;
case 3 : infra=new NetTunnelTest1(); break;
case 4 : infra=new NetTunnelTest2(); break;
default: infra=new Infrastructure(); break;
}
try
{ Vector errors=(new Validation(infra)).validate();
if(!errors.isEmpty())
showError(errors.toString());
}
catch (InfraException e)
{ reportError(e);
}
getSimModel().setCurCycle(0);
newInfrastructure(infra);
}
}