Updated SubmodelComponentParams json format
[Mograsim.git] / net.mograsim.logic.ui / src / net / mograsim / logic / ui / model / components / GUICustomComponentCreator.java
1 package net.mograsim.logic.ui.model.components;
2
3 import java.io.IOException;
4 import java.lang.reflect.Constructor;
5 import java.lang.reflect.InvocationTargetException;
6 import java.util.Map;
7
8 import net.mograsim.logic.ui.model.ViewModelModifiable;
9 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.ComponentCompositionParams.InnerComponentParams;
10 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.ComponentCompositionParams;
11 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.InnerWireParams;
12 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.InterfacePinParams;
13 import net.mograsim.logic.ui.model.wires.GUIWire;
14 import net.mograsim.logic.ui.model.wires.WireCrossPoint;
15
16 /**
17  * Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
18  */
19 public final class GUICustomComponentCreator
20 {
21         private static final String rectC = SimpleRectangularSubmodelComponent.class.getSimpleName();
22
23         /**
24          * Creates a {@link SubmodelComponent} from the {@link SubmodelComponentParams}, specified at the given path. The returned
25          * SubmodelComponent can also be e.g. a {@link SimpleRectangularSubmodelComponent}, depending on what the
26          * {@link SubmodelComponentParams} describe.
27          * 
28          * @param path The path of the file describing the {@link SubmodelComponentParams}, which define the new {@link SubmodelComponent}
29          * @return A new SubmodelComponent, as described in the file located at the given path
30          */
31         public static SubmodelComponent create(ViewModelModifiable model, String path)
32         {
33                 try
34                 {
35                         SubmodelComponentParams params = SubmodelComponentParams.readJson(path);
36                         SubmodelComponent ret = create(model, params, path);
37                         return ret;
38                 }
39                 catch (IOException e)
40                 {
41                         System.err.println("Failed to construct GUICustomComponent. Parameters were not found.");
42                         e.printStackTrace();
43                 }
44                 return new SimpleRectangularSubmodelComponent(model, 0, "ERROR");
45         }
46
47         /**
48          * Creates a {@link SubmodelComponent} from the specified {@link SubmodelComponentParams}. The returned SubmodelComponent can also be
49          * e.g. a {@link SimpleRectangularSubmodelComponent}, depending on what the {@link SubmodelComponentParams} describe.
50          * 
51          * @param params The parameters describing the {@link SubmodelComponent}
52          * @param path   This value is used when the new {@link SubmodelComponent} is an inner component to a different SubmodelComponent, which
53          *               is being saved to a file; Then, the new {@link SubmodelComponent} is referenced by its given path within the file.
54          * @return A new SubmodelComponent, as described by the {@link SubmodelComponentParams}
55          */
56         public static SubmodelComponent create(ViewModelModifiable model, SubmodelComponentParams params, String path)
57         {
58                 SubmodelComponent comp = null;
59                 if (rectC.equals(params.type))
60                 {
61                         comp = createRectComponent(model, params);
62                 }
63
64                 if (comp == null)
65                 {
66                         comp = createSubmodelComponent(model, params);
67                 }
68                 comp.identifierDelegate = () -> "file:".concat(path);
69                 initInnerComponents(comp, params.composition);
70                 return comp;
71         }
72
73         // May return null
74         private static SimpleRectangularSubmodelComponent createRectComponent(ViewModelModifiable model, SubmodelComponentParams params)
75         {
76                 try
77                 {
78                         Map<String, Object> m = params.specialized;
79                         SimpleRectangularSubmodelComponent rect = new SimpleRectangularSubmodelComponent(model,
80                                         ((Number) m.get(SimpleRectangularSubmodelComponent.kLogicWidth)).intValue(),
81                                         (String) m.get(SimpleRectangularSubmodelComponent.kLabel));
82                         rect.setSubmodelScale(params.composition.innerScale);
83                         // rect.setSize(params.width, params.height);
84
85                         // TODO save & restore names
86                         int inputCount = ((Number) m.get(SimpleRectangularSubmodelComponent.kInCount)).intValue();
87                         String[] inputNames = new String[inputCount];
88                         for (int i = 0; i < inputCount; i++)
89                                 inputNames[i] = params.interfacePins[i].name;
90                         rect.setInputPins(inputNames);
91
92                         int outputCount = ((Number) m.get(SimpleRectangularSubmodelComponent.kOutCount)).intValue();
93                         String[] outputPins = new String[outputCount];
94                         for (int i = 0; i < outputCount; i++)
95                                 outputPins[i] = params.interfacePins[inputCount + i].name;
96                         rect.setOutputPins(outputPins);
97
98                         return rect;
99                 }
100                 catch (ClassCastException | NullPointerException e)
101                 {
102                         System.err.println("Failed to specialize component!");
103                         e.printStackTrace();
104                         return null;
105                 }
106         }
107
108         private static SubmodelComponent createSubmodelComponent(ViewModelModifiable model, SubmodelComponentParams params)
109         {
110                 // As SubmodelComponent is abstract, for now SubmodelComponents are instantiated as SimpleRectangularSubmodelComponents
111                 SubmodelComponent comp = new SimpleRectangularSubmodelComponent(model, 0, "");
112                 comp.setSubmodelScale(params.composition.innerScale);
113                 comp.setSize(params.width, params.height);
114                 for (InterfacePinParams iPinParams : params.interfacePins)
115                 {
116                         comp.addSubmodelInterface(iPinParams.name, iPinParams.logicWidth, iPinParams.location.x, iPinParams.location.y);
117                 }
118                 return comp;
119         }
120
121         @SuppressWarnings("unused")
122         private static void initInnerComponents(SubmodelComponent comp, ComponentCompositionParams params)
123         {
124                 try
125                 {
126                         GUIComponent[] components = new GUIComponent[params.subComps.length];
127                         for (int i = 0; i < components.length; i++)
128                         {
129                                 InnerComponentParams cParams = params.subComps[i];
130                                 String path = cParams.type;
131                                 if (path.startsWith("class:"))
132                                 {
133                                         path = path.substring(6);
134                                         components[i] = createInnerComponentFromClass(comp, path, cParams.params);
135                                         components[i].moveTo(cParams.pos.x, cParams.pos.y);
136                                 } else if (path.startsWith("file:"))
137                                 {
138                                         path = path.substring(5);
139                                         components[i] = create(comp.submodelModifiable, path);
140                                         components[i].moveTo(cParams.pos.x, cParams.pos.y);
141                                 } else
142                                         throw new IllegalArgumentException("Invalid submodel type! Type was neither prefixed by 'class:' nor by 'file:'");
143                         }
144
145                         for (int i = 0; i < params.innerWires.length; i++)
146                         {
147                                 InnerWireParams innerWire = params.innerWires[i];
148                                 new GUIWire(comp.submodelModifiable,
149                                                 comp.submodelModifiable.getComponents().get(innerWire.pin1.compId).getPin(innerWire.pin1.pinName),
150                                                 comp.submodelModifiable.getComponents().get(innerWire.pin2.compId).getPin(innerWire.pin2.pinName), innerWire.path);
151                         }
152                 }
153                 catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | SecurityException
154                                 | ClassNotFoundException | IllegalArgumentException e)
155                 {
156                         System.err.println("Failed to initialize custom component!");
157                         e.printStackTrace();
158                 }
159         }
160
161         private static GUIComponent createInnerComponentFromClass(SubmodelComponent parent, String classname, Map<String, Object> params)
162                         throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException,
163                         ClassNotFoundException
164         {
165                 Class<?> c = Class.forName(classname);
166                 Object comp;
167                 if (SimpleRectangularGUIGate.class.isAssignableFrom(c) || WireCrossPoint.class.equals(c))
168                 {
169                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class, int.class);
170                         comp = constructor.newInstance(parent.submodelModifiable,
171                                         ((Number) params.get(SimpleRectangularGUIGate.kLogicWidth)).intValue());
172                 } else
173                 {
174                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class);
175                         comp = constructor.newInstance(parent.submodelModifiable);
176                 }
177                 return (GUIComponent) comp;
178         }
179 }