1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.databind.model.impl;
7   
8   import java.util.List;
9   
10  import dev.metaschema.core.datatype.markup.MarkupMultiline;
11  import dev.metaschema.core.model.AbstractChoiceInstance;
12  import dev.metaschema.core.model.DefaultChoiceModelBuilder;
13  import dev.metaschema.core.model.IAssemblyInstanceAbsolute;
14  import dev.metaschema.core.model.IContainerModelSupport;
15  import dev.metaschema.core.model.IFieldInstanceAbsolute;
16  import dev.metaschema.core.model.IModelInstanceAbsolute;
17  import dev.metaschema.core.model.IModule;
18  import dev.metaschema.core.model.INamedModelInstanceAbsolute;
19  import dev.metaschema.databind.model.IBoundDefinitionModelAssembly;
20  import dev.metaschema.databind.model.IBoundInstanceModelAssembly;
21  import dev.metaschema.databind.model.IBoundInstanceModelField;
22  import dev.metaschema.databind.model.IBoundInstanceModelNamed;
23  import edu.umd.cs.findbugs.annotations.NonNull;
24  import edu.umd.cs.findbugs.annotations.Nullable;
25  
26  /**
27   * Represents a choice instance for annotation-based bound definitions.
28   * <p>
29   * A choice contains mutually exclusive model instance alternatives. This class
30   * is used for annotation-based bindings (classes with {@code @BoundChoice}
31   * annotations).
32   */
33  /**
34   * Implementation of a choice instance within a bound model.
35   * <p>
36   * This class represents a choice between multiple model instances in a
37   * Metaschema assembly.
38   */
39  public final class BoundInstanceModelChoice
40      extends AbstractChoiceInstance<
41          IBoundDefinitionModelAssembly,
42          IModelInstanceAbsolute,
43          INamedModelInstanceAbsolute,
44          IFieldInstanceAbsolute,
45          IAssemblyInstanceAbsolute> {
46  
47    @NonNull
48    private final String choiceId;
49    @NonNull
50    private final IContainerModelSupport<
51        IModelInstanceAbsolute,
52        INamedModelInstanceAbsolute,
53        IFieldInstanceAbsolute,
54        IAssemblyInstanceAbsolute> modelContainer;
55  
56    /**
57     * Construct a new choice instance from a list of named model instances.
58     *
59     * @param choiceId
60     *          the identifier for this choice
61     * @param parent
62     *          the containing assembly definition
63     * @param instances
64     *          the list of named model instances that are alternatives in this
65     *          choice
66     */
67    public BoundInstanceModelChoice(
68        @NonNull String choiceId,
69        @NonNull IBoundDefinitionModelAssembly parent,
70        @NonNull List<IBoundInstanceModelNamed<?>> instances) {
71      super(parent);
72      this.choiceId = choiceId;
73      this.modelContainer = buildModelContainer(instances);
74    }
75  
76    @NonNull
77    private static IContainerModelSupport<
78        IModelInstanceAbsolute,
79        INamedModelInstanceAbsolute,
80        IFieldInstanceAbsolute,
81        IAssemblyInstanceAbsolute> buildModelContainer(
82            @NonNull List<IBoundInstanceModelNamed<?>> instances) {
83      if (instances.isEmpty()) {
84        return IContainerModelSupport.empty();
85      }
86  
87      DefaultChoiceModelBuilder<
88          IModelInstanceAbsolute,
89          INamedModelInstanceAbsolute,
90          IFieldInstanceAbsolute,
91          IAssemblyInstanceAbsolute> builder = new DefaultChoiceModelBuilder<>();
92  
93      for (IBoundInstanceModelNamed<?> instance : instances) {
94        if (instance instanceof IBoundInstanceModelField) {
95          builder.append((IFieldInstanceAbsolute) instance);
96        } else if (instance instanceof IBoundInstanceModelAssembly) {
97          builder.append((IAssemblyInstanceAbsolute) instance);
98        }
99      }
100 
101     return builder.buildChoice();
102   }
103 
104   /**
105    * Get the choice identifier for this choice instance.
106    *
107    * @return the choice identifier
108    */
109   @NonNull
110   public String getChoiceId() {
111     return choiceId;
112   }
113 
114   @Override
115   public IContainerModelSupport<
116       IModelInstanceAbsolute,
117       INamedModelInstanceAbsolute,
118       IFieldInstanceAbsolute,
119       IAssemblyInstanceAbsolute> getModelContainer() {
120     return modelContainer;
121   }
122 
123   /**
124    * {@inheritDoc}
125    * <p>
126    * For annotation-based bindings, choices are optional by default (minOccurs =
127    * 0). The individual alternatives have their own minOccurs constraints that
128    * apply when that alternative is selected.
129    */
130   @Override
131   public int getMinOccurs() {
132     return 0;
133   }
134 
135   @Override
136   public IModule getContainingModule() {
137     return getContainingDefinition().getContainingModule();
138   }
139 
140   @Override
141   @Nullable
142   public MarkupMultiline getRemarks() {
143     // no remarks for annotation-based bindings
144     return null;
145   }
146 }