1 /*
2 * Copyright 2020-2022 Foreseeti AB <https://foreseeti.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.mal_lang.langspec.builders;
18
19 import static java.util.Objects.requireNonNull;
20 import static org.mal_lang.langspec.Utils.requireIdentifier;
21
22 import jakarta.json.JsonObject;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 /**
28 * A builder for creating {@link org.mal_lang.langspec.Asset} objects.
29 *
30 * @since 1.0.0
31 */
32 public final class AssetBuilder {
33 private final String name;
34 private final MetaBuilder meta = new MetaBuilder();
35 private final String category;
36 private final boolean isAbstract;
37 private final String superAsset;
38 private final Map<String, VariableBuilder> variables = new LinkedHashMap<>();
39 private final Map<String, AttackStepBuilder> attackSteps = new LinkedHashMap<>();
40 private byte[] svgIcon = null;
41 private byte[] pngIcon = null;
42
43 /**
44 * Constructs a new {@code AssetBuilder} object.
45 *
46 * @param name the name of the asset
47 * @param category the category of the asset
48 * @param isAbstract whether the asset is abstract
49 * @param superAsset the super asset of the asset, or {@code null}
50 * @throws java.lang.NullPointerException if {@code name} or {@code category} is {@code null}
51 * @throws java.lang.IllegalArgumentException if {@code name} or {@code category} is not a valid
52 * identifier
53 * @since 1.0.0
54 */
55 public AssetBuilder(String name, String category, boolean isAbstract, String superAsset) {
56 this.name = requireIdentifier(name);
57 this.category = requireIdentifier(category);
58 this.isAbstract = isAbstract;
59 this.superAsset = superAsset;
60 }
61
62 /**
63 * Returns the name of this {@code AssetBuilder} object.
64 *
65 * @return the name of this {@code AssetBuilder} object
66 * @since 1.0.0
67 */
68 public String getName() {
69 return this.name;
70 }
71
72 /**
73 * Returns the meta info of this {@code AssetBuilder} object.
74 *
75 * @return the meta info of this {@code AssetBuilder} object
76 * @since 1.0.0
77 */
78 public MetaBuilder getMeta() {
79 return this.meta;
80 }
81
82 /**
83 * Returns the category of this {@code AssetBuilder} object.
84 *
85 * @return the category of this {@code AssetBuilder} object
86 * @since 1.0.0
87 */
88 public String getCategory() {
89 return this.category;
90 }
91
92 /**
93 * Returns whether this {@code AssetBuilder} object is abstract.
94 *
95 * @return whether this {@code AssetBuilder} object is abstract
96 * @since 1.0.0
97 */
98 public boolean isAbstract() {
99 return this.isAbstract;
100 }
101
102 /**
103 * Returns the super asset of this {@code AssetBuilder} object, or {@code null} if no super asset
104 * has been set.
105 *
106 * @return the super asset of this {@code AssetBuilder} object, or {@code null} if no super asset
107 * has been set
108 * @since 1.0.0
109 */
110 public String getSuperAsset() {
111 return this.superAsset;
112 }
113
114 /**
115 * Returns a list of all variables in this {@code AssetBuilder} object.
116 *
117 * @return a list of all variables in this {@code AssetBuilder} object
118 * @since 1.0.0
119 */
120 public List<VariableBuilder> getVariables() {
121 return List.copyOf(this.variables.values());
122 }
123
124 /**
125 * Adds a variable to this {@code AssetBuilder} object.
126 *
127 * @param variable the variable to add
128 * @return this {@code AssetBuilder} object
129 * @throws java.lang.NullPointerException if {@code variable} is {@code null}
130 * @since 1.0.0
131 */
132 public AssetBuilder addVariable(VariableBuilder variable) {
133 requireNonNull(variable);
134 this.variables.put(variable.getName(), variable);
135 return this;
136 }
137
138 /**
139 * Returns a list of all attack steps in this {@code AssetBuilder} object.
140 *
141 * @return a list of all attack steps in this {@code AssetBuilder} object
142 * @since 1.0.0
143 */
144 public List<AttackStepBuilder> getAttackSteps() {
145 return List.copyOf(this.attackSteps.values());
146 }
147
148 /**
149 * Adds an attack step to this {@code AssetBuilder} object.
150 *
151 * @param attackStep the attack step to add
152 * @return this {@code AssetBuilder} object
153 * @throws java.lang.NullPointerException if {@code attackStep} is {@code null}
154 * @since 1.0.0
155 */
156 public AssetBuilder addAttackStep(AttackStepBuilder attackStep) {
157 requireNonNull(attackStep);
158 this.attackSteps.put(attackStep.getName(), attackStep);
159 return this;
160 }
161
162 /**
163 * Returns the SVG icon of this {@code AssetBuilder} object, or {@code null} if no SVG icon has
164 * been set.
165 *
166 * @return the SVG icon of this {@code AssetBuilder} object, or {@code null} if no SVG icon has
167 * been set
168 * @since 1.0.0
169 */
170 public byte[] getSvgIcon() {
171 return this.svgIcon == null ? null : this.svgIcon.clone();
172 }
173
174 /**
175 * Sets the SVG icon of this {@code AssetBuilder} object.
176 *
177 * @param svgIcon the SVG icon to set
178 * @return this {@code AssetBuilder} object
179 * @throws java.lang.NullPointerException if {@code svgIcon} is {@code null}
180 * @since 1.0.0
181 */
182 public AssetBuilder setSvgIcon(byte[] svgIcon) {
183 this.svgIcon = requireNonNull(svgIcon).clone();
184 return this;
185 }
186
187 /**
188 * Returns the PNG icon of this {@code AssetBuilder} object, or {@code null} if no PNG icon has
189 * been set.
190 *
191 * @return the PNG icon of this {@code AssetBuilder} object, or {@code null} if no PNG icon has
192 * been set
193 * @since 1.0.0
194 */
195 public byte[] getPngIcon() {
196 return this.pngIcon == null ? null : this.pngIcon.clone();
197 }
198
199 /**
200 * Sets the PNG icon of this {@code AssetBuilder} object.
201 *
202 * @param pngIcon the PNG icon to set
203 * @return this {@code AssetBuilder} object
204 * @throws java.lang.NullPointerException if {@code pngIcon} is {@code null}
205 * @since 1.0.0
206 */
207 public AssetBuilder setPngIcon(byte[] pngIcon) {
208 this.pngIcon = requireNonNull(pngIcon).clone();
209 return this;
210 }
211
212 /**
213 * Creates a new {@code AssetBuilder} from a {@link jakarta.json.JsonObject}.
214 *
215 * @param jsonAsset the {@link jakarta.json.JsonObject}
216 * @param svgIcons the SVG icons of the language
217 * @param pngIcons the PNG icons of the language
218 * @return a new {@code AssetBuilder} from a {@link jakarta.json.JsonObject}
219 * @throws java.lang.NullPointerException if {@code jsonAsset}, {@code svgIcons}, or {@code
220 * pngIcons} is {@code null}
221 * @since 1.0.0
222 */
223 public static AssetBuilder fromJson(
224 JsonObject jsonAsset, Map<String, byte[]> svgIcons, Map<String, byte[]> pngIcons) {
225 requireNonNull(jsonAsset);
226 requireNonNull(svgIcons);
227 requireNonNull(pngIcons);
228 var builder =
229 new AssetBuilder(
230 jsonAsset.getString("name"),
231 jsonAsset.getString("category"),
232 jsonAsset.getBoolean("isAbstract"),
233 jsonAsset.isNull("superAsset") ? null : jsonAsset.getString("superAsset"));
234 builder.getMeta().fromJson(jsonAsset.getJsonObject("meta"));
235 for (var jsonVariable : jsonAsset.getJsonArray("variables")) {
236 builder.addVariable(VariableBuilder.fromJson(jsonVariable.asJsonObject()));
237 }
238 for (var jsonAttackStep : jsonAsset.getJsonArray("attackSteps")) {
239 builder.addAttackStep(AttackStepBuilder.fromJson(jsonAttackStep.asJsonObject()));
240 }
241 if (svgIcons.containsKey(builder.getName())) {
242 builder.setSvgIcon(svgIcons.get(builder.getName()));
243 }
244 if (pngIcons.containsKey(builder.getName())) {
245 builder.setPngIcon(pngIcons.get(builder.getName()));
246 }
247 return builder;
248 }
249 }