001/*
002 *     Copyright 2021 Siroshun09
003 *
004 *     Licensed under the Apache License, Version 2.0 (the "License");
005 *     you may not use this file except in compliance with the License.
006 *     You may obtain a copy of the License at
007 *
008 *         http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *     Unless required by applicable law or agreed to in writing, software
011 *     distributed under the License is distributed on an "AS IS" BASIS,
012 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *     See the License for the specific language governing permissions and
014 *     limitations under the License.
015 */
016
017package com.github.siroshun09.mccommand.common;
018
019import com.github.siroshun09.mccommand.common.argument.Argument;
020import org.jetbrains.annotations.Contract;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.annotations.Nullable;
023import org.jetbrains.annotations.Unmodifiable;
024
025import java.util.Arrays;
026import java.util.Collection;
027import java.util.List;
028import java.util.Objects;
029import java.util.Optional;
030
031/**
032 * A class that holds the subcommands
033 */
034public class SubCommandHolder {
035
036    private final List<Command> subCommands;
037
038    private SubCommandHolder(@NotNull Collection<Command> subCommands) {
039        this.subCommands = List.copyOf(subCommands);
040    }
041
042    /**
043     * Create a {@link SubCommandHolder} from a collection of subcommands.
044     *
045     * @param subCommands the subcommands in the holder
046     * @return a new {@link SubCommandHolder}
047     */
048    @Contract("_ -> new")
049    @NotNull
050    public static SubCommandHolder of(@NotNull Collection<Command> subCommands) {
051        Objects.requireNonNull(subCommands);
052        return new SubCommandHolder(subCommands);
053    }
054
055    /**
056     * Create a {@link SubCommandHolder} from specified subcommands.
057     *
058     * @param subCommands the subcommands in holder
059     * @return a new {@link SubCommandHolder}
060     */
061    @Contract("_ -> new")
062    @NotNull
063    public static SubCommandHolder of(@NotNull Command... subCommands) {
064        Objects.requireNonNull(subCommands);
065        return new SubCommandHolder(Arrays.asList(subCommands));
066    }
067
068    /**
069     * Gets subcommands that is included in this holder.
070     *
071     * @return the included subcommands in this holder
072     */
073    @Unmodifiable
074    @NotNull
075    public List<Command> getSubCommands() {
076        return subCommands;
077    }
078
079    /**
080     * Gets the command whose name matches the string contained in the {@link Argument}.
081     *
082     * @param argument the argument to search
083     * @return the matched command, or {@code null} if there is no match.
084     */
085    @Nullable
086    public Command search(@NotNull Argument argument) {
087        Objects.requireNonNull(argument);
088        return search(argument.get());
089    }
090
091    /**
092     * Gets the command whose name matches the string.
093     *
094     * @param str the string to search
095     * @return the matched command, or {@code null} if there is no match.
096     */
097    @Nullable
098    public Command search(@NotNull String str) {
099        return searchOptional(str).orElse(null);
100    }
101
102    /**
103     * Gets the command whose name matches the string contained in the {@link Argument}.
104     *
105     * @param argument the argument to search
106     * @return the search result
107     */
108    @NotNull
109    public Optional<Command> searchOptional(@NotNull Argument argument) {
110        Objects.requireNonNull(argument);
111        return searchOptional(argument.get());
112    }
113
114    /**
115     * Gets the command whose name matches the string.
116     *
117     * @param str the string to search
118     * @return the search result
119     */
120    @NotNull
121    public Optional<Command> searchOptional(@NotNull String str) {
122        Objects.requireNonNull(str);
123
124        Optional<Command> cmd = subCommands.stream().filter(c -> c.getName().equalsIgnoreCase(str)).findFirst();
125
126        if (cmd.isPresent()) {
127            return cmd;
128        } else {
129            return subCommands.stream()
130                    .filter(c -> c.getAliases().stream().anyMatch(a -> a.equalsIgnoreCase(str)))
131                    .findFirst();
132        }
133    }
134
135    @Override
136    public boolean equals(Object o) {
137        if (this == o) return true;
138        if (!(o instanceof SubCommandHolder)) return false;
139        SubCommandHolder that = (SubCommandHolder) o;
140        return Objects.equals(subCommands, that.subCommands);
141    }
142
143    @Override
144    public int hashCode() {
145        return Objects.hash(subCommands);
146    }
147
148    @Override
149    public String toString() {
150        return "SubCommandHolder{" +
151                "subCommands=" + subCommands +
152                '}';
153    }
154}