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

package com.hypixel.hytale.server.core.permissions.provider;

import com.google.gson.GsonBuilder;
import java.io.Writer;
import com.google.gson.stream.JsonWriter;
import java.util.function.Consumer;
import java.util.Objects;
import com.google.gson.JsonArray;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Iterator;
import com.google.gson.JsonObject;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.io.Reader;
import com.google.gson.stream.JsonReader;
import java.io.BufferedReader;
import java.util.Collections;
import java.util.Collection;
import java.util.HashSet;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.nio.file.Paths;
import java.util.UUID;
import com.google.gson.Gson;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.util.io.BlockingDiskFile;

public final class HytalePermissionsProvider extends BlockingDiskFile implements PermissionProvider
{
    @Nonnull
    public static final String DEFAULT_GROUP = "Default";
    @Nonnull
    public static final Set<String> DEFAULT_GROUP_LIST;
    @Nonnull
    public static final String OP_GROUP = "OP";
    @Nonnull
    public static final Map<String, Set<String>> DEFAULT_GROUPS;
    @Nonnull
    private static final Gson GSON;
    @Nonnull
    public static final String PERMISSIONS_FILE_PATH = "permissions.json";
    @Nonnull
    private final Map<UUID, Set<String>> userPermissions;
    @Nonnull
    private final Map<String, Set<String>> groupPermissions;
    @Nonnull
    private final Map<UUID, Set<String>> userGroups;
    
    public HytalePermissionsProvider() {
        super(Paths.get("permissions.json", new String[0]));
        this.userPermissions = new Object2ObjectOpenHashMap<UUID, Set<String>>();
        this.groupPermissions = new Object2ObjectOpenHashMap<String, Set<String>>();
        this.userGroups = new Object2ObjectOpenHashMap<UUID, Set<String>>();
    }
    
    @Nonnull
    @Override
    public String getName() {
        return "HytalePermissionsProvider";
    }
    
    @Override
    public void addUserPermissions(@Nonnull final UUID uuid, @Nonnull final Set<String> permissions) {
        this.fileLock.writeLock().lock();
        try {
            final Set<String> set = this.userPermissions.computeIfAbsent(uuid, k -> new HashSet());
            if (set.addAll(permissions)) {
                this.syncSave();
            }
        }
        finally {
            this.fileLock.writeLock().unlock();
        }
    }
    
    @Override
    public void removeUserPermissions(@Nonnull final UUID uuid, @Nonnull final Set<String> permissions) {
        this.fileLock.writeLock().lock();
        try {
            final Set<String> set = this.userPermissions.get(uuid);
            if (set != null) {
                final boolean hasChanges = set.removeAll(permissions);
                if (set.isEmpty()) {
                    this.userPermissions.remove(uuid);
                }
                if (hasChanges) {
                    this.syncSave();
                }
            }
        }
        finally {
            this.fileLock.writeLock().unlock();
        }
    }
    
    @Nonnull
    @Override
    public Set<String> getUserPermissions(@Nonnull final UUID uuid) {
        this.fileLock.readLock().lock();
        try {
            final Set<String> set = this.userPermissions.get(uuid);
            if (set == null) {
                return Collections.emptySet();
            }
            return Collections.unmodifiableSet((Set<? extends String>)set);
        }
        finally {
            this.fileLock.readLock().unlock();
        }
    }
    
    @Override
    public void addGroupPermissions(@Nonnull final String group, @Nonnull final Set<String> permissions) {
        this.fileLock.writeLock().lock();
        try {
            final Set<String> set = this.groupPermissions.computeIfAbsent(group, k -> new HashSet());
            if (set.addAll(permissions)) {
                this.syncSave();
            }
        }
        finally {
            this.fileLock.writeLock().unlock();
        }
    }
    
    @Override
    public void removeGroupPermissions(@Nonnull final String group, @Nonnull final Set<String> permissions) {
        this.fileLock.writeLock().lock();
        try {
            final Set<String> set = this.groupPermissions.get(group);
            if (set != null) {
                final boolean hasChanges = set.removeAll(permissions);
                if (set.isEmpty()) {
                    this.groupPermissions.remove(group);
                }
                if (hasChanges) {
                    this.syncSave();
                }
            }
        }
        finally {
            this.fileLock.writeLock().unlock();
        }
    }
    
    @Nonnull
    @Override
    public Set<String> getGroupPermissions(@Nonnull final String group) {
        this.fileLock.readLock().lock();
        try {
            final Set<String> set = this.groupPermissions.get(group);
            if (set == null) {
                return Collections.emptySet();
            }
            return Collections.unmodifiableSet((Set<? extends String>)set);
        }
        finally {
            this.fileLock.readLock().unlock();
        }
    }
    
    @Override
    public void addUserToGroup(@Nonnull final UUID uuid, @Nonnull final String group) {
        this.fileLock.writeLock().lock();
        try {
            final Set<String> list = this.userGroups.computeIfAbsent(uuid, k -> new HashSet());
            if (list.add(group)) {
                this.syncSave();
            }
        }
        finally {
            this.fileLock.writeLock().unlock();
        }
    }
    
    @Override
    public void removeUserFromGroup(@Nonnull final UUID uuid, @Nonnull final String group) {
        this.fileLock.writeLock().lock();
        try {
            final Set<String> list = this.userGroups.get(uuid);
            if (list != null) {
                final boolean hasChanges = list.remove(group);
                if (list.isEmpty()) {
                    this.userGroups.remove(uuid);
                }
                if (hasChanges) {
                    this.syncSave();
                }
            }
        }
        finally {
            this.fileLock.writeLock().unlock();
        }
    }
    
    @Nonnull
    @Override
    public Set<String> getGroupsForUser(@Nonnull final UUID uuid) {
        this.fileLock.readLock().lock();
        try {
            final Set<String> list = this.userGroups.get(uuid);
            if (list == null) {
                return HytalePermissionsProvider.DEFAULT_GROUP_LIST;
            }
            return Collections.unmodifiableSet((Set<? extends String>)list);
        }
        finally {
            this.fileLock.readLock().unlock();
        }
    }
    
    @Override
    protected void read(@Nonnull final BufferedReader fileReader) throws IOException {
        try (final JsonReader jsonReader = new JsonReader(fileReader)) {
            final JsonObject root = JsonParser.parseReader(jsonReader).getAsJsonObject();
            this.userPermissions.clear();
            this.groupPermissions.clear();
            this.userGroups.clear();
            Set<String> set = null;
            if (root.has("users")) {
                final JsonObject users = root.getAsJsonObject("users");
                for (final Map.Entry<String, JsonElement> entry : users.entrySet()) {
                    final UUID uuid = UUID.fromString(entry.getKey());
                    final JsonObject user = entry.getValue().getAsJsonObject();
                    if (user.has("permissions")) {
                        set = new HashSet<String>();
                        this.userPermissions.put(uuid, set);
                        user.getAsJsonArray("permissions").forEach(e -> set.add(e.getAsString()));
                    }
                    if (user.has("groups")) {
                        final Set<String> list = new HashSet<String>();
                        this.userGroups.put(uuid, list);
                        user.getAsJsonArray("groups").forEach(e -> list.add(e.getAsString()));
                    }
                }
            }
            if (root.has("groups")) {
                final JsonObject groups = root.getAsJsonObject("groups");
                for (final Map.Entry<String, JsonElement> entry : groups.entrySet()) {
                    final Set<String> set2 = new HashSet<String>();
                    this.groupPermissions.put(entry.getKey(), set2);
                    entry.getValue().getAsJsonArray().forEach(e -> set.add(e.getAsString()));
                }
            }
            for (final Map.Entry<String, Set<String>> entry2 : HytalePermissionsProvider.DEFAULT_GROUPS.entrySet()) {
                this.groupPermissions.put(entry2.getKey(), new HashSet<String>(entry2.getValue()));
            }
        }
    }
    
    @Override
    protected void write(@Nonnull final BufferedWriter fileWriter) throws IOException {
        final JsonObject root = new JsonObject();
        final JsonObject usersObj = new JsonObject();
        for (final Map.Entry<UUID, Set<String>> entry : this.userPermissions.entrySet()) {
            final JsonArray asArray = new JsonArray();
            final Set set = entry.getValue();
            final JsonArray obj = asArray;
            Objects.requireNonNull(obj);
            set.forEach(obj::add);
            final String memberName = entry.getKey().toString();
            if (!usersObj.has(memberName)) {
                usersObj.add(memberName, new JsonObject());
            }
            usersObj.getAsJsonObject(memberName).add("permissions", asArray);
        }
        for (final Map.Entry<UUID, Set<String>> entry : this.userGroups.entrySet()) {
            final JsonArray asArray = new JsonArray();
            final Set set2 = entry.getValue();
            final JsonArray obj2 = asArray;
            Objects.requireNonNull(obj2);
            set2.forEach(obj2::add);
            final String memberName = entry.getKey().toString();
            if (!usersObj.has(memberName)) {
                usersObj.add(memberName, new JsonObject());
            }
            usersObj.getAsJsonObject(memberName).add("groups", asArray);
        }
        if (!usersObj.isEmpty()) {
            root.add("users", usersObj);
        }
        final JsonObject groupsObj = new JsonObject();
        for (final Map.Entry<String, Set<String>> entry2 : this.groupPermissions.entrySet()) {
            final JsonArray asArray2 = new JsonArray();
            final Set set3 = entry2.getValue();
            final JsonArray obj3 = asArray2;
            Objects.requireNonNull(obj3);
            set3.forEach(obj3::add);
            groupsObj.add(entry2.getKey(), asArray2);
        }
        if (!groupsObj.isEmpty()) {
            root.add("groups", groupsObj);
        }
        fileWriter.write(HytalePermissionsProvider.GSON.toJson(root));
    }
    
    @Override
    protected void create(@Nonnull final BufferedWriter fileWriter) throws IOException {
        try (final JsonWriter jsonWriter = new JsonWriter(fileWriter)) {
            jsonWriter.beginObject();
            jsonWriter.endObject();
        }
    }
    
    static {
        DEFAULT_GROUP_LIST = Set.of("Default");
        DEFAULT_GROUPS = Map.ofEntries(Map.entry("OP", Set.of("*")), Map.entry("Default", Set.of()));
        GSON = new GsonBuilder().setPrettyPrinting().create();
    }
}
