// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.modules.accesscontrol.provider;

import java.util.function.Function;
import java.io.Writer;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import com.google.gson.JsonElement;
import com.google.gson.JsonArray;
import java.io.BufferedWriter;
import com.google.gson.JsonObject;
import java.util.Objects;
import com.hypixel.hytale.server.core.modules.accesscontrol.AccessControlModule;
import java.io.Reader;
import com.google.gson.JsonParser;
import java.io.BufferedReader;
import javax.annotation.Nonnull;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.nio.file.Paths;
import com.hypixel.hytale.server.core.modules.accesscontrol.ban.Ban;
import java.util.UUID;
import java.util.Map;
import com.hypixel.hytale.server.core.util.io.BlockingDiskFile;

public class HytaleBanProvider extends BlockingDiskFile implements AccessProvider
{
    private final Map<UUID, Ban> bans;
    
    public HytaleBanProvider() {
        super(Paths.get("bans.json", new String[0]));
        this.bans = new Object2ObjectOpenHashMap<UUID, Ban>();
    }
    
    @Nonnull
    @Override
    public CompletableFuture<Optional<String>> getDisconnectReason(final UUID uuid) {
        Ban ban = this.bans.get(uuid);
        if (ban != null && !ban.isInEffect()) {
            this.bans.remove(uuid);
            ban = null;
        }
        if (ban != null) {
            return ban.getDisconnectReason(uuid);
        }
        return CompletableFuture.completedFuture(Optional.empty());
    }
    
    @Override
    protected void read(@Nonnull final BufferedReader fileReader) {
        JsonParser.parseReader(fileReader).getAsJsonArray().forEach(entry -> {
            final JsonObject jsonObject = entry.getAsJsonObject();
            try {
                final Ban ban = AccessControlModule.get().parseBan(jsonObject.get("type").getAsString(), jsonObject);
                Objects.requireNonNull(ban.getBy(), "Ban has null getBy");
                Objects.requireNonNull(ban.getTarget(), "Ban has null getTarget");
                if (ban.isInEffect()) {
                    this.bans.put(ban.getTarget(), ban);
                }
            }
            catch (final Exception ex) {
                throw new RuntimeException("Failed to parse ban!", ex);
            }
        });
    }
    
    @Override
    protected void write(@Nonnull final BufferedWriter fileWriter) throws IOException {
        final JsonArray array = new JsonArray();
        this.bans.forEach((key, value) -> array.add(value.toJsonObject()));
        fileWriter.write(array.toString());
    }
    
    @Override
    protected void create(@Nonnull final BufferedWriter fileWriter) throws IOException {
        try (final JsonWriter jsonWriter = new JsonWriter(fileWriter)) {
            jsonWriter.beginArray().endArray();
        }
    }
    
    public boolean hasBan(final UUID uuid) {
        this.fileLock.readLock().lock();
        try {
            return this.bans.containsKey(uuid);
        }
        finally {
            this.fileLock.readLock().unlock();
        }
    }
    
    public boolean modify(@Nonnull final Function<Map<UUID, Ban>, Boolean> function) {
        this.fileLock.writeLock().lock();
        boolean modified;
        try {
            modified = function.apply(this.bans);
        }
        finally {
            this.fileLock.writeLock().unlock();
        }
        if (modified) {
            this.syncSave();
        }
        return modified;
    }
}
