package net.minecraft.world.scores;

import java.util.AbstractList;
import net.minecraft.nbt.CompoundTag;
import java.util.function.Function;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.Entity;
import net.minecraft.ChatFormatting;
import java.util.Iterator;
import java.util.Comparator;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Consumer;
import com.google.common.collect.Lists;
import net.minecraft.network.chat.Component;
import javax.annotation.Nullable;
import com.google.common.collect.Maps;
import java.util.List;
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
import java.util.Map;

public class Scoreboard {
    private final Map<String, Objective> objectivesByName;
    private final Map<ObjectiveCriteria, List<Objective>> objectivesByCriteria;
    private final Map<String, Map<Objective, Score>> playerScores;
    private final Objective[] displayObjectives;
    private final Map<String, PlayerTeam> teamsByName;
    private final Map<String, PlayerTeam> teamsByPlayer;
    private static String[] displaySlotNames;
    
    public Scoreboard() {
        this.objectivesByName = Maps.newHashMap();
        this.objectivesByCriteria = Maps.newHashMap();
        this.playerScores = Maps.newHashMap();
        this.displayObjectives = new Objective[19];
        this.teamsByName = Maps.newHashMap();
        this.teamsByPlayer = Maps.newHashMap();
    }
    
    public boolean hasObjective(final String string) {
        return this.objectivesByName.containsKey(string);
    }
    
    public Objective getOrCreateObjective(final String string) {
        return this.objectivesByName.get(string);
    }
    
    @Nullable
    public Objective getObjective(@Nullable final String string) {
        return this.objectivesByName.get(string);
    }
    
    public Objective addObjective(final String string, final ObjectiveCriteria dfp, final Component mr, final ObjectiveCriteria.RenderType a) {
        if (string.length() > 16) {
            throw new IllegalArgumentException("The objective name '" + string + "' is too long!");
        }
        if (this.objectivesByName.containsKey(string)) {
            throw new IllegalArgumentException("An objective with the name '" + string + "' already exists!");
        }
        final Objective dfj6 = new Objective(this, string, dfp, mr, a);
        this.objectivesByCriteria.computeIfAbsent(dfp, dfp -> Lists.newArrayList()).add(dfj6);
        this.objectivesByName.put(string, dfj6);
        this.onObjectiveAdded(dfj6);
        return dfj6;
    }
    
    public final void forAllObjectives(final ObjectiveCriteria dfp, final String string, final Consumer<Score> consumer) {
        this.objectivesByCriteria.getOrDefault(dfp, Collections.<Objective>emptyList()).forEach(dfj -> consumer.accept(this.getOrCreatePlayerScore(string, dfj)));
    }
    
    public boolean hasPlayerScore(final String string, final Objective dfj) {
        final Map<Objective, Score> map4 = this.playerScores.get(string);
        if (map4 == null) {
            return false;
        }
        final Score dfl5 = map4.get(dfj);
        return dfl5 != null;
    }
    
    public Score getOrCreatePlayerScore(final String string, final Objective dfj) {
        if (string.length() > 40) {
            throw new IllegalArgumentException("The player name '" + string + "' is too long!");
        }
        final Map<Objective, Score> map4 = this.playerScores.computeIfAbsent(string, string -> Maps.newHashMap());
        final Score dfl4;
        return map4.computeIfAbsent(dfj, dfj -> {
            dfl4 = new Score(this, dfj, string);
            dfl4.setScore(0);
            return dfl4;
        });
    }
    
    public Collection<Score> getPlayerScores(final Objective dfj) {
        final List<Score> list3 = Lists.newArrayList();
        for (final Map<Objective, Score> map5 : this.playerScores.values()) {
            final Score dfl6 = map5.get(dfj);
            if (dfl6 != null) {
                list3.add(dfl6);
            }
        }
        list3.sort(Score.SCORE_COMPARATOR);
        return list3;
    }
    
    public Collection<Objective> getObjectives() {
        return this.objectivesByName.values();
    }
    
    public Collection<String> getObjectiveNames() {
        return this.objectivesByName.keySet();
    }
    
    public Collection<String> getTrackedPlayers() {
        return Lists.newArrayList(this.playerScores.keySet());
    }
    
    public void resetPlayerScore(final String string, @Nullable final Objective dfj) {
        if (dfj == null) {
            final Map<Objective, Score> map4 = this.playerScores.remove(string);
            if (map4 != null) {
                this.onPlayerRemoved(string);
            }
        }
        else {
            final Map<Objective, Score> map4 = this.playerScores.get(string);
            if (map4 != null) {
                final Score dfl5 = map4.remove(dfj);
                if (map4.size() < 1) {
                    final Map<Objective, Score> map5 = this.playerScores.remove(string);
                    if (map5 != null) {
                        this.onPlayerRemoved(string);
                    }
                }
                else if (dfl5 != null) {
                    this.onPlayerScoreRemoved(string, dfj);
                }
            }
        }
    }
    
    public Map<Objective, Score> getPlayerScores(final String string) {
        Map<Objective, Score> map3 = this.playerScores.get(string);
        if (map3 == null) {
            map3 = Maps.newHashMap();
        }
        return map3;
    }
    
    public void removeObjective(final Objective dfj) {
        this.objectivesByName.remove(dfj.getName());
        for (int integer3 = 0; integer3 < 19; ++integer3) {
            if (this.getDisplayObjective(integer3) == dfj) {
                this.setDisplayObjective(integer3, null);
            }
        }
        final List<Objective> list3 = this.objectivesByCriteria.get(dfj.getCriteria());
        if (list3 != null) {
            list3.remove(dfj);
        }
        for (final Map<Objective, Score> map5 : this.playerScores.values()) {
            map5.remove(dfj);
        }
        this.onObjectiveRemoved(dfj);
    }
    
    public void setDisplayObjective(final int integer, @Nullable final Objective dfj) {
        this.displayObjectives[integer] = dfj;
    }
    
    @Nullable
    public Objective getDisplayObjective(final int integer) {
        return this.displayObjectives[integer];
    }
    
    public PlayerTeam getPlayerTeam(final String string) {
        return this.teamsByName.get(string);
    }
    
    public PlayerTeam addPlayerTeam(final String string) {
        if (string.length() > 16) {
            throw new IllegalArgumentException("The team name '" + string + "' is too long!");
        }
        PlayerTeam dfk3 = this.getPlayerTeam(string);
        if (dfk3 != null) {
            throw new IllegalArgumentException("A team with the name '" + string + "' already exists!");
        }
        dfk3 = new PlayerTeam(this, string);
        this.teamsByName.put(string, dfk3);
        this.onTeamAdded(dfk3);
        return dfk3;
    }
    
    public void removePlayerTeam(final PlayerTeam dfk) {
        this.teamsByName.remove(dfk.getName());
        for (final String string4 : dfk.getPlayers()) {
            this.teamsByPlayer.remove(string4);
        }
        this.onTeamRemoved(dfk);
    }
    
    public boolean addPlayerToTeam(final String string, final PlayerTeam dfk) {
        if (string.length() > 40) {
            throw new IllegalArgumentException("The player name '" + string + "' is too long!");
        }
        if (this.getPlayersTeam(string) != null) {
            this.removePlayerFromTeam(string);
        }
        this.teamsByPlayer.put(string, dfk);
        return dfk.getPlayers().add(string);
    }
    
    public boolean removePlayerFromTeam(final String string) {
        final PlayerTeam dfk3 = this.getPlayersTeam(string);
        if (dfk3 != null) {
            this.removePlayerFromTeam(string, dfk3);
            return true;
        }
        return false;
    }
    
    public void removePlayerFromTeam(final String string, final PlayerTeam dfk) {
        if (this.getPlayersTeam(string) != dfk) {
            throw new IllegalStateException("Player is either on another team or not on any team. Cannot remove from team '" + dfk.getName() + "'.");
        }
        this.teamsByPlayer.remove(string);
        dfk.getPlayers().remove(string);
    }
    
    public Collection<String> getTeamNames() {
        return this.teamsByName.keySet();
    }
    
    public Collection<PlayerTeam> getPlayerTeams() {
        return this.teamsByName.values();
    }
    
    @Nullable
    public PlayerTeam getPlayersTeam(final String string) {
        return this.teamsByPlayer.get(string);
    }
    
    public void onObjectiveAdded(final Objective dfj) {
    }
    
    public void onObjectiveChanged(final Objective dfj) {
    }
    
    public void onObjectiveRemoved(final Objective dfj) {
    }
    
    public void onScoreChanged(final Score dfl) {
    }
    
    public void onPlayerRemoved(final String string) {
    }
    
    public void onPlayerScoreRemoved(final String string, final Objective dfj) {
    }
    
    public void onTeamAdded(final PlayerTeam dfk) {
    }
    
    public void onTeamChanged(final PlayerTeam dfk) {
    }
    
    public void onTeamRemoved(final PlayerTeam dfk) {
    }
    
    public static String getDisplaySlotName(final int integer) {
        switch (integer) {
            case 0: {
                return "list";
            }
            case 1: {
                return "sidebar";
            }
            case 2: {
                return "belowName";
            }
            default: {
                if (integer >= 3 && integer <= 18) {
                    final ChatFormatting i2 = ChatFormatting.getById(integer - 3);
                    if (i2 != null && i2 != ChatFormatting.RESET) {
                        return "sidebar.team." + i2.getName();
                    }
                }
                return null;
            }
        }
    }
    
    public static int getDisplaySlotByName(final String string) {
        if ("list".equalsIgnoreCase(string)) {
            return 0;
        }
        if ("sidebar".equalsIgnoreCase(string)) {
            return 1;
        }
        if ("belowName".equalsIgnoreCase(string)) {
            return 2;
        }
        if (string.startsWith("sidebar.team.")) {
            final String string2 = string.substring("sidebar.team.".length());
            final ChatFormatting i3 = ChatFormatting.getByName(string2);
            if (i3 != null && i3.getId() >= 0) {
                return i3.getId() + 3;
            }
        }
        return -1;
    }
    
    public static String[] getDisplaySlotNames() {
        if (Scoreboard.displaySlotNames == null) {
            Scoreboard.displaySlotNames = new String[19];
            for (int integer1 = 0; integer1 < 19; ++integer1) {
                Scoreboard.displaySlotNames[integer1] = getDisplaySlotName(integer1);
            }
        }
        return Scoreboard.displaySlotNames;
    }
    
    public void entityRemoved(final Entity aom) {
        if (aom == null || aom instanceof Player || aom.isAlive()) {
            return;
        }
        final String string3 = aom.getStringUUID();
        this.resetPlayerScore(string3, null);
        this.removePlayerFromTeam(string3);
    }
    
    protected ListTag savePlayerScores() {
        final ListTag lk2 = new ListTag();
        final CompoundTag le3;
        final AbstractList<CompoundTag> list;
        this.playerScores.values().stream().map(Map::values).forEach(collection -> collection.stream().filter(dfl -> dfl.getObjective() != null).forEach(dfl -> {
            le3 = new CompoundTag();
            le3.putString("Name", dfl.getOwner());
            le3.putString("Objective", dfl.getObjective().getName());
            le3.putInt("Score", dfl.getScore());
            le3.putBoolean("Locked", dfl.isLocked());
            list.add(le3);
        }));
        return lk2;
    }
    
    protected void loadPlayerScores(final ListTag lk) {
        for (int integer3 = 0; integer3 < lk.size(); ++integer3) {
            final CompoundTag le4 = lk.getCompound(integer3);
            final Objective dfj5 = this.getOrCreateObjective(le4.getString("Objective"));
            String string6 = le4.getString("Name");
            if (string6.length() > 40) {
                string6 = string6.substring(0, 40);
            }
            final Score dfl7 = this.getOrCreatePlayerScore(string6, dfj5);
            dfl7.setScore(le4.getInt("Score"));
            if (le4.contains("Locked")) {
                dfl7.setLocked(le4.getBoolean("Locked"));
            }
        }
    }
}
