001package co.aikar.commands;
002
003import org.jetbrains.annotations.Nullable;
004import org.spongepowered.api.Sponge;
005import org.spongepowered.api.command.CommandSource;
006import org.spongepowered.api.entity.living.player.Player;
007
008import java.util.ArrayList;
009import java.util.Iterator;
010import java.util.List;
011import java.util.stream.Collectors;
012
013@SuppressWarnings("WeakerAccess")
014public class ACFSpongeUtil {
015    public static Player findPlayerSmart(CommandIssuer issuer, String search) {
016        CommandSource requester = issuer.getIssuer();
017        if (search == null) {
018            return null;
019        }
020        String name = ACFUtil.replace(search, ":confirm", "");
021
022        List<Player> matches = matchPlayer(name);
023        List<Player> confirmList = new ArrayList<>();
024        findMatches(search, requester, matches, confirmList);
025
026
027        if (matches.size() > 1 || confirmList.size() > 1) {
028            String allMatches = matches.stream().map(Player::getName).collect(Collectors.joining(", "));
029            issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH,
030                    "{search}", name, "{all}", allMatches);
031            return null;
032        }
033
034        if (matches.isEmpty()) {
035            if (!issuer.getManager().isValidName(name)) {
036                issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name);
037                return null;
038            }
039            Player player = ACFUtil.getFirstElement(confirmList);
040            if (player == null) {
041                issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER, "{search}", name);
042                return null;
043            } else {
044
045                issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName());
046                return null;
047            }
048        }
049
050        return matches.get(0);
051    }
052
053    private static void findMatches(String search, CommandSource requester, List<Player> matches, List<Player> confirmList) {
054        // Remove vanished players from smart matching.
055        Iterator<Player> iter = matches.iterator();
056        //noinspection Duplicates
057        while (iter.hasNext()) {
058            Player player = iter.next();
059            if (requester instanceof Player && !((Player) requester).canSee(player)) {
060                if (requester.hasPermission("acf.seevanish")) {
061                    if (!search.endsWith(":confirm")) {
062                        confirmList.add(player);
063                        iter.remove();
064                    }
065                } else {
066                    iter.remove();
067                }
068            }
069        }
070    }
071
072    public static List<Player> matchPlayer(String partialName) {
073        List<Player> matchedPlayers = new ArrayList<>();
074
075        for (Player iterPlayer : Sponge.getServer().getOnlinePlayers()) {
076            String iterPlayerName = iterPlayer.getName();
077
078            if (partialName.equalsIgnoreCase(iterPlayerName)) {
079                // Exact match
080                matchedPlayers.clear();
081                matchedPlayers.add(iterPlayer);
082                break;
083            }
084            if (iterPlayerName.toLowerCase(java.util.Locale.ENGLISH).contains(partialName.toLowerCase(java.util.Locale.ENGLISH))) {
085                // Partial match
086                matchedPlayers.add(iterPlayer);
087            }
088        }
089
090        return matchedPlayers;
091    }
092
093    public static boolean isValidName(@Nullable String name) {
094        return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches();
095    }
096
097}