001/*
002 * MIT License
003 *
004 * Copyright (c) 2024 Michael Cowan
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024
025package io.blt.util;
026
027import java.util.Optional;
028
029/**
030 * Static utility methods for operating on {@code Enum}.
031 */
032public final class En {
033
034    private En() {
035        throw new IllegalAccessError("Utility class should be accessed statically and never constructed");
036    }
037
038    /**
039     * Returns the {@code enum} constant matching {@code name} as an {@link Optional}; otherwise, returns empty.
040     * The {@code name} must match exactly.
041     * <p>
042     * This method will not throw for an invalid enum name and instead will return empty.
043     * </p>
044     * e.g.,
045     * <pre>{@code
046     * of(DayOfWeek.class, "FRIDAY");    // Optional.of(DayOfWeek.FRIDAY)
047     * of(DayOfWeek.class, "friday");    // Optional.empty()
048     * of(DayOfWeek.class, "Worf");      // Optional.empty()
049     * of(DayOfWeek.class, "");          // Optional.empty()
050     * }</pre>
051     *
052     * @param type The {@link Class} object of the enum class
053     * @param name The name of the constant to return
054     * @param <E>  The type of the {@code Enum}
055     * @return an {@code Optional} containing the {@code enum} constant if found
056     * @throws NullPointerException if {@code type} or {@code name} is {@code null}
057     */
058    public static <E extends Enum<E>> Optional<E> of(Class<E> type, String name) {
059        try {
060            return Optional.of(Enum.valueOf(type, name));
061        } catch (IllegalArgumentException ignore) {
062            return Optional.empty();
063        }
064    }
065
066    /**
067     * Returns the {@code enum} constant matching {@code name} as an {@link Optional}; otherwise, returns empty.
068     * The {@code name} comparison is case-insensitive.
069     * <p>
070     * This method will not throw for an invalid enum name and instead will return empty.
071     * </p>
072     * <pre>{@code
073     * ofIgnoreCase(DayOfWeek.class, "FRIDAY");    // Optional.of(DayOfWeek.FRIDAY)
074     * ofIgnoreCase(DayOfWeek.class, "friday");    // Optional.of(DayOfWeek.FRIDAY)
075     * ofIgnoreCase(DayOfWeek.class, "Worf");      // Optional.empty()
076     * ofIgnoreCase(DayOfWeek.class, "");          // Optional.empty()
077     * }</pre>
078     *
079     * @param type The {@link Class} object of the enum class
080     * @param name The name of the constant to return
081     * @param <E>  The type of the {@code Enum}
082     * @return an {@code Optional} containing the {@code enum} constant if found
083     * @throws NullPointerException if {@code type} or {@code name} is {@code null}
084     */
085    public static <E extends Enum<E>> Optional<E> ofIgnoreCase(Class<E> type, String name) {
086        for (var element : type.getEnumConstants()) {
087            if (name.equalsIgnoreCase(element.name())) {
088                return Optional.of(element);
089            }
090        }
091        return Optional.empty();
092    }
093
094}