SubmodelComponentSerializer now serializes PinUsages
[Mograsim.git] / net.mograsim.logic.model / src / net / mograsim / logic / model / serializing / SubmodelComponentSerializer.java
1 package net.mograsim.logic.model.serializing;
2
3 import java.io.IOException;
4
5 import com.google.gson.JsonElement;
6
7 import net.mograsim.logic.model.model.ViewModelModifiable;
8 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
9 import net.mograsim.logic.model.model.wires.MovablePin;
10 import net.mograsim.logic.model.model.wires.Pin;
11 import net.mograsim.logic.model.model.wires.PinUsage;
12 import net.mograsim.logic.model.serializing.SubmodelComponentParams.InterfacePinParams;
13 import net.mograsim.logic.model.snippets.HighLevelStateHandler;
14 import net.mograsim.logic.model.snippets.Renderer;
15 import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
16 import net.mograsim.logic.model.util.JsonHandler;
17 import net.mograsim.logic.model.util.Version;
18
19 /**
20  * Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
21  * 
22  * @author Fabian Stemmler
23  * @author Daniel Kirschten
24  */
25 public final class SubmodelComponentSerializer
26 {
27         // TODO set pin usages of existing components
28         public static final Version JSON_VERSION_CURRENT_SERIALIZING = Version.parseSemver("0.1.5");
29         public static final Version JSON_VERSION_LATEST_SUPPORTED_DESERIALIZING = Version.parseSemver("0.1.5");
30         public static final Version JSON_VERSION_EARLIEST_WITH_USAGE_SERIALIZED = Version.parseSemver("0.1.4");
31         // convenience methods
32
33         /**
34          * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams)}, but first reading the {@link SubmodelComponentParams} from
35          * the given file path.
36          * 
37          * @author Daniel Kirschten
38          */
39         public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath) throws IOException
40         {
41                 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class));
42         }
43
44         /**
45          * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, JsonElement)}, but first reading the
46          * {@link SubmodelComponentParams} from the given file path.
47          * 
48          * @author Daniel Kirschten
49          */
50         public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String idForSerializingOverride,
51                         JsonElement paramsForSerializingOverride) throws IOException
52         {
53                 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class), idForSerializingOverride,
54                                 paramsForSerializingOverride);
55         }
56
57         /**
58          * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String)}, but first reading the
59          * {@link SubmodelComponentParams} from the given file path.
60          * 
61          * @author Daniel Kirschten
62          */
63         public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String name) throws IOException
64         {
65                 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class), name);
66         }
67
68         /**
69          * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)}, but first reading the
70          * {@link SubmodelComponentParams} from the given file path.
71          * 
72          * @author Daniel Kirschten
73          */
74         public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String name, String idForSerializingOverride,
75                         JsonElement paramsForSerializingOverride) throws IOException
76         {
77                 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class), name, idForSerializingOverride,
78                                 paramsForSerializingOverride);
79         }
80
81         /**
82          * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} with no
83          * <code>idForSerializingOverride</code> set and using the default name.
84          * 
85          * @author Daniel Kirschten
86          */
87         public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params)
88         {
89                 return deserialize(model, params, null, null, null);
90         }
91
92         /**
93          * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} using the default name.
94          * 
95          * @author Daniel Kirschten
96          */
97         public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String idForSerializingOverride,
98                         JsonElement paramsForSerializingOverride)
99         {
100                 return deserialize(model, params, null, idForSerializingOverride, paramsForSerializingOverride);
101         }
102
103         /**
104          * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} with no
105          * <code>idForSerializingOverride</code> set.
106          * 
107          * @author Daniel Kirschten
108          */
109         public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String name)
110         {
111                 return deserialize(model, params, name, null, null);
112         }
113
114         /**
115          * Like {@link #serialize(SubmodelComponent)}, but instead of returning the generated {@link SubmodelComponentParams} they are written
116          * to a file at the given path.
117          * 
118          * @author Daniel Kirschten
119          */
120         public static void serialize(SubmodelComponent comp, String targetPath) throws IOException
121         {
122                 JsonHandler.writeJson(serialize(comp), targetPath);
123         }
124
125         /**
126          * Like {@link #serialize(SubmodelComponent, IdentifierGetter)}, but instead of returning the generated {@link SubmodelComponentParams}
127          * they are written to a file at the given path.
128          * 
129          * @author Daniel Kirschten
130          */
131         public static void serialize(SubmodelComponent comp, IdentifierGetter idGetter, String targetPath) throws IOException
132         {
133                 JsonHandler.writeJson(serialize(comp, idGetter), targetPath);
134         }
135
136         /**
137          * {@link #serialize(SubmodelComponent, IdentifierGetter)} using a default {@link IdentifierGetter} (see <code>IdentifierGetter</code>'s
138          * {@link IdentifierGetter#IdentifierGetter() default constructor})
139          * 
140          * @author Daniel Kirschten
141          */
142         public static SubmodelComponentParams serialize(SubmodelComponent comp)
143         {
144                 return serialize(comp, new IdentifierGetter());
145         }
146
147         // "core" methods
148         /**
149          * Creates a {@link SubmodelComponent} from the specified {@link SubmodelComponentParams} with the given name.
150          * <p>
151          * When serializing a <code>SubmodelComponent</code>, it is undesired for every subcomponent to be serialized with its complete inner
152          * structure. Instead, these sub-<code>SubmodelComponent</code>s should be serialized with the ID and params which were used to
153          * determine the <code>SubmodelComponentParams</code> defining the sub-<code>SubmodelComponent</code>. Because of this, it is possible
154          * to override the ID and params used in {@link #serialize(SubmodelComponent, IdentifierGetter) serialize(...)} to describe this
155          * subcomponent. See there for details.
156          * 
157          * @author Fabian Stemmler
158          * @author Daniel Kirschten
159          */
160         @SuppressWarnings("unused") // for GUIWire being created
161         public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String name,
162                         String idForSerializingOverride, JsonElement paramsForSerializingOverride)
163         {
164                 Version version = params.version;
165                 if (version.compareTo(JSON_VERSION_LATEST_SUPPORTED_DESERIALIZING) > 0)
166                         throw new IllegalArgumentException("JSON version " + version + " not supported yet");
167                 boolean hasUsageSerialized = version.compareTo(JSON_VERSION_EARLIEST_WITH_USAGE_SERIALIZED) > 0;
168                 DeserializedSubmodelComponent comp = new DeserializedSubmodelComponent(model, name, idForSerializingOverride,
169                                 paramsForSerializingOverride);
170                 comp.setSubmodelScale(params.innerScale);
171                 comp.setSize(params.width, params.height);
172                 for (InterfacePinParams iPinParams : params.interfacePins)
173                         // TRISTATE because we don't have a better choice
174                         comp.addSubmodelInterface(new MovablePin(comp, iPinParams.name, iPinParams.logicWidth,
175                                         hasUsageSerialized ? iPinParams.usage : PinUsage.TRISTATE, iPinParams.location.x, iPinParams.location.y));
176                 ViewModelModifiable submodelModifiable = comp.getSubmodelModifiable();
177                 ViewModelSerializer.deserialize(comp.getSubmodelModifiable(), params.submodel);
178                 comp.setSymbolRenderer(SubmodelComponentSnippetSuppliers.symbolRendererSupplier.getSnippetSupplier(params.symbolRendererSnippetID)
179                                 .create(comp, params.symbolRendererParams));
180                 comp.setOutlineRenderer(SubmodelComponentSnippetSuppliers.outlineRendererSupplier
181                                 .getSnippetSupplier(params.outlineRendererSnippetID).create(comp, params.outlineRendererParams));
182                 comp.setHighLevelStateHandler(SubmodelComponentSnippetSuppliers.highLevelStateHandlerSupplier
183                                 .getSnippetSupplier(params.highLevelStateHandlerSnippetID).create(comp, params.highLevelStateHandlerParams));
184                 return comp;
185         }
186
187         /**
188          * Returns {@link SubmodelComponentParams}, which describe this {@link SubmodelComponent}. <br>
189          * See {@link ViewModelSerializer#serialize(net.mograsim.logic.model.model.ViewModel, IdentifierGetter)
190          * ViewModelSerializer.serialize(...)} for how subcomponents are serialized.<br>
191          * CodeSnippets are serialized using the ID defined by <code>idGetter</code> and the params obtained by the respective
192          * <coce>getParamsForSerializing</code> methods ({@link Renderer#getParamsForSerializing()}).
193          * 
194          * @author Fabian Stemmler
195          * @author Daniel Kirschten
196          */
197         public static SubmodelComponentParams serialize(SubmodelComponent comp, IdentifierGetter idGetter)
198         {
199                 SubmodelComponentParams params = new SubmodelComponentParams(JSON_VERSION_CURRENT_SERIALIZING);
200                 params.innerScale = comp.getSubmodelScale();
201                 params.submodel = ViewModelSerializer.serialize(comp.submodel, idGetter);
202
203                 params.width = comp.getWidth();
204                 params.height = comp.getHeight();
205
206                 InterfacePinParams[] iPins = new InterfacePinParams[comp.getPins().size()];
207                 int i = 0;
208                 for (Pin p : comp.getPins().values())
209                 {
210                         InterfacePinParams iPinParams = new InterfacePinParams();
211                         iPins[i] = iPinParams;
212                         iPinParams.location = p.getRelPos();
213                         iPinParams.name = p.name;
214                         iPinParams.logicWidth = p.logicWidth;
215                         iPinParams.usage = p.usage;
216                         i++;
217                 }
218                 params.interfacePins = iPins;
219
220                 Renderer symbolRenderer = comp.getSymbolRenderer();
221                 if (symbolRenderer != null)
222                 {
223                         params.symbolRendererSnippetID = idGetter.symbolRendererIDs.apply(symbolRenderer);
224                         params.symbolRendererParams = symbolRenderer.getParamsForSerializingJSON(idGetter);
225                 }
226
227                 Renderer outlineRenderer = comp.getOutlineRenderer();
228                 if (outlineRenderer != null)
229                 {
230                         params.outlineRendererSnippetID = idGetter.outlineRendererIDs.apply(outlineRenderer);
231                         params.outlineRendererParams = outlineRenderer.getParamsForSerializingJSON(idGetter);
232                 }
233
234                 HighLevelStateHandler highLevelStateHandler = comp.getHighLevelStateHandler();
235                 if (highLevelStateHandler != null)
236                 {
237                         params.highLevelStateHandlerSnippetID = idGetter.highLevelStateHandlerIDs.apply(highLevelStateHandler);
238                         params.highLevelStateHandlerParams = highLevelStateHandler.getParamsForSerializingJSON(idGetter);
239                 }
240
241                 return params;
242         }
243 }