1 package net.mograsim.logic.model.examples;
3 import java.io.FileWriter;
4 import java.io.IOException;
5 import java.nio.file.Files;
6 import java.nio.file.Path;
7 import java.nio.file.Paths;
8 import java.util.Arrays;
9 import java.util.Collection;
10 import java.util.Comparator;
11 import java.util.HashMap;
12 import java.util.HashSet;
14 import java.util.Map.Entry;
15 import java.util.Scanner;
17 import java.util.TreeMap;
18 import java.util.stream.Collectors;
19 import java.util.stream.Stream;
21 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
22 import net.mograsim.logic.model.am2900.Am2900Loader;
23 import net.mograsim.logic.model.model.LogicModelModifiable;
24 import net.mograsim.logic.model.model.components.ModelComponent;
25 import net.mograsim.logic.model.model.components.atomic.ModelTextComponent;
26 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
27 import net.mograsim.logic.model.model.wires.ModelWire;
28 import net.mograsim.logic.model.model.wires.ModelWireCrossPoint;
29 import net.mograsim.logic.model.model.wires.MovablePin;
30 import net.mograsim.logic.model.model.wires.Pin;
31 import net.mograsim.logic.model.model.wires.PinUsage;
32 import net.mograsim.logic.model.serializing.DeserializedSubmodelComponent;
33 import net.mograsim.logic.model.serializing.IdentifyParams;
34 import net.mograsim.logic.model.serializing.LogicModelParams.ComponentParams;
35 import net.mograsim.logic.model.serializing.LogicModelParams.WireParams;
36 import net.mograsim.logic.model.serializing.SubmodelComponentParams;
37 import net.mograsim.logic.model.serializing.SubmodelComponentSerializer;
38 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.StandardHighLevelStateHandler.StandardHighLevelStateHandlerParams;
39 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic.AtomicHighLevelStateHandler.AtomicHighLevelStateHandlerParams;
40 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic.DelegatingAtomicHighLevelStateHandler.DelegatingAtomicHighLevelStateHandlerParams;
41 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic.WireForcingAtomicHighLevelStateHandler.WireForcingAtomicHighLevelStateHandlerParams;
42 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.subcomponent.DelegatingSubcomponentHighLevelStateHandler.DelegatingSubcomponentHighLevelStateHandlerParams;
43 import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.subcomponent.SubcomponentHighLevelStateHandler.SubcomponentHighLevelStateHandlerParams;
44 import net.mograsim.logic.model.util.JsonHandler;
46 public class ReserializeAndVerifyJSONs
48 public static double GRIDSIZE = 2.5;
49 public static boolean changePinUsages = false;
50 public static boolean changeComponentNames = true;
51 public static boolean forceDefaultComponentNames = true;
52 public static boolean changeWireNames = true;
53 public static boolean forceDefaultWireNames = true;
54 public static boolean snapWCPs = true;
55 public static boolean warnNonSnappedPoints = true;
56 public static boolean warnNonVertHorizLines = true;
57 public static boolean warnRedundantWires = true;
59 public static void main(String[] args) throws IOException
62 try (Scanner sysin = new Scanner(System.in))
64 System.out.print("Directory to search for JSONs in / JSON file to reserialize >");
65 Path root = Paths.get(sysin.nextLine());
66 if (!Files.exists(root))
67 throw new IllegalArgumentException("Path doesn't exist");
68 if (Files.isRegularFile(root))
69 reserializeJSON(root, sysin);
72 System.out.print("Recursive? >");
73 boolean recursive = Boolean.valueOf(sysin.nextLine());
74 try (Stream<Path> jsons = recursive ? Files.walk(root) : Files.list(root))
76 jsons.filter(Files::isRegularFile).filter(p -> p.getFileName().toString().endsWith(".json"))
77 .forEach(j -> reserializeJSON(j, sysin));
83 public static void reserializeJSON(Path componentPath, Scanner sysin)
87 SubmodelComponentParams oldComponentJSON = JsonHandler.readJson(componentPath.toString(), SubmodelComponentParams.class);
88 DeserializedSubmodelComponent comp = (DeserializedSubmodelComponent) SubmodelComponentSerializer
89 .deserialize(new LogicModelModifiable(), oldComponentJSON);
90 System.out.println("Reserializing " + componentPath);
91 LogicModelModifiable submodelModifiable = comp.getSubmodelModifiable();
92 Map<String, String> componentNameRemapping = new HashMap<>();
93 Map<String, String> wireNameRemapping = new HashMap<>();
96 changePinUsages(sysin, comp);
97 if (changeComponentNames)
98 changeComponentNames(sysin, submodelModifiable, componentNameRemapping);
100 changeWireNames(sysin, submodelModifiable, wireNameRemapping);
102 snapWCPs(submodelModifiable);
103 if (warnNonSnappedPoints)
104 warnNonSnappedPoints(comp, submodelModifiable);
105 if (warnNonVertHorizLines)
106 warnNonVertHorizLines(submodelModifiable);
107 if (warnRedundantWires)
108 warnRedundantWires(submodelModifiable);
110 SubmodelComponentParams newComponentJSON = SubmodelComponentSerializer.serialize(comp);
112 if (changeComponentNames)
113 changeComponentNames_AfterSerialization(newComponentJSON, componentNameRemapping);
115 changeWireNames_AfterSerialization(newComponentJSON, wireNameRemapping);
116 sortAllJSONArrays(newComponentJSON);
118 try (FileWriter writer = new FileWriter(componentPath.toString()))
120 String json = JsonHandler.toJson(newComponentJSON);
121 json = json.replace("\u00b5", "\\u00b5");
127 System.err.println("An error occurred visiting " + componentPath + ":");
132 private static void warnRedundantWires(LogicModelModifiable submodelModifiable)
134 Map<Pin, Set<Pin>> connectedPinGroups = new HashMap<>();
135 submodelModifiable.getComponentsByName().values().stream().map(ModelComponent::getPins).map(Map::values).flatMap(Collection::stream)
136 .forEach(p -> connectedPinGroups.put(p, new HashSet<>(Arrays.asList(p))));
137 submodelModifiable.getWiresByName().values().forEach(w ->
139 Pin pin1 = w.getPin1();
140 Pin pin2 = w.getPin2();
141 Set<Pin> pin1Group = connectedPinGroups.get(pin1);
142 Set<Pin> pin2Group = connectedPinGroups.get(pin2);
143 if (pin1Group == pin2Group)
144 System.out.println(" Wire " + w.name + " connecting " + pin1 + " and " + pin2 + " is redundant");
147 pin1Group.addAll(pin2Group);
148 pin2Group.forEach(p -> connectedPinGroups.put(p, pin1Group));
153 private static void changePinUsages(Scanner sysin, DeserializedSubmodelComponent comp)
155 comp.getSubmodelPins().entrySet().stream().sorted(Comparator.comparing(Entry::getKey)).map(Entry::getValue).forEach(pin ->
157 PinUsage oldUsage = comp.getSupermodelPin(pin.name).usage;
158 PinUsage usage = null;
162 System.out.print(" Usage for interface pin " + pin.name + " (empty: " + oldUsage + ") >");
163 String usageStr = sysin.nextLine().toUpperCase();
164 usage = usageStr.equals("") ? oldUsage
165 : usageStr.equals("I") ? PinUsage.INPUT
166 : usageStr.equals("O") ? PinUsage.OUTPUT
167 : usageStr.equals("T") ? PinUsage.TRISTATE : PinUsage.valueOf(usageStr);
169 catch (@SuppressWarnings("unused") IllegalArgumentException e)
171 System.err.println(" Illegal usage");
173 while (usage == null);
174 setInterfacePinUsage(comp, pin, usage);
178 @SuppressWarnings("unused") // TextComponent
179 private static void changeComponentNames(Scanner sysin, LogicModelModifiable submodelModifiable,
180 Map<String, String> componentNameRemapping)
182 componentNameRemapping.put(SubmodelComponent.SUBMODEL_INTERFACE_NAME, SubmodelComponent.SUBMODEL_INTERFACE_NAME);
183 LogicModelModifiable tempModel = new LogicModelModifiable();
184 IdentifyParams iP = new IdentifyParams();
185 submodelModifiable.getComponentsByName().entrySet().stream()
186 .filter(e -> !e.getKey().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
187 .sorted(Comparator.comparing(Entry::getKey, ReserializeAndVerifyJSONs::compareStringsWithIntegers)).forEach(e ->
189 String oldName = e.getKey();
190 ModelComponent subcomp = e.getValue();
191 String defaultName = tempModel.getDefaultComponentName(subcomp);
192 String newName = forceDefaultComponentNames ? defaultName : null;
193 while (newName == null)
195 System.out.print(" New name for component " + oldName + " of type " + subcomp.getIDForSerializing(iP) + " (empty: "
196 + defaultName + ") >");
197 newName = sysin.nextLine();
198 if (newName.equals(""))
199 newName = defaultName;
200 if (tempModel.getComponentsByName().containsKey(newName))
202 System.err.println(" There already is a component with that name");
206 componentNameRemapping.put(oldName, newName);
207 new ModelTextComponent(tempModel, "", newName);
211 private static void changeComponentNames_AfterSerialization(SubmodelComponentParams newComponentJSON,
212 Map<String, String> componentNameRemapping)
214 for (ComponentParams cParams : newComponentJSON.submodel.components)
215 cParams.name = componentNameRemapping.get(cParams.name);
216 for (WireParams wParams : newComponentJSON.submodel.wires)
218 wParams.pin1.compName = componentNameRemapping.get(wParams.pin1.compName);
219 wParams.pin2.compName = componentNameRemapping.get(wParams.pin2.compName);
221 if ("standard".equals(newComponentJSON.highLevelStateHandlerSnippetID))
223 StandardHighLevelStateHandlerParams hlshParams = JsonHandler.fromJsonTree(newComponentJSON.highLevelStateHandlerParams,
224 StandardHighLevelStateHandlerParams.class);
225 for (AtomicHighLevelStateHandlerParams ahlshParams : hlshParams.atomicHighLevelStates.values())
226 if ("delegating".equals(ahlshParams.id))
228 DelegatingAtomicHighLevelStateHandlerParams dhlshParams = JsonHandler.fromJsonTree(ahlshParams.params,
229 DelegatingAtomicHighLevelStateHandlerParams.class);
230 dhlshParams.delegateTarget = componentNameRemapping.get(dhlshParams.delegateTarget);
231 ahlshParams.params = JsonHandler.toJsonTree(dhlshParams);
233 for (SubcomponentHighLevelStateHandlerParams shlshParams : hlshParams.subcomponentHighLevelStates.values())
234 if ("delegating".equals(shlshParams.id))
236 DelegatingSubcomponentHighLevelStateHandlerParams dhlshParams = JsonHandler.fromJsonTree(shlshParams.params,
237 DelegatingSubcomponentHighLevelStateHandlerParams.class);
238 dhlshParams.delegateTarget = componentNameRemapping.get(dhlshParams.delegateTarget);
239 shlshParams.params = JsonHandler.toJsonTree(dhlshParams);
241 newComponentJSON.highLevelStateHandlerParams = JsonHandler.toJsonTree(hlshParams);
245 @SuppressWarnings("unused") // Wire
246 private static void changeWireNames(Scanner sysin, LogicModelModifiable submodelModifiable, Map<String, String> wireNameRemapping)
248 LogicModelModifiable tempModel = new LogicModelModifiable();
249 Pin p = new ModelWireCrossPoint(tempModel, 1).getPin();
250 IdentifyParams iP = new IdentifyParams();
251 submodelModifiable.getWiresByName().entrySet().stream()
252 .sorted(Comparator.comparing(Entry::getKey, ReserializeAndVerifyJSONs::compareStringsWithIntegers)).forEach(e ->
254 String oldName = e.getKey();
255 String defaultName = tempModel.getDefaultWireName();
256 String newName = forceDefaultWireNames ? defaultName : null;
257 while (newName == null)
259 System.out.print(" New name for wire " + oldName + " (empty: " + defaultName + ") >");
260 newName = sysin.nextLine();
261 if (newName.equals(""))
262 newName = defaultName;
263 if (tempModel.getComponentsByName().containsKey(newName))
265 System.err.println(" There already is a component with that name");
269 wireNameRemapping.put(oldName, newName);
270 new ModelWire(tempModel, newName, p, p);
274 private static void changeWireNames_AfterSerialization(SubmodelComponentParams newComponentJSON, Map<String, String> wireNameRemapping)
276 for (WireParams wParams : newComponentJSON.submodel.wires)
277 wParams.name = wireNameRemapping.get(wParams.name);
278 if ("standard".equals(newComponentJSON.highLevelStateHandlerSnippetID))
280 StandardHighLevelStateHandlerParams hlshParams = JsonHandler.fromJsonTree(newComponentJSON.highLevelStateHandlerParams,
281 StandardHighLevelStateHandlerParams.class);
282 for (AtomicHighLevelStateHandlerParams ahlshParams : hlshParams.atomicHighLevelStates.values())
283 if ("wireForcing".equals(ahlshParams.id))
285 WireForcingAtomicHighLevelStateHandlerParams whlshParams = JsonHandler.fromJsonTree(ahlshParams.params,
286 WireForcingAtomicHighLevelStateHandlerParams.class);
287 whlshParams.wiresToForce = whlshParams.wiresToForce.stream().map(wireNameRemapping::get).collect(Collectors.toList());
288 whlshParams.wiresToForceInverted = whlshParams.wiresToForceInverted.stream().map(wireNameRemapping::get)
289 .collect(Collectors.toList());
290 ahlshParams.params = JsonHandler.toJsonTree(whlshParams);
292 newComponentJSON.highLevelStateHandlerParams = JsonHandler.toJsonTree(hlshParams);
296 private static void snapWCPs(LogicModelModifiable submodelModifiable)
298 submodelModifiable.getComponentsByName().values().stream().filter(c -> c instanceof ModelWireCrossPoint).forEach(c ->
300 double x = c.getPosX();
301 double y = c.getPosY();
302 double newX = x % GRIDSIZE == 0 ? x - 1 : x;
303 double newY = y % GRIDSIZE == 0 ? y - 1 : y;
304 if (x != newX || y != newY)
306 c.moveTo(newX, newY);
307 System.out.println(" Snapping WCP " + c.getName());
312 private static void warnNonSnappedPoints(DeserializedSubmodelComponent comp, LogicModelModifiable submodelModifiable)
314 if (comp.getWidth() % GRIDSIZE != 0 || comp.getHeight() % GRIDSIZE != 0)
315 System.out.println(" Size is not snapped to grid: " + comp.getWidth() + "," + comp.getHeight());
316 submodelModifiable.getComponentsByName().values().forEach(c ->
318 double x = c.getPosX();
319 double y = c.getPosY();
320 if (c instanceof ModelWireCrossPoint)
325 if (x % GRIDSIZE != 0 || y % GRIDSIZE != 0)
326 System.out.println(" Component " + c.getName() + " (type " + c.getIDForSerializing(new IdentifyParams())
327 + ") is not snapped to grid: " + x + "," + y);
329 submodelModifiable.getWiresByName().values().forEach(w ->
331 Point[] p = w.getPath();
333 for (int i = 0; i < p.length; i++)
334 if (p[i].x % GRIDSIZE != 0 || p[i].y % GRIDSIZE != 0)
335 System.out.println(" Wire " + w.name + " path point #" + i + " is not snapped to grid: " + p[i].x + "," + p[i].y);
337 comp.getPins().values().forEach(p ->
339 if (p.getRelX() % GRIDSIZE != 0 || p.getRelY() % GRIDSIZE != 0)
340 System.out.println(" Interface point " + p.name + " is not snapped to grid: " + p.getRelX() + "," + p.getRelY());
344 private static void warnNonVertHorizLines(LogicModelModifiable submodelModifiable)
346 submodelModifiable.getWiresByName().values().forEach(w ->
348 double[] p = w.getEffectivePath();
349 for (int i = 1; i < p.length / 2; i++)
351 double x1 = p[2 * i - 2];
352 double y1 = p[2 * i - 1];
353 double x2 = p[2 * i + 0];
354 double y2 = p[2 * i + 1];
355 if (x1 != x2 && y1 != y2)
356 System.out.println(" Wire " + w.name + " part #" + (i - 1) + " is neither vertical nor horizontal");
361 private static void sortAllJSONArrays(SubmodelComponentParams newComponentJSON)
363 Comparator<String> c = ReserializeAndVerifyJSONs::compareStringsWithIntegers;
364 Arrays.sort(newComponentJSON.interfacePins, Comparator.comparing(p -> p.name, c));
365 Arrays.sort(newComponentJSON.submodel.components, Comparator.comparing(p -> p.name, c));
366 Arrays.sort(newComponentJSON.submodel.wires, Comparator.comparing(p -> p.name, c));
367 if ("standard".equals(newComponentJSON.highLevelStateHandlerSnippetID))
369 StandardHighLevelStateHandlerParams hlshP = JsonHandler.fromJsonTree(newComponentJSON.highLevelStateHandlerParams,
370 StandardHighLevelStateHandlerParams.class);
371 TreeMap<String, AtomicHighLevelStateHandlerParams> tmp1 = new TreeMap<>(c);
372 tmp1.putAll(hlshP.atomicHighLevelStates);
373 hlshP.atomicHighLevelStates = tmp1;
374 TreeMap<String, SubcomponentHighLevelStateHandlerParams> tmp2 = new TreeMap<>(c);
375 tmp2.putAll(hlshP.subcomponentHighLevelStates);
376 hlshP.subcomponentHighLevelStates = tmp2;
377 newComponentJSON.highLevelStateHandlerParams = JsonHandler.toJsonTree(hlshP);
381 private static int compareStringsWithIntegers(String a, String b)
387 if (aLoc == a.length())
389 if (bLoc == b.length())
393 if (bLoc == b.length())
395 int aInt = 1, bInt = 1;// 1 so a longer number is always greater (makes a difference for leading zeroes)
396 boolean aHasNumber = false, bHasNumber = false;
397 char nextCharA, nextCharB;
400 nextCharA = a.charAt(aLoc++);
401 if (nextCharA < '0' || nextCharA > '9')
404 aInt = aInt * 10 + nextCharA - '0';
405 if (aLoc == a.length())
410 nextCharB = b.charAt(bLoc++);
411 if (nextCharB < '0' || nextCharB > '9')
414 bInt = bInt * 10 + nextCharB - '0';
415 if (bLoc == b.length())
422 int comp = Integer.compare(aInt, bInt);
429 int comp = Character.compare(nextCharA, nextCharB);
436 private static void setInterfacePinUsage(DeserializedSubmodelComponent comp, Pin interfacePin, PinUsage usage)
438 Set<ModelWire> wiresConnectedToPin1 = comp.submodel.getWiresByName().values().stream().filter(w -> w.getPin1() == interfacePin)
439 .collect(Collectors.toSet());
440 Set<ModelWire> wiresConnectedToPin2 = comp.submodel.getWiresByName().values().stream().filter(w -> w.getPin2() == interfacePin)
441 .collect(Collectors.toSet());
442 LogicModelModifiable submodelModifiable = comp.getSubmodelModifiable();
443 wiresConnectedToPin1.forEach(submodelModifiable::destroyWire);
444 wiresConnectedToPin2.forEach(submodelModifiable::destroyWire);
445 Pin supermodelPin = comp.getSupermodelPin(interfacePin.name);
446 comp.removeSubmodelInterface(interfacePin.name);
447 comp.addSubmodelInterface(new MovablePin(submodelModifiable, comp, interfacePin.name, interfacePin.logicWidth, usage,
448 supermodelPin.getRelX(), supermodelPin.getRelY()));
449 Pin interfacePinNew = comp.getSubmodelPin(interfacePin.name);
450 wiresConnectedToPin1.forEach(w -> new ModelWire(submodelModifiable, interfacePinNew, w.getPin2(), w.getPath()));
451 wiresConnectedToPin2.forEach(w -> new ModelWire(submodelModifiable, w.getPin1(), interfacePinNew, w.getPath()));