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 java.nio.ByteBuffer;
9   
10  import dev.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
11  import dev.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
12  import dev.metaschema.core.metapath.item.atomic.impl.HexBinaryItem;
13  import dev.metaschema.core.metapath.item.atomic.impl.IBinaryItem;
14  import dev.metaschema.core.metapath.type.IAtomicOrUnionType;
15  import dev.metaschema.core.metapath.type.InvalidTypeMetapathException;
16  import edu.umd.cs.findbugs.annotations.NonNull;
17  
18  /**
19   * An atomic Metapath item containing a Base64 encoded data value.
20   */
21  public interface IHexBinaryItem extends IBinaryItem {
22    /**
23     * Get the type information for this item.
24     *
25     * @return the type information
26     */
27    @NonNull
28    static IAtomicOrUnionType<IHexBinaryItem> type() {
29      return MetaschemaDataTypeProvider.HEX_BINARY.getItemType();
30    }
31  
32    @Override
33    default IAtomicOrUnionType<IHexBinaryItem> getType() {
34      return type();
35    }
36  
37    /**
38     * Construct a new base64 byte sequence item using the provided base64 encoded
39     * string {@code value}.
40     *
41     * @param value
42     *          a string representing base64 encoded data
43     * @return the new item
44     * @throws InvalidTypeMetapathException
45     *           if the provided string is not a valid Base64 character sequence
46     */
47    @NonNull
48    static IHexBinaryItem valueOf(@NonNull String value) {
49      try {
50        return valueOf(MetaschemaDataTypeProvider.BASE64.parse(value));
51      } catch (IllegalArgumentException ex) {
52        throw new InvalidTypeMetapathException(
53            null,
54            String.format("The value starting with '%s' is not a valid hex encoded character sequence. %s",
55                value.substring(0, Math.min(value.length(), 200)),
56                ex.getLocalizedMessage()),
57            ex);
58      }
59    }
60  
61    /**
62     * Construct a new URI base64 encoded byte sequence using the provided
63     * {@link ByteBuffer} {@code value}.
64     * <p>
65     * The provided buffer will be managed by this instance. Make a copy of the
66     * buffer to ensure that the position, limit, and mark of the original are not
67     * affect by this.
68     *
69     * @param buffer
70     *          a byte buffer
71     * @return the new item
72     */
73    @NonNull
74    static IHexBinaryItem valueOf(@NonNull ByteBuffer buffer) {
75      return new HexBinaryItem(buffer);
76    }
77  
78    /**
79     * Cast the provided type to this item type.
80     *
81     * @param item
82     *          the item to cast
83     * @return the original item if it is already this type, otherwise a new item
84     *         cast to this type
85     * @throws InvalidValueForCastFunctionException
86     *           if the provided {@code item} cannot be cast to this type
87     */
88    @NonNull
89    static IHexBinaryItem cast(@NonNull IAnyAtomicItem item) {
90      try {
91        return item instanceof IHexBinaryItem
92            ? (IHexBinaryItem) item
93            : valueOf(item.asString());
94      } catch (IllegalStateException | InvalidTypeMetapathException ex) {
95        // asString can throw IllegalStateException exception
96        throw new InvalidValueForCastFunctionException(ex);
97      }
98    }
99  
100   @Override
101   default IHexBinaryItem castAsType(IAnyAtomicItem item) {
102     return cast(item);
103   }
104 
105   /**
106    * Compares this value with the argument.
107    *
108    * @param item
109    *          the item to compare with this value
110    * @return a negative integer, zero, or a positive integer if this value is less
111    *         than, equal to, or greater than the {@code item}.
112    */
113   default int compareTo(@NonNull IHexBinaryItem item) {
114     return asByteBuffer().compareTo(item.asByteBuffer());
115   }
116 }