ReserializeAndVerifyJSONs now checks wire part orientations
[Mograsim.git] / net.mograsim.logic.model.am2900 / src / net / mograsim / logic / model / examples / ReserializeAndVerifyJSONs.java
1 package net.mograsim.logic.model.examples;
2
3 import java.io.IOException;
4 import java.nio.file.Files;
5 import java.nio.file.Path;
6 import java.nio.file.Paths;
7 import java.util.Comparator;
8 import java.util.HashMap;
9 import java.util.Map;
10 import java.util.Map.Entry;
11 import java.util.Optional;
12 import java.util.Scanner;
13 import java.util.Set;
14 import java.util.function.Function;
15 import java.util.stream.Collectors;
16 import java.util.stream.Stream;
17
18 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
19 import net.mograsim.logic.model.am2900.Am2900Loader;
20 import net.mograsim.logic.model.model.LogicModelModifiable;
21 import net.mograsim.logic.model.model.components.ModelComponent;
22 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
23 import net.mograsim.logic.model.model.components.submodels.SubmodelInterface;
24 import net.mograsim.logic.model.model.wires.ModelWire;
25 import net.mograsim.logic.model.model.wires.ModelWireCrossPoint;
26 import net.mograsim.logic.model.model.wires.MovablePin;
27 import net.mograsim.logic.model.model.wires.Pin;
28 import net.mograsim.logic.model.model.wires.PinUsage;
29 import net.mograsim.logic.model.serializing.DeserializedSubmodelComponent;
30 import net.mograsim.logic.model.serializing.IdentifyParams;
31 import net.mograsim.logic.model.serializing.IndirectModelComponentCreator;
32 import net.mograsim.logic.model.serializing.SubmodelComponentSerializer;
33 import net.mograsim.logic.model.snippets.highlevelstatehandlers.DefaultHighLevelStateHandler;
34
35 public class ReserializeAndVerifyJSONs
36 {
37         public static double GRIDSIZE = 2.5;
38         public static boolean changePinUsages = false;
39         public static boolean changeComponentNames = false;
40         public static boolean snapWCPs = true;
41         public static boolean warnNonSnappedPoints = true;
42         public static boolean warnNonVertHorizLines = true;
43
44         public static void main(String[] args) throws IOException
45         {
46                 Am2900Loader.setup();
47                 try (Scanner sysin = new Scanner(System.in))
48                 {
49                         System.out.print("Directory to search for JSONs in / JSON file to reserialize >");
50                         Path root = Paths.get(sysin.nextLine());
51                         if (!Files.exists(root))
52                                 throw new IllegalArgumentException("Path doesn't exist");
53                         if (Files.isRegularFile(root))
54                                 reserializeJSON(root, sysin);
55                         else
56                         {
57                                 System.out.print("Recursive? >");
58                                 boolean recursive = Boolean.valueOf(sysin.nextLine());
59                                 try (Stream<Path> jsons = recursive ? Files.walk(root) : Files.list(root))
60                                 {
61                                         jsons.filter(Files::isRegularFile).filter(p -> p.getFileName().toString().endsWith(".json"))
62                                                         .forEach(j -> reserializeJSON(j, sysin));
63                                 }
64                         }
65                 }
66         }
67
68         public static void reserializeJSON(Path componentPath, Scanner sysin)
69         {
70                 try
71                 {
72                         DeserializedSubmodelComponent comp = (DeserializedSubmodelComponent) IndirectModelComponentCreator
73                                         .createComponent(new LogicModelModifiable(), "jsonfile:" + componentPath.toString());
74                         System.out.println("Reserializing " + componentPath);
75                         if (changePinUsages)
76                                 comp.getSupermodelPins().entrySet().stream().sorted(Comparator.comparing(Entry::getKey)).map(Entry::getValue).forEach(pin ->
77                                 {
78                                         PinUsage usage = null;
79                                         while (usage == null)
80                                                 try
81                                                 {
82                                                         System.out.print("  Usage for interface pin " + pin.name + " (empty: " + pin.usage + ") >");
83                                                         String usageStr = sysin.nextLine().toUpperCase();
84                                                         usage = usageStr.equals("") ? pin.usage
85                                                                         : usageStr.equals("I") ? PinUsage.INPUT
86                                                                                         : usageStr.equals("O") ? PinUsage.OUTPUT
87                                                                                                         : usageStr.equals("T") ? PinUsage.TRISTATE : PinUsage.valueOf(usageStr);
88                                                 }
89                                                 catch (@SuppressWarnings("unused") IllegalArgumentException e)
90                                                 {
91                                                         System.err.println("  Illegal usage");
92                                                 }
93                                         setInterfacePinUsage(comp, pin, usage);
94                                 });
95                         LogicModelModifiable submodelModifiable = comp.getSubmodelModifiable();
96                         Map<String, String> componentNameRemapping = new HashMap<>();
97                         if (changeComponentNames)
98                                 changeComponentNames(sysin, submodelModifiable, componentNameRemapping);
99                         if (snapWCPs)
100                                 snapWCPs(submodelModifiable);
101                         if (warnNonSnappedPoints)
102                                 warnNonSnappedPoints(comp, submodelModifiable);
103                         if (warnNonVertHorizLines)
104                                 warnNonVertHorizLines(submodelModifiable);
105                         SubmodelComponentSerializer.serialize(comp, componentPath.toString());
106                         if (changeComponentNames)
107                                 changeComponentNames_AfterSerialization(sysin, comp, componentNameRemapping);
108                 }
109                 catch (Exception e)
110                 {
111                         System.err.println("An error occurred visiting " + componentPath + ":");
112                         e.printStackTrace();
113                 }
114         }
115
116         private static void changeComponentNames_AfterSerialization(Scanner sysin, DeserializedSubmodelComponent comp,
117                         Map<String, String> componentNameRemapping)
118         {
119                 if (comp.getHighLevelStateHandler() == null || !(comp.getHighLevelStateHandler() instanceof DefaultHighLevelStateHandler))
120                 {
121                         System.out.println("  A non-default HighLevelStateHandler was detected. Check for changes there manually.");
122                         System.out.print("  Empty line to continue to next component, old component name to get new component name >");
123                         for (String line = sysin.nextLine(); !line.equals(""); line = sysin.nextLine())
124                                 System.out.println("  " + line + "->" + componentNameRemapping.get(line) + " >");
125                 }
126         }
127
128         private static void changeComponentNames(Scanner sysin, LogicModelModifiable submodelModifiable,
129                         Map<String, String> componentNameRemapping)
130         {
131                 componentNameRemapping.put(SubmodelComponent.SUBMODEL_INTERFACE_NAME, SubmodelComponent.SUBMODEL_INTERFACE_NAME);
132                 LogicModelModifiable tempModel = new LogicModelModifiable();
133                 IdentifyParams iP = new IdentifyParams();
134                 submodelModifiable.getComponentsByName().entrySet().stream()
135                                 .filter(e -> !e.getKey().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
136                                 .sorted(Comparator.comparing(Entry::getKey, ReserializeAndVerifyJSONs::compareStringsWithIntegers)).forEach(e ->
137                                 {
138                                         String oldName = e.getKey();
139                                         ModelComponent subcomp = e.getValue();
140                                         String defaultName = tempModel.getDefaultComponentName(subcomp);
141                                         String newName = null;
142                                         while (newName == null)
143                                         {
144                                                 System.out.print("  New name for component " + oldName + " of type " + subcomp.getIDForSerializing(iP) + " (empty: "
145                                                                 + defaultName + ") >");
146                                                 newName = sysin.nextLine();
147                                                 if (newName.equals(""))
148                                                         newName = defaultName;
149                                                 if (tempModel.getComponentsByName().containsKey(newName))
150                                                 {
151                                                         System.err.println("  There already is a component with that name");
152                                                         newName = null;
153                                                 }
154                                         }
155                                         componentNameRemapping.put(oldName, newName);
156                                         IndirectModelComponentCreator
157                                                         .createComponent(tempModel, subcomp.getIDForSerializing(iP), subcomp.getParamsForSerializingJSON(iP), newName)
158                                                         .moveTo(subcomp.getPosX(), subcomp.getPosY());
159                                 });
160                 SubmodelInterface tempSubmodelInterface = new SubmodelInterface(tempModel);
161                 for (Pin p : submodelModifiable.getComponentsByName().get(SubmodelComponent.SUBMODEL_INTERFACE_NAME).getPins().values())
162                         tempSubmodelInterface
163                                         .addPin(new Pin(tempModel, tempSubmodelInterface, p.name, p.logicWidth, p.usage, p.getRelX(), p.getRelY()));
164                 for (ModelWire w : submodelModifiable.getWiresByName().values())
165                         createWire(componentNameRemapping::get, tempModel, w);
166
167                 Optional<ModelComponent> o;
168                 while ((o = submodelModifiable.getComponentsByName().values().stream()
169                                 .filter(c -> !c.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME)).findAny()).isPresent())
170                         submodelModifiable.destroyComponent(o.get());
171
172                 tempModel.getComponentsByName().values().stream().filter(c -> !c.getName().equals(SubmodelComponent.SUBMODEL_INTERFACE_NAME))
173                                 .forEach(c -> IndirectModelComponentCreator
174                                                 .createComponent(submodelModifiable, c.getIDForSerializing(iP), c.getParamsForSerializingJSON(iP), c.getName())
175                                                 .moveTo(c.getPosX(), c.getPosY()));
176                 for (ModelWire w : tempModel.getWiresByName().values())
177                         createWire(Function.identity(), submodelModifiable, w);
178         }
179
180         private static void snapWCPs(LogicModelModifiable submodelModifiable)
181         {
182                 submodelModifiable.getComponentsByName().values().stream().filter(c -> c instanceof ModelWireCrossPoint).forEach(c ->
183                 {
184                         double x = c.getPosX();
185                         double y = c.getPosY();
186                         double newX = x % GRIDSIZE == 0 ? x - 1 : x;
187                         double newY = y % GRIDSIZE == 0 ? y - 1 : y;
188                         if (x != newX || y != newY)
189                         {
190                                 c.moveTo(newX, newY);
191                                 System.out.println("  Snapping WCP " + c.getName());
192                         }
193                 });
194         }
195
196         private static void warnNonSnappedPoints(DeserializedSubmodelComponent comp, LogicModelModifiable submodelModifiable)
197         {
198                 if (comp.getWidth() % GRIDSIZE != 0 || comp.getHeight() % GRIDSIZE != 0)
199                         System.out.println("  Size is not snapped to grid: " + comp.getWidth() + "," + comp.getHeight());
200                 submodelModifiable.getComponentsByName().values().forEach(c ->
201                 {
202                         double x = c.getPosX();
203                         double y = c.getPosY();
204                         if (c instanceof ModelWireCrossPoint)
205                         {
206                                 x++;
207                                 y++;
208                         }
209                         if (x % GRIDSIZE != 0 || y % GRIDSIZE != 0)
210                                 System.out.println("  Component " + c.getName() + " (type " + c.getIDForSerializing(new IdentifyParams())
211                                                 + ") is not snapped to grid: " + x + "," + y);
212                 });
213                 submodelModifiable.getWiresByName().values().forEach(w ->
214                 {
215                         Point[] p = w.getPath();
216                         if (p != null)
217                                 for (int i = 0; i < p.length; i++)
218                                         if (p[i].x % GRIDSIZE != 0 || p[i].y % GRIDSIZE != 0)
219                                                 System.out.println("  Wire " + w.name + " path point #" + i + " is not snapped to grid: " + p[i].x + "," + p[i].y);
220                 });
221                 comp.getPins().values().forEach(p ->
222                 {
223                         if (p.getRelX() % GRIDSIZE != 0 || p.getRelY() % GRIDSIZE != 0)
224                                 System.out.println("  Interface point " + p.name + " is not snapped to grid: " + p.getRelX() + "," + p.getRelY());
225                 });
226         }
227
228         private static void warnNonVertHorizLines(LogicModelModifiable submodelModifiable)
229         {
230                 submodelModifiable.getWiresByName().values().forEach(w ->
231                 {
232                         double[] p = w.getEffectivePath();
233                         for (int i = 1; i < p.length / 2; i++)
234                         {
235                                 double x1 = p[2 * i - 2];
236                                 double y1 = p[2 * i - 1];
237                                 double x2 = p[2 * i + 0];
238                                 double y2 = p[2 * i + 1];
239                                 if (x1 != x2 && y1 != y2)
240                                         System.out.println("  Wire " + w.name + " part #" + (i - 1) + " is neither vertical nor horizontal");
241                         }
242                 });
243         }
244
245         private static ModelWire createWire(Function<String, String> componentNameRemapping, LogicModelModifiable tempModelForDefaultNames,
246                         ModelWire w)
247         {
248                 return new ModelWire(tempModelForDefaultNames, w.name,
249                                 getRemappedPin(componentNameRemapping, tempModelForDefaultNames, w.getPin1()),
250                                 getRemappedPin(componentNameRemapping, tempModelForDefaultNames, w.getPin2()), w.getPath());
251         }
252
253         private static Pin getRemappedPin(Function<String, String> componentNameRemapping, LogicModelModifiable tempModelForDefaultNames,
254                         Pin pin)
255         {
256                 return tempModelForDefaultNames.getComponentsByName().get(componentNameRemapping.apply(pin.component.getName())).getPin(pin.name);
257         }
258
259         private static int compareStringsWithIntegers(String a, String b)
260         {
261                 int aLoc = 0;
262                 int bLoc = 0;
263                 for (;;)
264                 {
265                         if (aLoc == a.length())
266                         {
267                                 if (bLoc == b.length())
268                                         return 0;
269                                 return -1;
270                         }
271                         if (bLoc == b.length())
272                                 return 1;
273                         int aInt = 0;
274                         int aIntLen = 0;
275                         char nextCharA;
276                         for (;;)
277                         {
278                                 nextCharA = a.charAt(aLoc++);
279                                 if (nextCharA < '0' || nextCharA > '9')
280                                         break;
281                                 aIntLen++;
282                                 aInt = aInt * 10 + nextCharA - '0';
283                                 if (aLoc == a.length())
284                                         break;
285                         }
286                         int bInt = 0;
287                         int bIntLen = 0;
288                         char nextCharB;
289                         for (;;)
290                         {
291                                 nextCharB = b.charAt(bLoc++);
292                                 if (nextCharB < '0' || nextCharB > '9')
293                                         break;
294                                 bIntLen++;
295                                 bInt = bInt * 10 + nextCharB - '0';
296                                 if (bLoc == b.length())
297                                         break;
298                         }
299                         if (aIntLen != 0)
300                         {
301                                 if (bIntLen == 0)
302                                         return -1;
303                                 int comp = Integer.compare(aInt, bInt);
304                                 if (comp != 0)
305                                         return comp;
306                         } else
307                         {
308                                 if (bIntLen != 0)
309                                         return 1;
310                                 int comp = Character.compare(nextCharA, nextCharB);
311                                 if (comp != 0)
312                                         return comp;
313                         }
314                 }
315         }
316
317         private static void setInterfacePinUsage(DeserializedSubmodelComponent comp, Pin interfacePin, PinUsage usage)
318         {
319                 Set<ModelWire> wiresConnectedToPin = comp.submodel.getWiresByName().values().stream()
320                                 .filter(w -> w.getPin1() == interfacePin || w.getPin2() == interfacePin).collect(Collectors.toSet());
321                 LogicModelModifiable submodelModifiable = comp.getSubmodelModifiable();
322                 wiresConnectedToPin.forEach(submodelModifiable::destroyWire);
323                 comp.removeSubmodelInterface(interfacePin.name);
324                 comp.addSubmodelInterface(new MovablePin(submodelModifiable, comp, interfacePin.name, interfacePin.logicWidth, usage,
325                                 interfacePin.getRelX(), interfacePin.getRelY()));
326                 wiresConnectedToPin.forEach(w -> new ModelWire(submodelModifiable, w.getPin1(), w.getPin2()));
327         }
328 }