package ui.controller; import java.awt.Point; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.stream.Collectors; import javax.swing.JFrame; import org.apache.commons.compress.archivers.ArchiveException; import com.google.gson.JsonParseException; import classes.AbstractCanvasObject; import classes.Category; import classes.Edge; import classes.GroupNode; import classes.HolonElement; import classes.HolonObject; import classes.Node; import ui.model.Model; import ui.model.Model.FairnessModel; import ui.view.CreateTemplatePopUp; import ui.view.GUI; import utility.Event; /** * The Class represents the controller in the model, controller view Pattern. * * @author Gruppe14 */ public class Control { private final MultiPurposeController multiPurposeController; private final CategoryController categoryController; private final ObjectController objectController; private final CanvasController canvasController; private final GlobalController globalController; private final SaveController saveController; private final LoadController loadController; private final AutoSaveController autoSaveController; private final NodeController nodeController; private final ClipboardController clipboardController; private final HolonCanvasController holonCanvasController; private Model model; private GUI gui; private SimulationManager simulationManager; private String autosaveDir = ""; private String categoryDir = ""; private String otherDir = ""; private String dimensionsFileName = "dimensions"; private int rand; public Event OnCategoryChanged = new Event(); /** * Constructor. * * @param model the Model */ public Control(Model model) { this.model = model; this.multiPurposeController = new MultiPurposeController(model); this.categoryController = new CategoryController(model, multiPurposeController, this); this.objectController = new ObjectController(model, multiPurposeController); this.canvasController = new CanvasController(model, multiPurposeController); this.globalController = new GlobalController(model); this.saveController = new SaveController(model); this.nodeController = new NodeController(model, canvasController, multiPurposeController); this.loadController = new LoadController(model, categoryController, canvasController, objectController, nodeController, multiPurposeController); this.simulationManager = new SimulationManager(model); this.autoSaveController = new AutoSaveController(model); this.clipboardController = new ClipboardController(model, saveController, loadController, canvasController, objectController, nodeController, multiPurposeController); this.holonCanvasController = new HolonCanvasController(model); autosaveDir = System.getProperty("user.home") + "/.config/HolonGUI/Autosave/"; categoryDir = System.getProperty("user.home") + "/.config/HolonGUI/Category/"; otherDir = System.getProperty("user.home") + "/.config/HolonGUI/Other/"; File autoSave = new File(autosaveDir); File category = new File(categoryDir); File other = new File(otherDir); // deleteDirectory(dest); autoSave.mkdirs(); category.mkdirs(); other.mkdirs(); createAutoRandom(); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Generate random number, so that every instance of the program has unique * save files */ private void createAutoRandom() { rand = (int) (Math.random() * 1000); while (new File(autosaveDir + rand + (autoSaveController.getAutoSaveNr())).exists()) { rand = (int) Math.random() * 1000; } } /** * Delete a Directory. * * @param path to delete */ public void deleteDirectory(File path) { if (path.exists()) { File[] files = path.listFiles(); for (File file : files) { if (file.isDirectory()) { deleteDirectory(file); } else { if (file.getName().contains("" + rand)) file.delete(); } } // path.delete(); } } /* Operations for searching */ /** * Search for Object by ID. * * @param id the id of the Object * @return the CpsObject */ public AbstractCanvasObject searchByID(int id) { return multiPurposeController.searchByID(id); } /** * Search for Object by ID in upperNode * * @param id the id of the Object * @return the CpsObject */ public AbstractCanvasObject searchByIDUpperNode(int id, GroupNode upperNode) { return multiPurposeController.searchByIDUpperNode(id, upperNode); } public AbstractCanvasObject searchTracked(int id) { return multiPurposeController.searchByID(id); } /** * Search for Object in a Category. * * @param category name of the Category * @param object Name of the Object * @return The Object */ public AbstractCanvasObject searchCategoryObject(String category, String object) { return multiPurposeController.searchCatObj(multiPurposeController.searchCat(category), object); } /** * search for category. * * @param cat name of the Category * @return the Category */ public Category searchCategory(String cat) { return multiPurposeController.searchCat(cat); } /* Operations for Categories and Objects */ /** * init default category and objects. * * @throws IOException */ public void resetCategorys() throws IOException { categoryController.initCategories(); objectController.initHolonElements(); saveCategory(); } /** * Adds New Category into Model. * * @param cat name of the new Category * @throws IOException */ public void addCategory(String cat) throws IOException { categoryController.addNewCategory(cat); saveCategory(); } /** * Gives all Category as String * @return a array of strings from all Categorys */ public String[] getCategoriesStrings() { return ((ArrayList) categoryController.getCategories().stream().map(c -> c.getName()).collect(Collectors.toList())).toArray(new String[categoryController.getCategories().size()]); } /** * Add new Holon Object to a Category. * * @param cat Category * @param obj New Object Name * @param ele Array of Elements * @param img the image Path * @throws IOException */ public void addObject(Category cat, String obj, ArrayList ele, String img) throws IOException { categoryController.addNewHolonObject(cat, obj, ele, img); saveCategory(); } /** * Add new Holon Switch to a Category. * * @param cat Category * @param obj New Object Name * @throws IOException */ public void addSwitch(Category cat, String obj) throws IOException { categoryController.addNewHolonSwitch(cat, obj, "/Images/switch-on.png"); saveCategory(); } /** * delete a given Category. * * @param cat the Category * @throws IOException */ public void deleteCategory(String cat) throws IOException { categoryController.deleteCategory(cat); saveCategory(); } /** * Delete an Object from a Category. * * @param cat the Category * @param obj the Object * @throws IOException */ public void delObjectCategory(String cat, String obj) throws IOException { categoryController.deleteObject(cat, obj); saveCategory(); } /** * deletes a selectedObject. * * @param obj Cpsobject */ public void deleteSelectedObject(AbstractCanvasObject obj) { objectController.deleteSelectedObject(obj); } /** * add an Object to selectedObject. * * @param obj AbstractCpsobject */ public void addSelectedObject(AbstractCanvasObject obj) { objectController.addSelectedObject(obj); } /* Operations for Canvas */ /** * Add a new Object. * * @param object the Object */ public void addObjectCanvas(AbstractCanvasObject object) { canvasController.addNewObject(object); calculateStateAndVisualForTimeStep(model.getCurIteration()); if (!(object instanceof Node)) { try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } } /** * Deletes an CpsObject on the Canvas and its connections. * * @param obj AbstractCpsObject * @param save */ public void deleteCanvasObject(AbstractCanvasObject obj, boolean save) { canvasController.deleteObjectOnCanvas(obj); if (obj instanceof GroupNode) { canvasController.bfsNodeCleaner((GroupNode) obj); } calculateStateAndVisualForCurrentTimeStep(); if (save) try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Replaces {@code toBeReplaced} by {@code by} on the canvas * @param toBeReplaced the object that will be replaced * @param by the object that will replace it */ public void replaceCanvasObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) { canvasController.replaceObjectOnCanvas(toBeReplaced, by); try { autoSave(); } catch (IOException e) { System.out.println("Error by Replacing "+toBeReplaced.toString() + " by " + by.toString()); e.printStackTrace(); } } /** * Add an edge to the Canvas. * * @param edge the edge */ public void addEdgeOnCanvas(Edge edge) { canvasController.addEdgeOnCanvas(edge); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Removes an Edge from the Canvas. * * @param edge the edge to remove */ public void removeEdgesOnCanvas(Edge edge) { canvasController.removeEdgesOnCanvas(edge); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Set the selected Edge. * * @param edge that is selected */ public void setSelecteEdge(Edge edge) { model.setSelectedEdge(edge); } /** * Returns the ID of the selected Object 0 = no Object is selected. * * @param id the ID of the selected Object */ public void setSelectedObjectID(int id) { objectController.setSelectedObjectID(id); } /* Operations for Objects and Elements */ /** * Add a new Element into a Object on the Canvas. * * @param objectId the Object ID * @param ele the Name of the Element * @param amount the Amount * @param energy the Energy * @param elementId the Element ID */ public void addElementCanvasObject(int objectId, String ele, int amount, float energy, int elementId) { objectController.addNewElementIntoCanvasObject(objectId, ele, amount, energy, elementId); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Add a new Element into a Object in Category. * * @param catName the Category * @param objName the Object * @param eleName the Element Name * @param amount the amount * @param energy the Energy */ public void addElementCategoryObject(String catName, String objName, String eleName, int amount, float energy) { objectController.addNewElementIntoCategoryObject(catName, objName, eleName, amount, energy); } /** * deletes a Element from a given Canvas Object. * * @param id the ID * @param elementid the Element ID */ public void deleteElementCanvas(int id, int elementid) { objectController.deleteElementInCanvas(id, elementid); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Returns SCALE. * * @return SCALE */ public int getScale() { return globalController.getScale(); } /** * Changes the value of SCALE and SCALEDIV2. * * @param s Scale */ public void setScale(int s) { globalController.setScale(s); } /** * Returns SCALE Divided by 2. * * @return SCALE Divided by 2 */ public int getScaleDiv2() { return globalController.getScaleDiv2(); } /** * sets the current Iteration. * * @param curit the current Iteration */ public void setCurIteration(int curit) { globalController.setCurIteration(curit); //getGui().getTimePanel().getTimeSlider().setValue(curit); } /** * Writes the current State of the Modelling into a JSON File which can be * loaded. * * @param path the Path * @throws IOException exception */ public void saveFile(String path) throws IOException, ArchiveException { saveController.writeSave(path); } /** * Reads the the Save File and load the state into the Model. * * @param path the Path * @throws IOException exception * @throws ArchiveException */ public void loadFile(String path) throws IOException, ArchiveException { loadController.readSave(path); saveCategory(); autoSave(); } /** * Reads the Json File from Autosave * * @param path * @throws IOException */ public void loadAutoSave(String path) throws IOException { loadController.readJson(path); } public ArrayList loadSavedWindowDimensionsIfExistent() { try { return loadController.readWindowDimensions(otherDir + dimensionsFileName); } catch (Exception e) { return new ArrayList<>(); } } /** * calculates the flow of the edges and the supply for objects for the * current Timestep. */ public void calculateStateAndVisualForCurrentTimeStep() { calculateStateAndVisualForTimeStep(model.getCurIteration()); } public void calculateStateOnlyForCurrentTimeStep() { simulationManager.calculateStateForTimeStep(model.getCurIteration(), false); } /** * calculates the flow of the edges and the supply for objects. * * @param x current Iteration */ public void calculateStateAndVisualForTimeStep(int x) { simulationManager.calculateStateForTimeStep(x, true); updateOutliner(); updateFlexWindow(); this.updateCanvas(); } /** * resets the whole State of the simulation including a reset of all Edges * to the default "is working" state */ public void resetSimulation() { simulationManager.resetFlexManager(); } /** * make an autosave. * * @throws IOException Exception */ public void autoSave() throws IOException { autoSaveController.increaseAutoSaveNr(); saveController.writeAutosave(autosaveDir + rand + autoSaveController.getAutoSaveNr()); if (autoSaveController.allowed()) { new File(autosaveDir + rand + (autoSaveController.getAutoSaveNr() - globalController.getNumbersOfSaves())) .delete(); } } /** * find all old auto save files (with a file-name, that does not contain the current rand) * * @return a list of files, that are not from the current run */ public ArrayList filterOldAutoSaveFiles() { File[] files = new File(autosaveDir).listFiles(); ArrayList oldAutoSaves = new ArrayList<>(); for (File file : files) { if (!file.getName().contains(String.valueOf(rand))) oldAutoSaves.add(file); } return oldAutoSaves; } /** * deletes the old autosave files */ public void deleteObsoleteAutoSaveFiles() { for (File file : filterOldAutoSaveFiles()) { file.delete(); } } public void saveCategory() throws IOException { saveController.writeCategory(categoryDir + "Category.json"); } public void savePosAndSizeOfWindow(int x, int y, int width, int height) throws IOException, ArchiveException { saveController.writeWindowStatus(otherDir + dimensionsFileName, x, y, width, height); } /** * Returns the undo save. * * @return the undo save */ public String getUndoSave() { autoSaveController.decreaseAutoSaveNr(); if (!new File(autosaveDir + rand + (autoSaveController.getAutoSaveNr())).exists()) { autoSaveController.increaseAutoSaveNr(); } return autosaveDir + rand + (autoSaveController.getAutoSaveNr()); } /** * Returns the redo save. * * @return the redo save */ public String getRedoSave() { autoSaveController.increaseAutoSaveNr(); if (!new File(autosaveDir + rand + (autoSaveController.getAutoSaveNr())).exists()) { autoSaveController.decreaseAutoSaveNr(); // if it still does not exist, try old autosaves if (!new File(autosaveDir + rand + (autoSaveController.getAutoSaveNr())).exists()) { ArrayList oldAutoSaves = filterOldAutoSaveFiles(); if (oldAutoSaves.size() > 0) { return autosaveDir + oldAutoSaves.get(oldAutoSaves.size() - 1).getName(); } } } return autosaveDir + rand + (autoSaveController.getAutoSaveNr()); } /** * Getter for Model. * * @return the Model */ public Model getModel() { return model; } /** * get the Simulation Manager. * * @return the Simulation Manager */ public SimulationManager getSimManager() { return simulationManager; } /** * Set the timerSpeed. * * @param t interval in ms */ public void setTimerSpeed(int t) { globalController.setTimerSpeed(t); } /** * Set the Canvas X Size. * * @param canvasX the cANVAS_X to set */ public void setCanvasX(int canvasX) { globalController.setCanvasX(canvasX); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Set the Canvas Y Size. * * @param canvasY the cANVAS_Y to set */ public void setCanvasY(int canvasY) { globalController.setCanvasY(canvasY); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } public void setMaxCapacity(float cap) { globalController.setMaxCapacity(cap); } // ========================== MANAGING TRACKED OBJECTS END ================ /** * Controlling Nodes of Nodes */ public void addUpperNode(String nodeName, GroupNode upperNode, ArrayList toGroup) { nodeController.doUpperNode(nodeName, upperNode, toGroup); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } public void ungroupGroupNode(GroupNode node, GroupNode upperNode) { nodeController.undoUpperNode(node, upperNode); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } public void addObjUpperNode(AbstractCanvasObject object, GroupNode upperNode) { nodeController.addObjectInUpperNode(object, upperNode, true); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } public void delObjUpperNode(AbstractCanvasObject object, GroupNode upperNode) { nodeController.deleteObjectInUpperNode(object, upperNode); if (object instanceof GroupNode) canvasController.bfsNodeCleaner((GroupNode) object); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * Replaces {@code toBePlaced} by {@code by} in {@code upperNode} * @param toBeReplaced * @param by * @param upperNode */ public void replaceObjUpperNode(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by, GroupNode upperNode) { nodeController.replaceObjectInUpperNode(toBeReplaced, by, upperNode); try { autoSave(); } catch (IOException e) { System.out.println("Error by Replacing "+toBeReplaced.toString() + " by " + by.toString() + " in UpperNode " + upperNode.toString()); e.printStackTrace(); } } /** * Get the number of HolonObjects in the given List * * @param list */ public int getNumberHolonObjects(ArrayList list) { return objectController.getNumberHolonObjects(list); } /** * Get the number of HolonObjects in the given List * * @param list */ public ArrayList getAllHolonObjects(ArrayList list) { return objectController.getAllHolonObjects(list); } /** * Copy all Selected Objects. */ public void copy(GroupNode upperNode) { clipboardController.copy(upperNode); } public void paste(GroupNode upperNode, Point point) throws JsonParseException, UnsupportedFlavorException, IOException { clipboardController.paste(upperNode, point); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } public void cut(GroupNode upperNode) { clipboardController.cut(upperNode); try { autoSave(); } catch (IOException e) { e.printStackTrace(); } } /** * creates a new Template for the given cps Object * @param cps Object, which should become a template * @param parentFrame */ public void createTemplate(HolonObject cps, JFrame parentFrame) { CreateTemplatePopUp t = new CreateTemplatePopUp(cps,model,parentFrame,this); t.setVisible(true); } public void getObjectsInDepth() { clipboardController.getObjectsInDepth(); } public float getTotalProduction(ArrayList arrayList) { return holonCanvasController.getTotalProduction(arrayList); } public float getTotalConsumption(ArrayList arrayList) { return holonCanvasController.getTotalConsumption(arrayList); } public int getTotalElements(ArrayList arrayList) { return holonCanvasController.getTotalElements(arrayList); } public int getTotalProducers(ArrayList arrayList) { return holonCanvasController.getTotalProducers(arrayList); } public int getActiveElements(ArrayList arrayList) { return holonCanvasController.getActiveElements(arrayList); } /** * Set the Background Image; * * @param imagePath Image Path * @param mode Image Mode * @param width Image custom width * @param height Image custom height */ public void setBackgroundImage(String imagePath, int mode, int width, int height) { canvasController.setBackgroundImage(imagePath, mode, width, height); } /** * Sets show * @param showSupplyBars wether the bars should be shown */ public void setShowSupplyBars(boolean showSupplyBars) { globalController.setShowSupplyBars(showSupplyBars); } /** * Sets fairness Model * @param fairnessModel that should be used. */ public void setFairnessModel(FairnessModel fairnessModel) { globalController.setFairnessModel(fairnessModel); } public void updateOutliner() { gui.updateOutliners(simulationManager.getActualDecorState()); } public void updateFlexWindow() { gui.updateFlexWindows(); } public void updateCanvas() { gui.repaintCanvas(); gui.triggerUpdateController(null); } public GUI getGui() { return gui; } public void guiDisable(boolean state) { gui.guiDisable(state); } public void setGui(GUI gui) { this.gui = gui; } }