summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnits/utils/NameSymbol.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/sevenUnits/utils/NameSymbol.java')
-rw-r--r--src/main/java/sevenUnits/utils/NameSymbol.java308
1 files changed, 308 insertions, 0 deletions
diff --git a/src/main/java/sevenUnits/utils/NameSymbol.java b/src/main/java/sevenUnits/utils/NameSymbol.java
new file mode 100644
index 0000000..7ef2967
--- /dev/null
+++ b/src/main/java/sevenUnits/utils/NameSymbol.java
@@ -0,0 +1,308 @@
+/**
+ * Copyright (C) 2019 Adrien Hopkins
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package sevenUnits.utils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A class that can be used to specify names and a symbol for a unit.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-10-21
+ */
+public final class NameSymbol {
+ public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(),
+ Optional.empty(), new HashSet<>());
+
+ /**
+ * Creates a {@code NameSymbol}, ensuring that if primaryName is null and
+ * otherNames is not empty, one name is moved from otherNames to primaryName
+ *
+ * Ensure that otherNames is not a copy of the inputted argument.
+ */
+ private static final NameSymbol create(final String name,
+ final String symbol, final Set<String> otherNames) {
+ final Optional<String> primaryName;
+
+ if (name == null && !otherNames.isEmpty()) {
+ // get primary name and remove it from savedNames
+ final Iterator<String> it = otherNames.iterator();
+ assert it.hasNext();
+ primaryName = Optional.of(it.next());
+ otherNames.remove(primaryName.get());
+ } else {
+ primaryName = Optional.ofNullable(name);
+ }
+
+ return new NameSymbol(primaryName, Optional.ofNullable(symbol),
+ otherNames);
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and no other
+ * names.
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if name or symbol is null
+ */
+ public static final NameSymbol of(final String name, final String symbol) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>());
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol,
+ final Set<String> otherNames) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>(Objects.requireNonNull(otherNames,
+ "otherNames must not be null.")));
+ }
+
+ /**
+ * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol,
+ final String... otherNames) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames,
+ "otherNames must not be null."))));
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, no symbol, and no other
+ * names.
+ *
+ * @param name name to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if name is null
+ */
+ public static final NameSymbol ofName(final String name) {
+ return new NameSymbol(Optional.of(name), Optional.empty(),
+ new HashSet<>());
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ * <p>
+ * If any argument is null, this static factory replaces it with an empty
+ * Optional or empty Set.
+ * <p>
+ * If {@code name} is null and {@code otherNames} is not empty, a primary
+ * name will be picked from {@code otherNames}. This name will not appear in
+ * getOtherNames().
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-11-26
+ */
+ public static final NameSymbol ofNullable(final String name,
+ final String symbol, final Set<String> otherNames) {
+ return NameSymbol.create(name, symbol,
+ otherNames == null ? new HashSet<>() : new HashSet<>(otherNames));
+ }
+
+ /**
+ * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ * <p>
+ * If any argument is null, this static factory replaces it with an empty
+ * Optional or empty Set.
+ * <p>
+ * If {@code name} is null and {@code otherNames} is not empty, a primary
+ * name will be picked from {@code otherNames}. This name will not appear in
+ * getOtherNames().
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-11-26
+ */
+ public static final NameSymbol ofNullable(final String name,
+ final String symbol, final String... otherNames) {
+ return create(name, symbol, otherNames == null ? new HashSet<>()
+ : new HashSet<>(Arrays.asList(otherNames)));
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a symbol and no names.
+ *
+ * @param symbol symbol to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if symbol is null
+ */
+ public static final NameSymbol ofSymbol(final String symbol) {
+ return new NameSymbol(Optional.empty(), Optional.of(symbol),
+ new HashSet<>());
+ }
+
+ private final Optional<String> primaryName;
+ private final Optional<String> symbol;
+
+ private final Set<String> otherNames;
+
+ /**
+ * Creates the {@code NameSymbol}.
+ *
+ * @param primaryName primary name of unit
+ * @param symbol symbol used to represent unit
+ * @param otherNames other names and/or spellings, should be a mutable copy
+ * of the argument
+ * @since 2019-10-21
+ */
+ private NameSymbol(final Optional<String> primaryName,
+ final Optional<String> symbol, final Set<String> otherNames) {
+ this.primaryName = primaryName;
+ this.symbol = symbol;
+ otherNames.remove(null);
+ this.otherNames = Collections.unmodifiableSet(otherNames);
+
+ if (this.primaryName.isEmpty()) {
+ assert this.otherNames.isEmpty();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof NameSymbol))
+ return false;
+ final NameSymbol other = (NameSymbol) obj;
+ if (this.otherNames == null) {
+ if (other.otherNames != null)
+ return false;
+ } else if (!this.otherNames.equals(other.otherNames))
+ return false;
+ if (this.primaryName == null) {
+ if (other.primaryName != null)
+ return false;
+ } else if (!this.primaryName.equals(other.primaryName))
+ return false;
+ if (this.symbol == null) {
+ if (other.symbol != null)
+ return false;
+ } else if (!this.symbol.equals(other.symbol))
+ return false;
+ return true;
+ }
+
+ /**
+ * @return otherNames
+ * @since 2019-10-21
+ */
+ public final Set<String> getOtherNames() {
+ return this.otherNames;
+ }
+
+ /**
+ * @return primaryName
+ * @since 2019-10-21
+ */
+ public final Optional<String> getPrimaryName() {
+ return this.primaryName;
+ }
+
+ /**
+ * @return symbol
+ * @since 2019-10-21
+ */
+ public final Optional<String> getSymbol() {
+ return this.symbol;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + (this.otherNames == null ? 0 : this.otherNames.hashCode());
+ result = prime * result
+ + (this.primaryName == null ? 0 : this.primaryName.hashCode());
+ result = prime * result
+ + (this.symbol == null ? 0 : this.symbol.hashCode());
+ return result;
+ }
+
+ /**
+ * @return true iff this {@code NameSymbol} contains no names or symbols.
+ */
+ public final boolean isEmpty() {
+ // if primaryName is empty, otherNames must also be empty
+ return this.primaryName.isEmpty() && this.symbol.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ if (this.isEmpty())
+ return "NameSymbol.EMPTY";
+ else if (this.primaryName.isPresent() && this.symbol.isPresent())
+ return this.primaryName.orElseThrow() + " ("
+ + this.symbol.orElseThrow() + ")";
+ else
+ return this.primaryName.orElseGet(this.symbol::orElseThrow);
+ }
+
+ /**
+ * Creates and returns a copy of this {@code NameSymbol} with the provided
+ * extra name. If this {@code NameSymbol} has a primary name, the provided
+ * name will become an other name, otherwise it will become the primary name.
+ *
+ * @since 2022-04-19
+ */
+ public final NameSymbol withExtraName(String name) {
+ if (this.primaryName.isPresent()) {
+ final var otherNames = new HashSet<>(this.otherNames);
+ otherNames.add(name);
+ return NameSymbol.ofNullable(this.primaryName.orElse(null),
+ this.symbol.orElse(null), otherNames);
+ } else
+ return NameSymbol.ofNullable(name, this.symbol.orElse(null));
+ }
+} \ No newline at end of file