package org.opentrafficsim.demo.trafficcontrol;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.rmi.RemoteException;
import java.util.Scanner;
import javax.naming.NamingException;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.djunits.value.vdouble.scalar.Duration;
import org.djunits.value.vdouble.scalar.Time;
import org.djutils.event.EventInterface;
import org.djutils.event.EventListenerInterface;
import org.djutils.event.EventTypeInterface;
import org.djutils.immutablecollections.ImmutableMap;
import org.djutils.io.URLResource;
import org.djutils.logger.CategoryLogger;
import org.opentrafficsim.core.dsol.AbstractOTSModel;
import org.opentrafficsim.core.dsol.OTSAnimator;
import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
import org.opentrafficsim.core.object.InvisibleObjectInterface;
import org.opentrafficsim.demo.trafficcontrol.TrafCODDemo2.TrafCODModel;
import org.opentrafficsim.draw.core.OTSDrawingException;
import org.opentrafficsim.road.network.OTSRoadNetwork;
import org.opentrafficsim.road.network.factory.xml.parser.XmlNetworkLaneParser;
import org.opentrafficsim.swing.gui.OTSAnimationPanel;
import org.opentrafficsim.swing.gui.OTSSimulationApplication;
import org.opentrafficsim.trafficcontrol.TrafficController;
import org.opentrafficsim.trafficcontrol.trafcod.TrafCOD;
import org.opentrafficsim.xml.generated.OTS;
import nl.tudelft.simulation.dsol.SimRuntimeException;
import nl.tudelft.simulation.dsol.swing.gui.TabbedContentPane;
import nl.tudelft.simulation.language.DSOLException;
/**
*
* Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Dec 06, 2016
* @author Alexander Verbraeck
* @author Peter Knoppers
* @author Wouter Schakel
*/
public class TrafCODDemo2 extends OTSSimulationApplication
{
/** */
private static final long serialVersionUID = 20161118L;
/**
* Create a Trafcod demo.
* @param title String; the title of the Frame
* @param panel OTSAnimationPanel; the tabbed panel to display
* @param model TrafCODModel; the model
* @throws OTSDrawingException on animation error
*/
public TrafCODDemo2(final String title, final OTSAnimationPanel panel, final TrafCODModel model) throws OTSDrawingException
{
super(model, panel);
}
/**
* Main program.
* @param args String[]; the command line arguments (not used)
* @throws IOException ...
*/
public static void main(final String[] args) throws IOException
{
demo(true);
}
/**
* Open an URL, read it and store the contents in a string. Adapted from
* https://stackoverflow.com/questions/4328711/read-url-to-string-in-few-lines-of-java-code
* @param url URL; the URL
* @return String
* @throws IOException when reading the file fails
*/
public static String readStringFromURL(final URL url) throws IOException
{
try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.toString()))
{
scanner.useDelimiter("\\A");
return scanner.hasNext() ? scanner.next() : "";
}
}
/**
* Start the demo.
* @param exitOnClose boolean; when running stand-alone: true; when running as part of a demo: false
* @throws IOException when reading the file fails
*/
public static void demo(final boolean exitOnClose) throws IOException
{
try
{
OTSAnimator simulator = new OTSAnimator("TrafCODDemo2");
URL url = URLResource.getResource("/TrafCODDemo2/TrafCODDemo2.xml");
System.out.println("url is " + url);
String xml = readStringFromURL(url);
final TrafCODModel trafcodModel = new TrafCODModel(simulator, "TrafCODModel", "TrafCOD demonstration Model", xml);
simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0), trafcodModel);
OTSAnimationPanel animationPanel = new OTSAnimationPanel(trafcodModel.getNetwork().getExtent(),
new Dimension(800, 600), simulator, trafcodModel, DEFAULT_COLORER, trafcodModel.getNetwork());
TrafCODDemo2 app = new TrafCODDemo2("TrafCOD demo complex crossing", animationPanel, trafcodModel);
app.setExitOnClose(exitOnClose);
}
catch (SimRuntimeException | NamingException | RemoteException | OTSDrawingException | DSOLException exception)
{
exception.printStackTrace();
}
}
/**
* Add tabs with trafCOD status display.
*/
@Override
protected final void addTabs()
{
OTSAnimationPanel animationPanel = getAnimationPanel();
if (null == animationPanel)
{
return;
}
ImmutableMap invisibleObjectMap = getModel().getNetwork().getInvisibleObjectMap();
for (InvisibleObjectInterface ioi : invisibleObjectMap.values())
{
if (ioi instanceof TrafCOD)
{
TrafCOD trafCOD = (TrafCOD) ioi;
Container controllerDisplayPanel = trafCOD.getDisplayContainer();
if (null != controllerDisplayPanel)
{
JPanel wrapper = new JPanel(new BorderLayout());
wrapper.add(new JScrollPane(controllerDisplayPanel));
TabbedContentPane tabbedPane = animationPanel.getTabbedPane();
tabbedPane.addTab(tabbedPane.getTabCount() - 1, trafCOD.getId(), wrapper);
}
// trafCOD.addListener(this, TrafficController.TRAFFICCONTROL_CONTROLLER_EVALUATING);
trafCOD.addListener(getModel(), TrafficController.TRAFFICCONTROL_CONTROLLER_WARNING);
trafCOD.addListener(getModel(), TrafficController.TRAFFICCONTROL_CONFLICT_GROUP_CHANGED);
trafCOD.addListener(getModel(), TrafficController.TRAFFICCONTROL_STATE_CHANGED);
trafCOD.addListener(getModel(), TrafficController.TRAFFICCONTROL_VARIABLE_CREATED);
trafCOD.addListener(getModel(), TrafficController.TRAFFICCONTROL_TRACED_VARIABLE_UPDATED);
}
}
}
/**
* The simulation model.
*/
public static class TrafCODModel extends AbstractOTSModel implements EventListenerInterface
{
/** */
private static final long serialVersionUID = 20161020L;
/** The network. */
private OTSRoadNetwork network;
/** The XML. */
private final String xml;
/**
* @param simulator OTSSimulatorInterface; the simulator
* @param shortName String; name of the model
* @param description String; description of the model
* @param xml String; the XML string
*/
public TrafCODModel(final OTSSimulatorInterface simulator, final String shortName, final String description,
final String xml)
{
super(simulator, shortName, description);
this.xml = xml;
}
/** {@inheritDoc} */
@Override
public void constructModel() throws SimRuntimeException
{
try
{
this.network = new OTSRoadNetwork(getShortName(), true, getSimulator());
OTS ots = XmlNetworkLaneParser.parseXML(new ByteArrayInputStream(this.xml.getBytes(StandardCharsets.UTF_8)));
XmlNetworkLaneParser.build(ots, this.network, false);
}
catch (Exception exception)
{
exception.printStackTrace();
}
}
/** {@inheritDoc} */
@Override
public final OTSRoadNetwork getNetwork()
{
return this.network;
}
/** {@inheritDoc} */
@Override
public void notify(final EventInterface event) throws RemoteException
{
EventTypeInterface type = event.getType();
Object[] payload = (Object[]) event.getContent();
if (TrafficController.TRAFFICCONTROL_CONTROLLER_EVALUATING.equals(type))
{
// System.out.println("Evaluation starts at " + getSimulator().getSimulatorTime());
return;
}
else if (TrafficController.TRAFFICCONTROL_CONFLICT_GROUP_CHANGED.equals(type))
{
CategoryLogger.always().info("Conflict group changed from {} to {}", (String) payload[1], (String) payload[2]);
}
else if (TrafficController.TRAFFICCONTROL_TRACED_VARIABLE_UPDATED.equals(type))
{
CategoryLogger.always().info("Variable changed %s <- %d %s", payload[1], payload[4], payload[5]);
}
else if (TrafficController.TRAFFICCONTROL_CONTROLLER_WARNING.equals(type))
{
CategoryLogger.always().info("Warning " + payload[1]);
}
else
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("TrafCODDemo received event of type " + event.getType() + ", payload [");
String separator = "";
for (Object o : payload)
{
stringBuilder.append(separator + o);
separator = ",";
}
stringBuilder.append("]");
CategoryLogger.always().info(stringBuilder.toString());
}
}
/** {@inheritDoc} */
@Override
public Serializable getSourceId()
{
return "TrafCODModel";
}
/** {@inheritDoc} */
@Override
public String toString()
{
return "TrafCODModel [network=" + network.getId() + "]";
}
}
}