001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.core.model;
007
008import java.util.Collection;
009
010import edu.umd.cs.findbugs.annotations.NonNull;
011
012/**
013 * Walks a Metaschema model. The "visit" methods can be implemented by child
014 * classes to perform processing on a visited node.
015 *
016 * @param <DATA>
017 *          state information that is carried through the walk
018 */
019public abstract class ModelWalker<DATA> {
020  /**
021   * Generate default state information.
022   *
023   * @return the state information
024   */
025  protected abstract DATA getDefaultData();
026
027  /**
028   * Will visit the provided Metaschema module flag definition.
029   *
030   * @param flag
031   *          the Metaschema module flag definition to walk
032   */
033  public void walk(@NonNull IFlagDefinition flag) {
034    walk(flag, getDefaultData());
035  }
036
037  /**
038   * Will visit the provided Metaschema module flag definition.
039   *
040   * @param flag
041   *          the Metaschema module flag definition to walk
042   * @param data
043   *          additional state information to operate on
044   */
045  public void walk(@NonNull IFlagDefinition flag, DATA data) {
046    visit(flag, data);
047  }
048
049  /**
050   * Will visit the provided Metaschema module field definition, and then walk the
051   * associated flag instances.
052   *
053   * @param field
054   *          the Metaschema module field definition to walk
055   */
056  public void walk(@NonNull IFieldDefinition field) {
057    walk(field, getDefaultData());
058  }
059
060  /**
061   * Will visit the provided Metaschema module field definition, and then walk the
062   * associated flag instances.
063   *
064   * @param field
065   *          the Metaschema module field definition to walk
066   * @param data
067   *          additional state information to operate on
068   */
069  public void walk(@NonNull IFieldDefinition field, DATA data) {
070    if (visit(field, data)) {
071      walkFlagInstances(field.getFlagInstances(), data);
072    }
073  }
074
075  /**
076   * Will visit the provided Metaschema module assembly definition, and then walk
077   * the associated flag and model instances.
078   *
079   * @param assembly
080   *          the Metaschema module assembly definition to walk
081   */
082  public void walk(@NonNull IAssemblyDefinition assembly) {
083    walk(assembly, getDefaultData());
084  }
085
086  /**
087   * Will visit the provided Metaschema module assembly definition, and then walk
088   * the associated flag and model instances.
089   *
090   * @param assembly
091   *          the Metaschema module assembly definition to walk
092   * @param data
093   *          additional state information to operate on
094   */
095  public void walk(@NonNull IAssemblyDefinition assembly, DATA data) {
096    if (visit(assembly, data)) {
097      walkFlagInstances(assembly.getFlagInstances(), data);
098      walkModelInstances(assembly.getModelInstances(), data);
099    }
100  }
101
102  /**
103   * Will visit the provided Metaschema module flag instance, and then walk the
104   * associated flag definition.
105   *
106   * @param instance
107   *          the Metaschema module flag instance to walk
108   * @param data
109   *          additional state information to operate on
110   */
111  public void walk(@NonNull IFlagInstance instance, DATA data) {
112    if (visit(instance, data)) {
113      walk(instance.getDefinition(), data);
114    }
115  }
116
117  /**
118   * Will visit the provided Metaschema module field instance, and then walk the
119   * associated field definition.
120   *
121   * @param instance
122   *          the Metaschema module field instance to walk
123   * @param data
124   *          additional state information to operate on
125   */
126  public void walk(@NonNull IFieldInstance instance, DATA data) {
127    if (visit(instance, data)) {
128      walk(instance.getDefinition(), data);
129    }
130  }
131
132  /**
133   * Will visit the provided Metaschema module assembly instance, and then walk
134   * the associated assembly definition.
135   *
136   * @param instance
137   *          the Metaschema module assembly instance to walk
138   * @param data
139   *          additional state information to operate on
140   */
141  public void walk(@NonNull IAssemblyInstance instance, DATA data) {
142    if (visit(instance, data)) {
143      walk(instance.getDefinition(), data);
144    }
145  }
146
147  /**
148   * Will visit the provided Metaschema module choice instance, and then walk the
149   * choice's child model instances.
150   *
151   * @param instance
152   *          the Metaschema module choice instance to walk
153   * @param data
154   *          additional state information to operate on
155   */
156  public void walk(@NonNull IChoiceInstance instance, DATA data) {
157    if (visit(instance, data)) {
158      walkModelInstances(instance.getModelInstances(), data);
159    }
160  }
161
162  /**
163   * Will visit the provided Metaschema module choice group instance, and then
164   * walk the choice's child model instances.
165   *
166   * @param instance
167   *          the Metaschema module choice instance to walk
168   * @param data
169   *          additional state information to operate on
170   */
171  public void walk(@NonNull IChoiceGroupInstance instance, DATA data) {
172    if (visit(instance, data)) {
173      walkModelInstances(instance.getModelInstances(), data);
174    }
175  }
176
177  /**
178   * Will walk the provided model definition.
179   *
180   * @param definition
181   *          the definition to walk
182   */
183  public void walkDefinition(@NonNull IDefinition definition) {
184    walkDefinition(definition, getDefaultData());
185  }
186
187  /**
188   * Will walk the provided model definition.
189   *
190   * @param definition
191   *          the definition to walk
192   * @param data
193   *          additional state information to operate on
194   */
195  public void walkDefinition(@NonNull IDefinition definition, DATA data) {
196    if (definition instanceof IAssemblyDefinition) {
197      walk((IAssemblyDefinition) definition, data);
198    } else if (definition instanceof IFieldDefinition) {
199      walk((IFieldDefinition) definition, data);
200    } else if (definition instanceof IFlagDefinition) {
201      walk((IFlagDefinition) definition, data);
202    }
203  }
204
205  /**
206   * Will walk each of the provided flag instances.
207   *
208   * @param instances
209   *          a collection of flag instances to visit
210   * @param data
211   *          additional state information to operate on
212   */
213  protected void walkFlagInstances(@NonNull Collection<? extends IFlagInstance> instances, DATA data) {
214    for (IFlagInstance instance : instances) {
215      assert instance != null;
216      walk(instance, data);
217    }
218  }
219
220  /**
221   * Will walk each of the provided model instances.
222   *
223   * @param instances
224   *          a collection of model instances to visit
225   * @param data
226   *          additional state information to operate on
227   */
228  protected void walkModelInstances(@NonNull Collection<? extends IModelInstance> instances, DATA data) {
229    for (IModelInstance instance : instances) {
230      assert instance != null;
231      walkModelInstance(instance, data);
232    }
233  }
234
235  /**
236   * Will walk the provided model instance.
237   *
238   * @param instance
239   *          the instance to walk
240   * @param data
241   *          additional state information to operate on
242   */
243  protected void walkModelInstance(@NonNull IModelInstance instance, DATA data) {
244    if (instance instanceof IAssemblyInstance) {
245      walk((IAssemblyInstance) instance, data);
246    } else if (instance instanceof IFieldInstance) {
247      walk((IFieldInstance) instance, data);
248    } else if (instance instanceof IChoiceGroupInstance) {
249      walk((IChoiceGroupInstance) instance, data);
250    } else if (instance instanceof IChoiceInstance) {
251      walk((IChoiceInstance) instance, data);
252    }
253  }
254
255  /**
256   * Will visit the provided model definition.
257   *
258   * @param definition
259   *          the definition to visit
260   * @param data
261   *          additional state information to operate on
262   */
263  protected void visitDefinition(@NonNull IDefinition definition, DATA data) {
264    if (definition instanceof IAssemblyDefinition) {
265      visit((IAssemblyDefinition) definition, data);
266    } else if (definition instanceof IFieldDefinition) {
267      visit((IFieldDefinition) definition, data);
268    } else if (definition instanceof IFlagDefinition) {
269      visit((IFlagDefinition) definition, data);
270    }
271  }
272
273  /**
274   * Called when the provided definition is walked. This can be overridden by
275   * child classes to enable processing of the visited definition.
276   *
277   * @param def
278   *          the definition that is visited
279   * @param data
280   *          additional state information to operate on
281   */
282  protected abstract void visit(@NonNull IFlagDefinition def, DATA data);
283
284  /**
285   * Called when the provided definition is walked. This can be overridden by
286   * child classes to enable processing of the visited definition.
287   *
288   * @param def
289   *          the definition that is visited
290   * @param data
291   *          additional state information to operate on
292   * @return {@code true} if child instances are to be walked, or {@code false}
293   *         otherwise
294   */
295  protected boolean visit(@NonNull IFieldDefinition def, DATA data) {
296    return true;
297  }
298
299  /**
300   * Called when the provided definition is walked. This can be overridden by
301   * child classes to enable processing of the visited definition.
302   *
303   * @param def
304   *          the definition that is visited
305   * @param data
306   *          additional state information to operate on
307   * @return {@code true} if child instances are to be walked, or {@code false}
308   *         otherwise
309   */
310  protected boolean visit(@NonNull IAssemblyDefinition def, DATA data) {
311    return true;
312  }
313
314  /**
315   * Called when the provided instance is walked. This can be overridden by child
316   * classes to enable processing of the visited instance.
317   *
318   * @param instance
319   *          the instance that is visited
320   * @param data
321   *          additional state information to operate on
322   * @return {@code true} if the associated definition is to be walked, or
323   *         {@code false} otherwise
324   */
325  protected boolean visit(@NonNull IFlagInstance instance, DATA data) {
326    return true;
327  }
328
329  /**
330   * Called when the provided instance is walked. This can be overridden by child
331   * classes to enable processing of the visited instance.
332   *
333   * @param instance
334   *          the instance that is visited
335   * @param data
336   *          additional state information to operate on
337   * @return {@code true} if the associated definition is to be walked, or
338   *         {@code false} otherwise
339   */
340  protected boolean visit(@NonNull IFieldInstance instance, DATA data) {
341    return true;
342  }
343
344  /**
345   * Called when the provided instance is walked. This can be overridden by child
346   * classes to enable processing of the visited instance.
347   *
348   * @param instance
349   *          the instance that is visited
350   * @param data
351   *          additional state information to operate on
352   * @return {@code true} if the associated definition is to be walked, or
353   *         {@code false} otherwise
354   */
355  protected boolean visit(@NonNull IAssemblyInstance instance, DATA data) {
356    return true;
357  }
358
359  /**
360   * Called when the provided instance is walked. This can be overridden by child
361   * classes to enable processing of the visited instance.
362   *
363   * @param instance
364   *          the instance that is visited
365   * @param data
366   *          additional state information to operate on
367   * @return {@code true} if the child instances are to be walked, or
368   *         {@code false} otherwise
369   */
370  protected boolean visit(@NonNull IChoiceInstance instance, DATA data) {
371    return true;
372  }
373
374  /**
375   * Called when the provided instance is walked. This can be overridden by child
376   * classes to enable processing of the visited instance.
377   *
378   * @param instance
379   *          the instance that is visited
380   * @param data
381   *          additional state information to operate on
382   * @return {@code true} if the child instances are to be walked, or
383   *         {@code false} otherwise
384   */
385  protected boolean visit(@NonNull IChoiceGroupInstance instance, DATA data) {
386    return true;
387  }
388}