1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.metapath.impl;
7   
8   import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
9   import gov.nist.secauto.metaschema.core.metapath.ICollectionValue;
10  import gov.nist.secauto.metaschema.core.metapath.ISequence;
11  import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
12  import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
13  import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
14  import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem;
15  import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem;
16  import gov.nist.secauto.metaschema.core.metapath.type.ISequenceType;
17  import gov.nist.secauto.metaschema.core.metapath.type.Occurrence;
18  import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
19  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
20  
21  import java.util.EnumSet;
22  import java.util.List;
23  import java.util.Objects;
24  import java.util.Set;
25  import java.util.stream.Collectors;
26  
27  import edu.umd.cs.findbugs.annotations.NonNull;
28  
29  /**
30   * The base class for {@link IArrayItem} implementations, that provides an
31   * implementation of common methods.
32   *
33   * @param <ITEM>
34   *          the Java type of the items contained within the sequence
35   */
36  public abstract class AbstractArrayItem<ITEM extends ICollectionValue>
37      extends ImmutableCollections.AbstractImmutableDelegatedList<ITEM>
38      implements IArrayItem<ITEM> {
39    @NonNull
40    private static final IEnhancedQName QNAME = IEnhancedQName.of("array");
41    @NonNull
42    private static final Set<FunctionProperty> PROPERTIES = ObjectUtils.notNull(
43        EnumSet.of(FunctionProperty.DETERMINISTIC));
44    @NonNull
45    private static final List<IArgument> ARGUMENTS = ObjectUtils.notNull(List.of(
46        IArgument.builder().name("position").type(IIntegerItem.type()).one().build()));
47    @NonNull
48    private static final ISequenceType RESULT = ISequenceType.of(
49        IAnyAtomicItem.type(), Occurrence.ZERO_OR_ONE);
50  
51    @NonNull
52    private static final IArrayItem<?> EMPTY = new ArrayItemN<>();
53  
54    /**
55     * Get an immutable array item that is empty.
56     *
57     * @param <T>
58     *          the item Java type
59     * @return the empty array item
60     */
61    @SuppressWarnings("unchecked")
62    @NonNull
63    public static <T extends ICollectionValue> IArrayItem<T> empty() {
64      return (IArrayItem<T>) EMPTY;
65    }
66  
67    @Override
68    public boolean isDeterministic() {
69      return true;
70    }
71  
72    @Override
73    public boolean isContextDepenent() {
74      return false;
75    }
76  
77    @Override
78    public boolean isFocusDepenent() {
79      return false;
80    }
81  
82    @Override
83    public IEnhancedQName getQName() {
84      return QNAME;
85    }
86  
87    @Override
88    public Set<FunctionProperty> getProperties() {
89      return PROPERTIES;
90    }
91  
92    @Override
93    public List<IArgument> getArguments() {
94      return ARGUMENTS;
95    }
96  
97    @Override
98    public int arity() {
99      return 1;
100   }
101 
102   @Override
103   public boolean isArityUnbounded() {
104     return false;
105   }
106 
107   @Override
108   public ISequenceType getResult() {
109     return RESULT;
110   }
111 
112   @Override
113   public ISequence<?> execute(List<? extends ISequence<?>> arguments, DynamicContext dynamicContext,
114       ISequence<?> focus) {
115     ISequence<? extends IIntegerItem> arg = FunctionUtils.asType(
116         ObjectUtils.notNull(arguments.get(0)));
117 
118     IIntegerItem position = arg.getFirstItem(true);
119     if (position == null) {
120       return ISequence.empty(); // NOPMD - readability
121     }
122 
123     int index = position.asInteger().intValueExact() - 1;
124     ICollectionValue result = getValue().get(index);
125     return result.toSequence();
126   }
127 
128   @Override
129   public int hashCode() {
130     return Objects.hash(getValue());
131   }
132 
133   @Override
134   public boolean equals(Object other) {
135     return other == this
136         || other instanceof IArrayItem && getValue().equals(((IArrayItem<?>) other).getValue());
137   }
138 
139   @Override
140   public String toSignature() {
141     return ObjectUtils.notNull(stream()
142         .map(ICollectionValue::toSignature)
143         .collect(Collectors.joining(",", "[", "]")));
144   }
145 
146   @Override
147   public String toString() {
148     return toSignature();
149   }
150 }