package de.tud.kom.p2psim.impl.topology.movement.modularosm.movementIconVisualisation;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModelViz;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tudarmstadt.maki.simonstrator.api.*;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Visualises the different nodes as icons instead of these lame dots.
* The icons are configured entirely in the config files. To use this visualisation
* the first thing to do is specify this {@link ModularMovementIconVis} as visualisation for
* your modular movement model. To add icons to the visualisation the class {@link IconMapping} is used within the tags.
* You have two tags available for different kind of icons:
*
* 1. Class icons: These icons are used dependent on the class of the components the host includes. You can
* add a class icon by using the <ClassIcon> tag you config and setting the fully qualified classname
* of you components as object. If a host has multiple components with different specified icons, the first one will be used.
*
* 2. State icons: These icons are used dependent on the state of a host and take precedence over the class icons. You
* can add them via the <StateIcon> tag. The object should be a String representing the state. When
* using these types of icons, you need to set a {@link StateSelector} for this class in the config.
*
* For example usage, see the movement_social.xml config for the resourceAllocation overlay.
*
* @author Clemens Krug
*/
public class ModularMovementIconVis extends ModularMovementModelViz implements EventHandler
{
private HashMap pathMap;
private HashMap classIconMap;
private HashMap stateMap;
private HashMap stateIconMap;
private StateSelector stateSelector;
private boolean init = false;
public ModularMovementIconVis()
{
init();
pathMap = new HashMap<>();
classIconMap = new HashMap<>();
stateMap = new HashMap<>();
stateIconMap = new HashMap<>();
// scheduling initalization!
de.tudarmstadt.maki.simonstrator.api.Event.scheduleImmediately(this, null, 0);
}
private void initialize()
{
assert !init : "ModularMovementIconVis: Was already initialized!";
VisualizationTopologyView.VisualizationInjector.getTopologyView().setShowNodes(false);
for (Map.Entry e : pathMap.entrySet())
{
try
{
Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST);
classIconMap.put(e.getKey(), icon);
} catch (IOException ioe)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue());
}
}
for (Map.Entry e : stateMap.entrySet())
{
assert stateSelector != null : "There must be a state selector specified when using state icons!";
try
{
Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST);
stateIconMap.put(e.getKey(), icon);
} catch (IOException ioe)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue());
}
}
init = true;
}
@Override
public void paint(Graphics g)
{
super.paintSuper(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (showAttractionPoints)
{
super.drawAttractionPoints(g2);
}
if (showNodePositions)
{
for (SimLocationActuator comp : movementModel
.getAllLocationActuators())
{
drawNodePosition(g2, comp);
}
}
}
@Override
protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp)
{
boolean iconNotFound = true;
Host host = comp.getHost();
Point2D pt = comp.getRealPosition().asPoint();
pt = new Point2D.Double(VisualizationTopologyView.VisualizationInjector.scaleValue(pt.getX()), VisualizationTopologyView.VisualizationInjector.scaleValue(pt.getY()));
g2.setColor(Color.GRAY);
// Check if the component has a specified state, as this would have precedence over the classIcon.
if (stateSelector != null)
{
String state = stateSelector.getState(comp);
if (stateIconMap.containsKey(state))
{
Image icon = stateIconMap.get(state);
int width = icon.getWidth(null);
int height = icon.getHeight(null);
g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null);
return;
}
}
// If not, check if there's a class icon available
for (Map.Entry e : classIconMap.entrySet())
{
try
{
host.getComponent(e.getKey());
Image icon = e.getValue();
int width = icon.getWidth(null);
int height = icon.getHeight(null);
g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null);
iconNotFound = false;
break;
} catch (ComponentNotAvailableException nae)
{
iconNotFound = true;
}
}
// If not, use standard visualisation
if (iconNotFound) super.drawNodePosition(g2, comp);
}
@Override
public void eventOccurred(Object content, int type)
{
if (type == 0)
{
initialize();
}
}
public void setClassIcon(IconMapping classIcon)
{
try
{
pathMap.put(Class.forName(classIcon.getObject()), classIcon.getIconpath());
} catch (ClassNotFoundException e)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Class %s not found!", classIcon.getObject());
}
}
public void setStateIcon(IconMapping stateIcon)
{
stateMap.put(stateIcon.getObject(), stateIcon.getIconpath());
}
public void setStateSelector(StateSelector selector)
{
this.stateSelector = selector;
}
}