package net.minecraft.server.players;

import com.google.gson.GsonBuilder;
import org.apache.logging.log4j.LogManager;
import java.io.BufferedReader;
import net.minecraft.util.GsonHelper;
import java.io.Reader;
import java.io.BufferedWriter;
import com.google.gson.JsonElement;
import com.google.common.io.Files;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;
import net.minecraft.Util;
import com.google.gson.JsonArray;
import java.util.Collection;
import com.google.gson.JsonObject;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Lists;
import javax.annotation.Nullable;
import java.io.IOException;
import com.google.common.collect.Maps;
import java.util.Map;
import java.io.File;
import com.google.gson.Gson;
import org.apache.logging.log4j.Logger;

public abstract class StoredUserList<K, V extends StoredUserEntry<K>> {
    protected static final Logger LOGGER;
    private static final Gson GSON;
    private final File file;
    private final Map<String, V> map;
    
    public StoredUserList(final File file) {
        this.map = Maps.newHashMap();
        this.file = file;
    }
    
    public File getFile() {
        return this.file;
    }
    
    public void add(final V abs) {
        this.map.put(this.getKeyForUser(abs.getUser()), abs);
        try {
            this.save();
        }
        catch (IOException iOException3) {
            StoredUserList.LOGGER.warn("Could not save the list after adding a user.", (Throwable)iOException3);
        }
    }
    
    @Nullable
    public V get(final K object) {
        this.removeExpired();
        return this.map.get(this.getKeyForUser(object));
    }
    
    public void remove(final K object) {
        this.map.remove(this.getKeyForUser(object));
        try {
            this.save();
        }
        catch (IOException iOException3) {
            StoredUserList.LOGGER.warn("Could not save the list after removing a user.", (Throwable)iOException3);
        }
    }
    
    public void remove(final StoredUserEntry<K> abs) {
        this.remove(abs.getUser());
    }
    
    public String[] getUserList() {
        return this.map.keySet().<String>toArray(new String[this.map.size()]);
    }
    
    public boolean isEmpty() {
        return this.map.size() < 1;
    }
    
    protected String getKeyForUser(final K object) {
        return object.toString();
    }
    
    protected boolean contains(final K object) {
        return this.map.containsKey(this.getKeyForUser(object));
    }
    
    private void removeExpired() {
        final List<K> list2 = Lists.newArrayList();
        for (final V abs4 : this.map.values()) {
            if (abs4.hasExpired()) {
                list2.add(abs4.getUser());
            }
        }
        for (final K object4 : list2) {
            this.map.remove(this.getKeyForUser(object4));
        }
    }
    
    protected abstract StoredUserEntry<K> createEntry(final JsonObject jsonObject);
    
    public Collection<V> getEntries() {
        return this.map.values();
    }
    
    public void save() throws IOException {
        final JsonArray jsonArray2 = new JsonArray();
        this.map.values().stream().map(abs -> Util.<JsonObject>make(new JsonObject(), abs::serialize)).forEach(jsonArray2::add);
        try (final BufferedWriter bufferedWriter3 = Files.newWriter(this.file, StandardCharsets.UTF_8)) {
            StoredUserList.GSON.toJson(jsonArray2, bufferedWriter3);
        }
    }
    
    public void load() throws IOException {
        if (!this.file.exists()) {
            return;
        }
        try (final BufferedReader bufferedReader2 = Files.newReader(this.file, StandardCharsets.UTF_8)) {
            final JsonArray jsonArray4 = StoredUserList.GSON.<JsonArray>fromJson(bufferedReader2, JsonArray.class);
            this.map.clear();
            for (final JsonElement jsonElement6 : jsonArray4) {
                final JsonObject jsonObject7 = GsonHelper.convertToJsonObject(jsonElement6, "entry");
                final StoredUserEntry<K> abs8 = this.createEntry(jsonObject7);
                if (abs8.getUser() != null) {
                    this.map.put(this.getKeyForUser(abs8.getUser()), (V)abs8);
                }
            }
        }
    }
    
    static {
        LOGGER = LogManager.getLogger();
        GSON = new GsonBuilder().setPrettyPrinting().create();
    }
}
