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

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

import java.util.Collections;
import java.util.function.Function;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.io.Writer;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.Iterator;
import com.google.gson.JsonArray;
import java.io.BufferedWriter;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonObject;
import java.io.Reader;
import com.google.gson.JsonParser;
import java.io.BufferedReader;
import java.util.HashSet;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.nio.file.Paths;
import java.util.UUID;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.util.io.BlockingDiskFile;

public class HytaleWhitelistProvider extends BlockingDiskFile implements AccessProvider
{
    @Nonnull
    private static final String WHITELIST_FILE_PATH = "whitelist.json";
    @Nonnull
    private final ReadWriteLock lock;
    @Nonnull
    private final Set<UUID> whitelist;
    private boolean isEnabled;
    
    public HytaleWhitelistProvider() {
        super(Paths.get("whitelist.json", new String[0]));
        this.lock = new ReentrantReadWriteLock();
        this.whitelist = new HashSet<UUID>();
    }
    
    @Override
    protected void read(@Nonnull final BufferedReader fileReader) {
        final JsonElement element = JsonParser.parseReader(fileReader);
        if (element instanceof final JsonObject jsonObject) {
            this.isEnabled = jsonObject.get("enabled").getAsBoolean();
            jsonObject.get("list").getAsJsonArray().forEach(entry -> this.whitelist.add(UUID.fromString(entry.getAsString())));
            return;
        }
        throw new JsonParseException("element is not JsonObject!");
    }
    
    @Override
    protected void write(@Nonnull final BufferedWriter fileWriter) throws IOException {
        final JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("enabled", this.isEnabled);
        final JsonArray jsonArray = new JsonArray();
        for (final UUID uuid : this.whitelist) {
            jsonArray.add(uuid.toString());
        }
        jsonObject.add("list", jsonArray);
        fileWriter.write(jsonObject.toString());
    }
    
    @Override
    protected void create(@Nonnull final BufferedWriter fileWriter) throws IOException {
        try (final JsonWriter jsonWriter = new JsonWriter(fileWriter)) {
            jsonWriter.beginObject().name("enabled").value(false).name("list").beginArray().endArray().endObject();
        }
    }
    
    @Nonnull
    @Override
    public CompletableFuture<Optional<String>> getDisconnectReason(final UUID uuid) {
        this.lock.readLock().lock();
        try {
            if (this.isEnabled && !this.whitelist.contains(uuid)) {
                return CompletableFuture.completedFuture(Optional.of("You are not whitelisted!"));
            }
        }
        finally {
            this.lock.readLock().unlock();
        }
        return CompletableFuture.completedFuture(Optional.empty());
    }
    
    public void setEnabled(final boolean isEnabled) {
        this.lock.writeLock().lock();
        try {
            this.isEnabled = isEnabled;
        }
        finally {
            this.lock.writeLock().unlock();
        }
    }
    
    public boolean modify(@Nonnull final Function<Set<UUID>, Boolean> consumer) {
        this.lock.writeLock().lock();
        boolean result;
        try {
            result = consumer.apply(this.whitelist);
        }
        finally {
            this.lock.writeLock().unlock();
        }
        if (result) {
            this.syncSave();
        }
        return result;
    }
    
    @Nonnull
    public Set<UUID> getList() {
        this.lock.readLock().lock();
        try {
            return Collections.unmodifiableSet((Set<? extends UUID>)this.whitelist);
        }
        finally {
            this.lock.readLock().unlock();
        }
    }
    
    public boolean isEnabled() {
        this.lock.readLock().lock();
        try {
            return this.isEnabled;
        }
        finally {
            this.lock.readLock().unlock();
        }
    }
}
