1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.metapath.item.atomic;
7   
8   import dev.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
9   import dev.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
10  import dev.metaschema.core.metapath.item.atomic.impl.StringItemImpl;
11  import dev.metaschema.core.metapath.type.IAtomicOrUnionType;
12  import dev.metaschema.core.metapath.type.InvalidTypeMetapathException;
13  import edu.umd.cs.findbugs.annotations.NonNull;
14  
15  /**
16   * An atomic Metapath item containing a text data value.
17   */
18  public interface IStringItem extends IAnyAtomicItem {
19    /**
20     * Get the type information for this item.
21     *
22     * @return the type information
23     */
24    @NonNull
25    static IAtomicOrUnionType<IStringItem> type() {
26      return MetaschemaDataTypeProvider.STRING.getItemType();
27    }
28  
29    @Override
30    default IAtomicOrUnionType<? extends IStringItem> getType() {
31      return type();
32    }
33  
34    /**
35     * Construct a new item using the provided string {@code value}.
36     *
37     * @param value
38     *          a string value that must conform to Metaschema string validation
39     *          rules
40     * @return the new item
41     * @throws InvalidTypeMetapathException
42     *           if the value fails string validation
43     */
44    @NonNull
45    static IStringItem valueOf(@NonNull String value) {
46      try {
47        return new StringItemImpl(MetaschemaDataTypeProvider.STRING.parse(value));
48      } catch (IllegalArgumentException ex) {
49        throw new InvalidTypeMetapathException(
50            null,
51            String.format("Invalid string value '%s'. %s",
52                value,
53                ex.getLocalizedMessage()),
54            ex);
55      }
56    }
57  
58    /**
59     * Encode this string as base64.
60     *
61     * @return the base64 encoded text
62     */
63    default IBase64BinaryItem encode() {
64      // Encode the string to Base64
65      return IBase64BinaryItem.encode(asString());
66    }
67  
68    /**
69     * Cast the provided type to this item type.
70     *
71     * @param item
72     *          the item to cast
73     * @return the original item if it is already this type, otherwise a new item
74     *         cast to this type
75     * @throws InvalidValueForCastFunctionException
76     *           if the provided {@code item} cannot be cast to this type
77     */
78    @NonNull
79    static IStringItem cast(@NonNull IAnyAtomicItem item) {
80      try {
81        return item instanceof IStringItem
82            ? (IStringItem) item
83            : valueOf(item.asString());
84      } catch (IllegalStateException ex) {
85        // asString can throw IllegalStateException exception
86        throw new InvalidValueForCastFunctionException(ex);
87      }
88    }
89  
90    @Override
91    default IStringItem asStringItem() {
92      return this;
93    }
94  
95    @Override
96    default IStringItem castAsType(IAnyAtomicItem item) {
97      return cast(item);
98    }
99  
100   /**
101    * Compares this value with the argument. Ordering is in lexical dictionary
102    * order.
103    *
104    * @param other
105    *          the item to compare with this value
106    * @return a negative integer, zero, or a positive integer if this value is less
107    *         than, equal to, or greater than the {@code item}.
108    */
109   default int compareTo(@NonNull IStringItem other) {
110     return asString().compareTo(other.asString());
111   }
112 
113   /**
114    * An implementation of <a href=
115    * "https://www.w3.org/TR/xpath-functions-31/#func-normalize-space">fn::normalize-space</a>.
116    *
117    * @return the normalized string value for this string
118    */
119   @NonNull
120   IStringItem normalizeSpace();
121 
122   /**
123    * Get the length of the string.
124    *
125    * @return the length
126    */
127   default int length() {
128     return asString().length();
129   }
130 }