package holeg.ui.controller; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import holeg.model.*; import holeg.model.HolonElement.Priority; import holeg.ui.model.GuiSettings; import holeg.ui.model.IdCounter; import holeg.ui.model.Model; import holeg.ui.model.IdCounter.CounterType; import holeg.utility.math.vector.Vec2f; import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveException; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.apache.commons.compress.utils.IOUtils; import java.io.*; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; import java.util.stream.Collectors; /** * Controller for the Loading. * * @author Gruppe14 */ public class LoadController { private static final Logger log = Logger.getLogger(Model.class.getName()); private Model model; private CategoryController cgC; private CanvasController cvsC; private NodeController uppC; private static HashMap OldTypeNameReplacement = new HashMap(); static { OldTypeNameReplacement.put("CpsNode", "Node"); OldTypeNameReplacement.put("CpsUpperNode", "GroupNode"); } /** * Constructor. * * @param model Model * @param cg CategoryController * @param cvs CanvasController */ LoadController(Model model, CategoryController cg, CanvasController cvs, NodeController uppC) { this.model = model; this.cgC = cg; this.cvsC = cvs; this.uppC = uppC; } /** * Reads the the JSON File and load the state into the Model. * * @param path the Path * @throws IOException exception */ void readSave(String path) throws IOException, ArchiveException { File src = new File(path); File folder = readArchive(src); folder.deleteOnExit(); String trim = folder.getPath().substring(0, folder.getPath().lastIndexOf(folder.getName()) + folder.getName().length()); forwardFiles(folder, trim); } /** * reads the dimensions file containing the saved position and dimensions of the frame * * @return a list of the form [x, y, width, height] */ ArrayList readWindowDimensions(String path) throws FileNotFoundException { JsonObject json = (JsonObject) JsonParser.parseReader(new FileReader(path)); ArrayList dimensions = new ArrayList<>(); List keys = getKeys(json); for (int i = 1; i < 5; i++) { dimensions.add(json.get(keys.get(i)).getAsInt()); } return dimensions; } void readJson(String path) throws IOException { JsonObject json = (JsonObject) JsonParser.parseReader(new FileReader(path)); // get all keys via stream List keys = getKeys(json); List edges = keys.stream().filter(key -> key.contains("EDGE")) .collect(Collectors.toCollection(ArrayList::new)); HashMap objDispatch = new HashMap<>(); HashMap eleDispatch = new HashMap<>(); initialize(json); forwardObjects(keys, json, objDispatch, eleDispatch); forwardEdges(edges, json, objDispatch); } /** * Loads the Files from the Savefile * * @param trim the part of the file's path to be trimmed * @throws IOException if anythings goes wrong reading the files */ private void forwardFiles(File folder, String trim) throws IOException { for (File file : folder.listFiles()) { File dst = new File( System.getProperty("user.home") + "/.config/HolonGUI/" + file.getPath().replace(trim, "")); if (file.getName().contains(".json")) readJson(file.getPath()); else if (file.isDirectory()) forwardFiles(file, trim); else { dst.getParentFile().mkdirs(); Files.copy(file.toPath(), dst.toPath(), StandardCopyOption.REPLACE_EXISTING); } } } /** * distribute the Edges */ private void forwardEdges(List edges, JsonObject json, HashMap objDispatch) { for (String edge : edges) { if (edge.contains("CVSEDGE")) loadEdge(EDGETYPE.CANVAS, json.get(edge), objDispatch); if (edge.contains("CONNEDGE")) loadEdge(EDGETYPE.CONNECTION, json.get(edge), objDispatch); if (edge.contains("NODE")) loadEdge(EDGETYPE.NODE, json.get(edge), objDispatch); if (edge.contains("OLD")) loadEdge(EDGETYPE.OLD, json.get(edge), objDispatch); } } /** * Distribute the given keys for right processing */ private void forwardObjects(List keys, JsonObject json, HashMap objDispatch, HashMap eleDispatch) { for (String key : keys) { if (key.contains("CATEGORY")) loadCategory(json.get(key)); else if (key.contains("CGOBJECT")) loadCategoryObject(json.get(key).getAsJsonObject()); else if (key.contains("CGELEMENT")) loadCategoryElements(json.get(key), eleDispatch); else if (key.contains("CVSOBJECT")) loadCanvasObject(json.get(key).getAsJsonObject(), objDispatch); else if (key.contains("CVSELEMENT")) loadCanvasElements(json.get(key), objDispatch, eleDispatch); else if (key.contains("SWUNITGRAPH")) loadUnitGraph(GRAPHTYPE.SWITCH, json.get(key), objDispatch, null); else if (key.contains("ELEUNITGRAPH") && key.contains("ELETESTUNITGRAPH")) loadUnitGraph(GRAPHTYPE.ELEMENT, json.get(key), null, eleDispatch); } } /** * Init the Global Parameters */ private void initialize(JsonObject json) { switch (MODE.valueOf(json.get("MODE").getAsString())) { case COMPLETE: case PARTIAL: model.getEdgesOnCanvas().clear(); GuiSettings.canvasSize.setX(json.get("CANVAS_SIZE_X").getAsInt()); GuiSettings.canvasSize.setY(json.get("CANVAS_SIZE_Y").getAsInt()); IdCounter.setCounter(json.get("IDCOUNTER").getAsInt(), CounterType.Object); IdCounter.setCounter(json.get("IDCOUNTERELEMENT").getAsInt(), CounterType.Element); break; case CATEGORY: default: break; } } /** * Load a given Category */ private void loadCategory(JsonElement jsonElement) { if (cgC.findCategoryWithName(jsonElement.getAsString()).isEmpty()) { cgC.createCategoryWithName(jsonElement.getAsString()); } } /** * Load a given Object in Category by Deserialization */ private void loadCategoryObject(JsonObject jsonObject) { AbstractCanvasObject temp; replaceOldClassNames(jsonObject); try { temp = GuiSettings.gson.fromJson(jsonObject, AbstractCanvasObject.class); }catch (com.google.gson.JsonParseException e){ log.warning(jsonObject.get("type").getAsString()); return; } temp.initForReflection(); temp.setImage(checkOS(temp.getImage())); //TODO(Tom2022-01-16): Cat name should be stored somewhere cgC.findCategoryWithName(temp.getName()).ifPresent(cat -> { cat.findObjectWithName(temp.getName()).ifPresent(obj -> { cgC.removeObject(cat, obj); }); cgC.addObject(cat, temp); }); } /** * Load a given Element in Category by Deserialization * @param eleDispatch */ private void loadCategoryElements(JsonElement jsonElement, HashMap eleDispatch) { JsonObject object = jsonElement.getAsJsonObject(); HolonElement ele = GuiSettings.gson.fromJson(object.get("properties"), HolonElement.class); eleDispatch.put(ele.getId(), ele); initElements(ele); ele.flexList = GuiSettings.gson.fromJson(object.get("FlexList"), new TypeToken>() {}.getType()); if(ele.flexList == null) ele.flexList = new ArrayList(); ele.flexList.stream().forEach(flex -> { flex.setElement(ele); flex.constrainList.forEach(con -> con.fixJson()); }); //Fix old amount JsonElement amount = object.get("properties").getAsJsonObject().get("amount"); if(amount != null) { ele.setEnergy(amount.getAsInt() * ele.getEnergy()); } } /** * Load a given Object in Canvas by Deserialization */ private void loadCanvasObject(JsonObject jsonObject, HashMap objDispatch) { AbstractCanvasObject temp = null; replaceOldClassNames(jsonObject); try { temp = GuiSettings.gson.fromJson(jsonObject, AbstractCanvasObject.class); }catch (com.google.gson.JsonParseException e){ log.warning(e + jsonObject.get("type").getAsString()); return; } temp.initForReflection(); temp.setImage(checkOS(temp.getImage())); cvsC.addObject(temp, false); objDispatch.put(temp.getId(), temp); } private void replaceOldClassNames(JsonObject abstractCanvasClassJsonObject) { String type = abstractCanvasClassJsonObject.get("type").getAsString(); if(OldTypeNameReplacement.containsKey(type)) { abstractCanvasClassJsonObject.addProperty("type", OldTypeNameReplacement.get(type)); } } /** * Load a given Element in Canvas by Deserialization */ private void loadCanvasElements(JsonElement jsonElement, HashMap objDispatch, HashMap eleDispatch) { JsonObject object = jsonElement.getAsJsonObject(); HolonElement ele = GuiSettings.gson.fromJson(object.get("properties"), HolonElement.class); initElements(ele); ele.flexList = GuiSettings.gson.fromJson(object.get("FlexList"), new TypeToken>() {}.getType()); if(ele.flexList == null) ele.flexList = new ArrayList<>(); ele.flexList.stream().forEach(flex -> { flex.setElement(ele); flex.constrainList.forEach(con -> con.fixJson()); }); //Fix old amount JsonElement amount = object.get("properties").getAsJsonObject().get("amount"); if(amount != null) { ele.setEnergy(amount.getAsInt() * ele.getEnergy()); } // id which Object it was stored before int stored = object.get("ID").getAsInt(); // lookup that object HolonObject hObject = (HolonObject) objDispatch.get(stored); // add it hObject.add(ele); ele.parentObject = hObject; // store element also inside a table eleDispatch.put(ele.getId(), ele); } /** * Load a given Edge by Deserialization */ private void loadEdge(EDGETYPE type, JsonElement jsonElement, HashMap objDispatch) { JsonObject object = jsonElement.getAsJsonObject(); Edge temp = GuiSettings.gson.fromJson(object.get("properties"), Edge.class); initCpsEdge(temp); // look for A and B inside the Table temp.setA(objDispatch.get(object.get("A").getAsInt())); temp.setB(objDispatch.get(object.get("B").getAsInt())); model.getEdgesOnCanvas().add(temp); } /** * Load a Unitgraph by Deserialization */ private void loadUnitGraph(GRAPHTYPE type, JsonElement jsonElement, HashMap objDispatch, HashMap eleDispatch) { JsonObject object = jsonElement.getAsJsonObject(); List keys = getKeys(object); String p; int mid; int sav = 0; LinkedList graphpointTEST = new LinkedList<>(); for (String k : keys) { if (!k.equals("ID")) { p = object.get(k).getAsString(); mid = p.indexOf(':'); float x1 = Float.parseFloat(p.substring(0, mid)); float y1 = Float.parseFloat(p.substring(mid + 1, p.length())); graphpointTEST.add(new Vec2f(x1, y1)); } else // else its an ID sav = object.get(k).getAsInt(); } switch (type) { case SWITCH: HolonSwitch sw = (HolonSwitch) objDispatch.get(sav); sw.setGraphPoints(graphpointTEST); sw.sampleGraph(); break; case ELEMENT: HolonElement ele1 = eleDispatch.get(sav); ele1.setGraphPoints(graphpointTEST); ele1.sampleGraph(); break; default: break; } } private File readArchive(File src) throws IOException, ArchiveException { File tmp = Files.createTempDirectory("tmpHolon").toFile(); tmp.deleteOnExit(); InputStream input = new FileInputStream(src); ArchiveInputStream stream = new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP, input); ArchiveEntry entry = stream.getNextEntry(); while (entry != null) { // String entryName = checkOS(entry.getName()); File file = new File(tmp, entry.getName()); file.getParentFile().mkdirs(); OutputStream output = new FileOutputStream(file); IOUtils.copy(stream, output); output.close(); // file.createNewFile(); entry = stream.getNextEntry(); } stream.close(); input.close(); return tmp; } private String checkOS(String entryName) { String os = System.getProperty("os.name").toLowerCase(); String ret = entryName; // String partition = System.getProperty("user.home"); if (!ret.contains("HolonGUI")) return ret; if (os.contains("windows")) { ret = ret.replace("/", "\\"); ret = System.getProperty("user.home") + "\\.config" + ret.substring(ret.indexOf("\\HolonGUI\\"), ret.length()); } if (os.contains("mac")) { // dosmth ret = ret.replace("\\", "/"); ret = System.getProperty("user.home") + "/.config" + ret.substring(ret.indexOf("/HolonGUI/"), ret.length()); } if (os.contains("linux")) { // dosmth ret = ret.replace("\\", "/"); ret = System.getProperty("user.home") + "/.config" + ret.substring(ret.indexOf("/HolonGUI/"), ret.length()); } // if (os.contains("solaris")) { // // dosmth // } return ret; } /** * Init Elements (set available energy, set new graph points) * * @param ele the element to be initialized */ void initElements(HolonElement ele) { ele.flexList = new ArrayList(); ele.setGraphPoints(new LinkedList<>()); if(ele.getPriority() == null) ele.setPriority(Priority.Low); ele.reset(); if(ele.getPriority() == null) { ele.setPriority(Priority.Low); } } /** * TODO(Tom2021-12-1) DELETE * Init Edges (set tags and reset source and target) * * @param edge the edge to be initialized */ void initCpsEdge(Edge edge) { edge.setA(null); edge.setB(null); edge.setState(Edge.EdgeState.Working); } /** * Get Set of Keys * * @return the keys from the json object */ List getKeys(JsonObject json) { return json.entrySet().stream().map(i -> i.getKey()).collect(Collectors.toCollection(ArrayList::new)); } /** * enum Mode. (in SaveController there is an additional mode called SIZE, * it is not currently needed here and was therefore not added) */ public enum MODE { COMPLETE, PARTIAL, CATEGORY } public enum EDGETYPE { CANVAS, CONNECTION, NODE, OLD } public enum GRAPHTYPE { SWITCH, ELEMENT } }