package ui.model; import java.awt.Color; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.swing.JTable; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import TypeAdapter.AbstractCpsObjectAdapter; import TypeAdapter.ColorAdapter; import TypeAdapter.PairAdapter; import TypeAdapter.PositionAdapter; import classes.AbstractCanvasObject; import classes.Category; import classes.Edge; import classes.GroupNode; import classes.Holon; import classes.HolonElement; import classes.HolonObject; import classes.HolonSwitch; import classes.Node; import classes.Pair; import classes.Position; import interfaces.GraphListener; import interfaces.ObjectListener; import ui.view.DefaulTable; import ui.view.PropertyTable; /** * The Class Model is the class where everything is saved. All changes made to * the Data is managed via a controller. * * @author Gruppe14 */ public class Model { private static final int GRAPH_ITERATIONS = 100; // Global Variables private static int sCALE = 50; // Picture Scale private static int sCALEdIV2 = sCALE / 2; public String[] colNames = {"Field", "Information"}; // Canvas Attributes private String imgPath = ""; private int backgroundMode = 0; private int backgroundWidth = 0; private int backgroundHeight = 0; private int canvasX = 3000; private int canvasY = 3000; private int curIteration = 0; private HolonElement selectedHolonElement; private Edge selectedEdge; private ArrayList selectedObjects = new ArrayList<>(); private ArrayList clipboardObjects = new ArrayList<>(); private HashMap> eleToDelete; // Capacity for Edge private float maxCapacity; // Table for HolonElements --> all cells are editable private JTable tableHolonElement; /** Table for the properties of HolonObjects, Edges etc */ private JTable propertyTable; private ArrayList graphListeners = new ArrayList(); // Iteration Speed private int timerSpeed = 1000; private int selectedID = 0; // number of the current autosave private int autoSaveNr = -1; // number of max simultaneous autosaves private int numberOfSaves = 35; /** whether the supplyBars should be shown or not */ private boolean showSupplyBars = true; //TODO: private int iterations=100; /** * All implemented FairnessModels:
* {@link FairnessModel#MininumDemandFirst}
* {@link FairnessModel#AllEqual} */ public enum FairnessModel{ /** * One Element of each HolonObject will be powered first, starting with the * smallest Demand. If ale HolonObjects have an active Element, the * simulation will try to fully supply as many HolonObjects as possible. */ MininumDemandFirst, /** * All HolonObjects will receive the same amount of energy. */ AllEqual } /** the Fairness model in use */ private FairnessModel fairnessModel = FairnessModel.MininumDemandFirst; /* * Array of all categories in the model. It is set by default with the * categories ENERGY, BUILDINGS and COMPONENTS */ private ArrayList categories; /* * Array of all CpsObjects in our canvas. It is set by default as an empty * list. */ private ArrayList objectsOnCanvas; private HashMap cgIdx; private HashMap cvsObjIdx; /* * Array of all CpsObjects in our canvas. It is set by default as an empty * list. */ private ArrayList edgesOnCanvas; private ArrayList holonObjectsOnCanvas = new ArrayList(); private ArrayList nodesOnCanvas= new ArrayList(); private ArrayList switchsOnCanvas= new ArrayList(); private List objectListeners; private PropertyTable tableModelHolonElementMulti; private PropertyTable tableModelHolonElementSingle; private DefaulTable tableModelProperties; private HashMap hashcodeMap = new HashMap<>(); private Holon stateHolon = new Holon("All Holons", this); private Map holonsByID = new HashMap(); private Gson gson; /** * Constructor for the model. It initializes the categories and * objectsOnCanvas by default values. Listeners are also initialized by * default values. */ public Model() { setCategories(new ArrayList<>()); setObjectsOnCanvas(new ArrayList<>()); setEdgesOnCanvas(new ArrayList<>()); setObjectListeners(new LinkedList<>()); setCgIdx(new HashMap<>()); setCvsObjIdx(new HashMap<>()); setClipboradObjects(new ArrayList<>()); setEleToDelete(new HashMap<>()); setSingleTable(new PropertyTable()); setMultiTable(new PropertyTable()); setPropertyTable(new DefaulTable(1000, colNames.length)); getPropertyTable().setColumnIdentifiers(colNames); setTableHolonElement(new JTable()); initGson(); this.holonsByID.put(stateHolon.getUniqueID(), stateHolon); } /** * Returns all Categories. * * @return the categories */ public ArrayList getCategories() { return categories; } /** * Sets all Categories. * * @param categories the categories to set */ public void setCategories(ArrayList categories) { this.categories = categories; } /** * Transform the Arraylist of categories into a string of all objectName * with a separation (',') between each name. * * @return String of all names separeted by ',' */ public String toStringCat() { String text = ""; for (int i = 0; i < categories.size(); i++) { if (text.equals("")) { text = categories.get(i).getName(); } else { text = text + ", " + categories.get(i).getName(); } } return text; } /** * Returns all Objects on the Canvas. * * @return the objectsOnCanvas */ public ArrayList getObjectsOnCanvas() { return objectsOnCanvas; } /** * Sets all Objects on the Canvas. * * @param objectsOnCanvas the objectsOnCanvas to set */ public void setObjectsOnCanvas(ArrayList objectsOnCanvas) { this.objectsOnCanvas = objectsOnCanvas; } /** * Get all Edges on the Canvas. * * @return the edgesOnCanvas */ public ArrayList getEdgesOnCanvas() { return edgesOnCanvas; } /** * Sets the edges on the Canvas. * * @param arrayList the edgesOnCanvas to set */ public void setEdgesOnCanvas(ArrayList arrayList) { this.edgesOnCanvas = arrayList; } /** * Adds an Edge to The Canvas. * * @param edge the edgesOnCanvas to add */ public void addEdgeOnCanvas(Edge edge) { this.edgesOnCanvas.add(edge); } /** * Remove an edge from the Canvas. * * @param edge the edge to remove */ public void removeEdgesOnCanvas(Edge edge) { this.edgesOnCanvas.remove(edge); } /** * Returns the ObjectListener. * * @return the objectListeners */ public List getObjectListeners() { return objectListeners; } /** * Sets the ObjectListener. * * @param linkedList the objectListeners to set */ public void setObjectListeners(LinkedList linkedList) { this.objectListeners = linkedList; } /** * Returns the ID of the selected Object 0 = no Object is selected. * * @return ID */ public int getSelectedObjectID() { return selectedID; } /** * Set the ID of the selected Object 0 = no Object is selected. * * @param id the ID */ public void setSelectedObjectID(int id) { this.selectedID = id; } /** * Returns all selected Objects on the Canvas. * * @return The selected Objects */ public ArrayList getSelectedCpsObjects() { return selectedObjects; } /** * Returns all selected Objects on the Canvas. * * @return The selected Objects */ public void setSelectedCpsObjects(ArrayList arr) { this.selectedObjects = arr; } /** * Returns the Selected Holon Element. * * @return selected Holon Element */ public HolonElement getSelectedHolonElement() { return selectedHolonElement; } /** * Sets the Selecte HolonElement. * * @param selectedHolonElement that is Selected */ public void setSelectedHolonElement(HolonElement selectedHolonElement) { this.selectedHolonElement = selectedHolonElement; } /** * Returns the sCale (Scale for the Images). * * @return sCALE */ public int getScale() { return sCALE; } public Holon getStateHolon() { return stateHolon; } /** * Sets the Image Scale. * * @param scale for the image */ public void setScale(int scale) { sCALE = scale; if ((sCALE & 1) == 0) sCALEdIV2 = sCALE / 2; else sCALEdIV2 = (sCALE + 1) / 2; } /** * Returns sCALEdIV2 (The Scale divided by 2). * * @return sCALEdIV2 */ public int getScaleDiv2() { return sCALEdIV2; } /** * Returns the maximum ITERATIONS. * * @return ITERATIONS */ public int getIterations() { return iterations; } private void notifyGraphListeners() { for (GraphListener gl : graphListeners) { gl.repaintTree(); } } /** * Returns cURiTERATION. * * @return cURiTERATION */ public int getCurIteration() { return curIteration; } /** * sets the current Iteration. * * @param curIT the current Iteration */ public void setCurIteration(int curIT) { this.curIteration = curIT; notifyGraphListeners(); } /** * Returns the selected Edge. * * @return selectedEdge */ public Edge getSelectedEdge() { return selectedEdge; } /** * Set the selected Edge. * * @param edge that is selected */ public void setSelectedEdge(Edge edge) { this.selectedEdge = edge; } /** * Returns the Categorie Index. * * @return the cgIdx */ public HashMap getCgIdx() { return cgIdx; } /** * Sets the Categorie Index. * * @param cgIdx the cgIdx to set */ public void setCgIdx(HashMap cgIdx) { this.cgIdx = cgIdx; } /** * Returns the CanvasObject Index. * * @return the cvsObjIdx */ public HashMap getCvsObjIdx() { return cvsObjIdx; } /** * Sets the CanvasObject Index. * * @param cvsObjIdx the cvsObjIdx to set */ public void setCvsObjIdx(HashMap cvsObjIdx) { this.cvsObjIdx = cvsObjIdx; } /** * Returns the auto save Number. * * @return the auto save Number */ public int getAutoSaveNr() { return autoSaveNr; } /** * Sets the auto save Number. * * @param autoSaveNr the auto save number */ public void setAutoSaveNr(int autoSaveNr) { this.autoSaveNr = autoSaveNr; } /** * Returns the Number of Saves. * * @return the numberOfSaves */ public int getNumberOfSaves() { return numberOfSaves; } /** * Set the Number of Saves. * * @param numberOfSaves the numberOfSaves to set */ public void setNumberOfSaves(int numberOfSaves) { this.numberOfSaves = numberOfSaves; } /** * Returns all Objects in the Clipboard. * * @return Objects in the Clipboard */ public ArrayList getClipboradObjects() { return clipboardObjects; } /** * Sets the ClipboardObjects. * * @param c Array of Objects */ public void setClipboradObjects(ArrayList c) { this.clipboardObjects = c; } /** * @return the maxCapacity */ public float getMaxCapacity() { return maxCapacity; } /** * @param maxCapacity the maxCapacity to set */ public void setMaxCapacity(float maxCapacity) { this.maxCapacity = maxCapacity; } /** * get the Interval in ms between each Iteration. * * @return timerSpeed speed for the Iterations */ public int getTimerSpeed() { return this.timerSpeed; } /** * Sets the Interval in ms between each Iteration. * * @param t speed for the Iterations */ public void setTimerSpeed(int t) { this.timerSpeed = t; } /** * Get Canvas X Size. * * @return the cANVAS_X */ public int getCanvasX() { return canvasX; } /** * Set Canvas X Size. * * @param canvasX the cANVAS_X to set */ public void setCanvasX(int canvasX) { this.canvasX = canvasX; } /** * get Canvas Y size. * * @return the cANVAS_Y */ public int getCanvasY() { return canvasY; } /** * Set Canvas Y size. * * @param canvasY the cANVAS_Y to set */ public void setCanvasY(int canvasY) { this.canvasY = canvasY; } public HashMap> getEleToDelete() { return this.eleToDelete; } public void setEleToDelete(HashMap> theHash) { this.eleToDelete = theHash; } public PropertyTable getSingleTable() { return this.tableModelHolonElementSingle; } public void setSingleTable(PropertyTable pt) { this.tableModelHolonElementSingle = pt; } public PropertyTable getMultiTable() { return this.tableModelHolonElementMulti; } public void setMultiTable(PropertyTable pt) { this.tableModelHolonElementMulti = pt; } public DefaulTable getPropertyTable() { return this.tableModelProperties; } public void setPropertyTable(DefaulTable pt) { this.tableModelProperties = pt; } public JTable getTableHolonElement() { return tableHolonElement; } public void setTableHolonElement(JTable tableHolonElement) { this.tableHolonElement = tableHolonElement; } /** * @return the tableProperties */ public JTable getTableProperties() { return propertyTable; } /** * @return the tableProperties */ public void setTableProperties(JTable propertyTable) { this.propertyTable = propertyTable; } public List getAllHolonElemnts() { return getAllHolonObjectsOnCanvas().stream().flatMap(hO -> hO.getElements().stream()).collect(Collectors.toList()); } public ArrayList getAllHolonObjectsOnCanvas(){ ArrayList objectToReturn = new ArrayList(); getAllHolonObjectsRecursive(objectToReturn, getObjectsOnCanvas()); return objectToReturn; } private void getAllHolonObjectsRecursive(ArrayList addObjectsToThisList, List listOfObjectsToSearch){ for(AbstractCanvasObject aCps : listOfObjectsToSearch) { if(aCps instanceof HolonObject) { addObjectsToThisList.add((HolonObject) aCps); }else if(aCps instanceof GroupNode){ getAllHolonObjectsRecursive(addObjectsToThisList, ((GroupNode)aCps).getNodes()); } } } /** * get all Switches */ public ArrayList getAllSwitches() { ArrayList switches = new ArrayList<>(); for (AbstractCanvasObject obj : getObjectsOnCanvas()) { if (obj instanceof HolonSwitch) { switches.add((HolonSwitch) obj); } else if (obj instanceof GroupNode) { getSwitchesRec(((GroupNode) obj).getNodes(), switches); } } return switches; } /** * get the Amount of Switches help function * * @param objects objects * @param switches List of switches */ private ArrayList getSwitchesRec(ArrayList objects, ArrayList switches) { for (AbstractCanvasObject obj : objects) { if (obj instanceof HolonSwitch) { switches.add((HolonSwitch) obj); } else if (obj instanceof GroupNode) { getSwitchesRec(((GroupNode) obj).getNodes(), switches); } } return switches; } /** * Returns the Path for the background Image of the Canvas. * * @return imgPath the Path */ public String getCanvasImagePath() { return imgPath; } /** * Set the Path for the background Image of the Canvas. * * @param path the Path */ public void setCanvasImagePath(String path) { imgPath = path; } /** * Returns the mode for the background Image of the Canvas. *

* 0 take size of the Image 1 stretch the Image 2 Custom Image size * * @return backgroundMode the mode */ public int getCanvasImageMode() { return backgroundMode; } /** * Set the mode for the background Image of the Canvas. *

* 0 take size of the Image, 1 stretch the Image, 2 Custom Image size * * @param mode the backgroundMode */ public void setCanvasImageMode(int mode) { backgroundMode = mode; } /** * Returns the Custom width of the background Image of the Canvas. * * @return backgroundWidth the Width */ public int getCanvasImageWidth() { return backgroundWidth; } /** * Set the Custom width of the background Image of the Canvas. * * @param width the Width */ public void setCanvasImageWidth(int width) { backgroundWidth = width; } /** * Returns the Custom height of the background Image of the Canvas. * * @return backgroundHeight the height */ public int getCanvasImageHeight() { return backgroundHeight; } /** * Set the Custom height of the background Image of the Canvas. * * @param height the height */ public void setCanvasImageHeight(int height) { backgroundHeight = height; } /** * @return true if SupplyBars should be shown */ public boolean getShowSupplyBars() { return showSupplyBars; } /** * @param showSupplyBars true if the SupplyBars should be shown */ public void setShowSupplyBars(boolean showSupplyBars) { this.showSupplyBars = showSupplyBars; } /** * @param iterations the number of steps for this simulation */ public void setIterations(int iterations){ this.iterations=iterations; } /** * @return the fairnessModel */ public FairnessModel getFairnessModel() { return fairnessModel; } /** * @param fairnessModel the fairnessModel to set */ public void setFairnessModel(FairnessModel fairnessModel) { this.fairnessModel = fairnessModel; } public int getGraphIterations(){ return GRAPH_ITERATIONS; } /** * Initialize the Gson with wanted parameters */ private void initGson() { GsonBuilder builder = new GsonBuilder(); builder.serializeNulls(); builder.excludeFieldsWithoutExposeAnnotation(); builder.setPrettyPrinting(); builder.registerTypeAdapter(AbstractCanvasObject.class, new AbstractCpsObjectAdapter()); builder.registerTypeAdapter(Position.class, new PositionAdapter()); builder.registerTypeAdapter(Color.class, new ColorAdapter()); builder.registerTypeAdapter(Pair.class, new PairAdapter()); // use the builder and make a instance of the Gson this.setGson(builder.create()); } /** * @return the gson */ public Gson getGson() { return gson; } /** * @param gson the gson to set */ public void setGson(Gson gson) { this.gson = gson; } /** * @return the hashcodeMap */ public HashMap getHashcodeMap() { return hashcodeMap; } /** * @param hashcodeMap the hashcodeMap to set */ public void setHashcodeMap(HashMap hashcodeMap) { this.hashcodeMap = hashcodeMap; } public ArrayList getSwitchsOnCanvas() { return switchsOnCanvas; } public void setSwitchsOnCanvas(ArrayList switchsOnCanvas) { this.switchsOnCanvas = switchsOnCanvas; } public ArrayList getNodesOnCanvas() { return nodesOnCanvas; } public void setNodesOnCanvas(ArrayList nodesOnCanvas) { this.nodesOnCanvas = nodesOnCanvas; } public ArrayList getHolonObjectsOnCanvas() { return holonObjectsOnCanvas; } public void setHolonObjectsOnCanvas(ArrayList holonObjectsOnCanvas) { this.holonObjectsOnCanvas = holonObjectsOnCanvas; } public void defineLists() { switchsOnCanvas.clear(); nodesOnCanvas.clear(); holonObjectsOnCanvas.clear(); for(AbstractCanvasObject aCps : this.objectsOnCanvas) { if(aCps instanceof HolonObject)holonObjectsOnCanvas.add((HolonObject) aCps); else if(aCps instanceof Node)nodesOnCanvas.add((Node) aCps); else if(aCps instanceof HolonSwitch)switchsOnCanvas.add((HolonSwitch) aCps); } } public Map getHolonsByID() { return holonsByID; } /** * get all edges that connect objects inside the holarchy * requires that all objects are connected * energy always takes the shortest path between two objects -> all shortest paths are included * all traversed objects are whether a switch or holon that is part of the holarchy * group nodes not supported * @param from * @param to * @return */ public ArrayList getAllEdgesInHolarchy(ArrayList holarchy){ if(holarchy.size() < 2) { return new ArrayList(); } //construct subgraph that contains all objects of the holarchy and all switches from the canvas ArrayList vertices = new ArrayList(); for(AbstractCanvasObject aco : this.objectsOnCanvas) { if(aco instanceof HolonSwitch || aco instanceof Node || (aco instanceof HolonObject && holarchy.contains(aco)) ) { vertices.add(aco); } } ArrayList edges = new ArrayList(); for(Edge e : this.edgesOnCanvas) { AbstractCanvasObject a = e.getA(); AbstractCanvasObject b = e.getB(); if(vertices.contains(a) && vertices.contains(b)) { edges.add(e); } } //find shortest paths between the objects ArrayList es = new ArrayList(); if(holarchy.size() < 2) { return es; } for(int i=0; i> getShortestPathToHolarchy(MinimumModel minModel, MinimumModel minModel2, ArrayList holarchy){ ArrayList objects = new ArrayList(); objects.addAll(minModel.getHolonObjectList()); objects.addAll(minModel.getNodeList()); objects.addAll(minModel.getSwitchList()); ArrayList objects2 = new ArrayList(); objects2.addAll(minModel2.getHolonObjectList()); objects2.addAll(minModel2.getNodeList()); objects2.addAll(minModel2.getSwitchList()); HashMap> map = new HashMap>(); for(AbstractCanvasObject aco : objects) { for(AbstractCanvasObject aco2 : objects2) { ArrayList edges = dijkstra(aco, aco2, holarchy, this.objectsOnCanvas, this.edgesOnCanvas); float dist = 0; for(Edge e : edges) { dist += e.getLength(); } map.put(dist, edges); } } return map; } public ArrayList dijkstra(AbstractCanvasObject a, AbstractCanvasObject b, ArrayList holarchy, ArrayList vertices, ArrayList edges) { ArrayList es = new ArrayList(); HashSet visited = new HashSet(); ArrayList unvisited = new ArrayList(); HashMap dist = new HashMap(); for(AbstractCanvasObject aco : vertices) { unvisited.add(aco); dist.put(aco, Float.MAX_VALUE); } dist.put(a, 0f); HashMap pre = new HashMap(); AbstractCanvasObject current = a; visited.add(a); unvisited.remove(a); while(!unvisited.isEmpty()) { if(b.equals(current)) break; float currDist = dist.get(current); for(AbstractCanvasObject aco : current.getConnectedObjects()) { if(visited.contains(aco) || (aco instanceof HolonObject && !holarchy.contains(aco))) { continue; } float newDist = currDist + getEdgeBetweenObjects(current, aco, this.edgesOnCanvas).getLength(); if(newDist < dist.get(aco)) { dist.put(aco, newDist); pre.put(aco, current); } } AbstractCanvasObject next = getMinInMap(dist, unvisited); visited.add(current); unvisited.remove(current); current = next; } //trace back path current = b; while(!current.equals(a)) { AbstractCanvasObject next = pre.get(current); es.add(getEdgeBetweenObjects(current, next, edges)); current = next; } return es; } public AbstractCanvasObject getMinInMap(HashMap map, ArrayList unvisited) { AbstractCanvasObject min = null; float m = Float.MAX_VALUE; for(AbstractCanvasObject aco : map.keySet()) { if(unvisited.contains(aco) && map.get(aco) < m) { // System.out.println("new min "+min); m = map.get(aco); min = aco; } } return min; } public Edge getEdgeBetweenObjects(AbstractCanvasObject a, AbstractCanvasObject b, ArrayList edges) { for(Edge e : edges) { AbstractCanvasObject a2 = e.getA(); AbstractCanvasObject b2 = e.getB(); if( (a.equals(a2) && b.equals(b2)) || (a.equals(b2) && b.equals(a2)) ) { return e; } } return null; } public boolean checkHolonObjectsAreConnected(Holon a, Holon b) { if(a.equals(b)) { return false; } HashSet visited = new HashSet(); ArrayList objects = new ArrayList(); objects.addAll(a.getAllHolonObjects()); objects.addAll(b.getAllHolonObjects()); ArrayList toVisit = new ArrayList(); toVisit.add(a.getHolonObject()); while(!toVisit.isEmpty()) { AbstractCanvasObject aco = toVisit.remove(0); for(AbstractCanvasObject aco2 : aco.getConnectedObjects()) { if(visited.contains(aco2) || (aco2 instanceof HolonSwitch && !((HolonSwitch)aco2).isClosed()) ) { continue; } if(aco2 instanceof HolonObject && aco2.equals(b.getHolonObject())) { return true; } if( aco2 instanceof HolonSwitch || aco2 instanceof Node || (aco2 instanceof HolonObject && objects.contains(aco2)) ) { toVisit.add(aco2); } } visited.add(aco); } return false; } }