package nl.tudelft.bw4t.server.model; import java.util.HashSet; import java.util.Set; import org.jgrapht.WeightedGraph; import org.jgrapht.graph.DefaultWeightedEdge; import nl.tudelft.bw4t.map.NewMap; import nl.tudelft.bw4t.server.model.zone.Zone; import nl.tudelft.bw4t.server.repast.MapLoader; import nl.tudelft.bw4t.server.util.GraphHelper; import repast.simphony.context.Context; import repast.simphony.space.continuous.ContinuousSpace; import repast.simphony.space.continuous.NdPoint; import repast.simphony.space.grid.Grid; import repast.simphony.util.collections.IndexedIterable; /** * A data structure containing both the map and the repast context that is active within the current server. */ public class BW4TServerMap { // [start] Constructors /** * Create a new server map with the given {@link NewMap}. * * @param map * the map */ public BW4TServerMap(NewMap map) { this.setMap(map); } /** * Create a new server map with the given {@link NewMap} and repast {@link Context}. * * @param map * the map * @param context * the repast context */ public BW4TServerMap(NewMap map, Context<Object> context) { this(map); this.setContext(context); } // [end] // [start] Map and Context private Context<Object> context; private NewMap map; public NewMap getMap() { return map; } /** * @return is there a map currently present */ public boolean hasMap() { return map != null; } /** * Set the new {@link NewMap} for this server map, will notify attached listeners. * * @param map * the new {@link NewMap} */ public void setMap(NewMap map) { if (this.map == map) { return; } this.map = map; notifyMapChange(); } public Context<Object> getContext() { return context; } /** * @return is there a repast context currently present */ public boolean hasContext() { return context != null; } /** * Set a new repast {@link Context} for this server map, will notify attached listeners. * * @param context * the new repast {@link Context} */ public void setContext(Context<Object> context) { if (this.context == context) { return; } this.context = context; this.continuousSpace = null; this.gridSpace = null; this.graph = null; notifyContextChange(); } // [end] // [start] Repast Context derived functions private ContinuousSpace<Object> continuousSpace; private Grid<Object> gridSpace; private WeightedGraph<NdPoint, DefaultWeightedEdge> graph; /** * Get the contiuous space for the current repast {@link Context}. * * @return the {@link ContinuousSpace} */ @SuppressWarnings("unchecked") public ContinuousSpace<Object> getContinuousSpace() { if (continuousSpace == null && hasContext()) { continuousSpace = (ContinuousSpace<Object>) getContext().getProjection(MapLoader.PROJECTION_ID); } return continuousSpace; } /** * Get the grid space for the current repast {@link Context}. * * @return the {@link Grid} */ @SuppressWarnings("unchecked") public Grid<Object> getGridSpace() { if (gridSpace == null && hasContext()) { gridSpace = (Grid<Object>) getContext().getProjection(MapLoader.GRID_PROJECTION_ID); } return gridSpace; } /** * Get the graph of all connected zones in the map. * * @return the graph */ public WeightedGraph<NdPoint, DefaultWeightedEdge> getZoneGraph() { if (graph == null && hasContext()) { graph = GraphHelper.generateZoneGraph(getObjectsFromContext(Zone.class)); } return graph; } /** * Get a set of objects of type clazz from the repast {@link Context}. * * @see Context#getObjects(Class) * @param clazz * the class of the objects to be found * @param <T> * the type of object to be found * @return a {@link Set} of the found objects */ @SuppressWarnings("unchecked") public <T> Set<T> getObjectsFromContext(Class<T> clazz) { if (!hasContext()) { return new HashSet<T>(0); } IndexedIterable<Object> objects = getContext().getObjects(clazz); Set<T> elements = new HashSet<>(objects.size()); for (Object t : objects) { elements.add((T) t); } return elements; } // [end] // [start] Change Listeners private Set<BW4TServerMapListerner> listeners = new HashSet<>(); /** * Attach the given object so it get notified whenever there are changes to the {@link NewMap} or repast * {@link Context}. * * @param e * the object to be notified */ public void attachChangeListener(BW4TServerMapListerner e) { listeners.add(e); } /** * Remove the given object so it does not get notified of changes any more. * * @param o * the object to remove */ public void removeChangeListener(Object o) { listeners.remove(o); } /** * Notify all attached listeners that the {@link NewMap} changed. */ private void notifyMapChange() { for (BW4TServerMapListerner listener : listeners) { listener.mapChange(this); } } /** * Notify all attached listeners that the repast {@link Context} changed. */ private void notifyContextChange() { for (BW4TServerMapListerner listener : listeners) { listener.contextChange(this); } } // [end] }