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