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