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

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

import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Collection;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import com.hypixel.hytale.server.core.event.events.permissions.PlayerGroupEvent;
import com.hypixel.hytale.server.core.event.events.permissions.GroupPermissionChangeEvent;
import com.hypixel.hytale.event.IEvent;
import com.hypixel.hytale.server.core.event.events.permissions.PlayerPermissionChangeEvent;
import com.hypixel.hytale.server.core.HytaleServer;
import java.util.UUID;
import java.util.Collections;
import java.util.HashSet;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.server.core.command.system.CommandManager;
import com.hypixel.hytale.server.core.command.system.CommandRegistry;
import com.hypixel.hytale.server.core.permissions.commands.PermCommand;
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.server.core.permissions.commands.op.OpCommand;
import java.util.concurrent.CopyOnWriteArrayList;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.server.core.permissions.provider.PermissionProvider;
import java.util.List;
import java.util.Set;
import java.util.Map;
import com.hypixel.hytale.server.core.permissions.provider.HytalePermissionsProvider;
import javax.annotation.Nonnull;
import com.hypixel.hytale.common.plugin.PluginManifest;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;

public class PermissionsModule extends JavaPlugin
{
    @Nonnull
    public static final PluginManifest MANIFEST;
    private static PermissionsModule instance;
    @Nonnull
    private final HytalePermissionsProvider standardProvider;
    @Nonnull
    private Map<String, Set<String>> virtualGroups;
    @Nonnull
    private final List<PermissionProvider> providers;
    
    public static PermissionsModule get() {
        return PermissionsModule.instance;
    }
    
    public PermissionsModule(@Nonnull final JavaPluginInit init) {
        super(init);
        this.standardProvider = new HytalePermissionsProvider();
        this.virtualGroups = (Map<String, Set<String>>)Object2ObjectMaps.emptyMap();
        this.providers = new CopyOnWriteArrayList<PermissionProvider>() {
            {
                ((CopyOnWriteArrayList<HytalePermissionsProvider>)this).add(PermissionsModule.this.standardProvider);
            }
        };
        PermissionsModule.instance = this;
    }
    
    @Override
    protected void setup() {
        final CommandRegistry commandRegistry = this.getCommandRegistry();
        commandRegistry.registerCommand(new OpCommand());
        commandRegistry.registerCommand(new PermCommand());
    }
    
    @Override
    protected void start() {
        final Map<String, Set<String>> virtualGroups = CommandManager.get().createVirtualPermissionGroups();
        virtualGroups.computeIfAbsent(GameMode.Creative.toString(), k -> new HashSet()).add("hytale.editor.builderTools");
        this.setVirtualGroups(virtualGroups);
        this.standardProvider.syncLoad();
    }
    
    public void addProvider(@Nonnull final PermissionProvider permissionProvider) {
        this.providers.add(permissionProvider);
    }
    
    public void removeProvider(@Nonnull final PermissionProvider provider) {
        this.providers.remove(provider);
    }
    
    @Nonnull
    public List<PermissionProvider> getProviders() {
        return Collections.unmodifiableList((List<? extends PermissionProvider>)this.providers);
    }
    
    public PermissionProvider getFirstPermissionProvider() {
        return this.providers.getFirst();
    }
    
    public boolean areProvidersTampered() {
        return this.providers.size() != 1 || this.providers.getFirst() != this.standardProvider;
    }
    
    public void addUserPermission(@Nonnull final UUID uuid, @Nonnull final Set<String> permissions) {
        this.getFirstPermissionProvider().addUserPermissions(uuid, permissions);
        HytaleServer.get().getEventBus().dispatchFor((Class<? super IEvent<Void>>)PlayerPermissionChangeEvent.PermissionsAdded.class).dispatch(new PlayerPermissionChangeEvent.PermissionsAdded(uuid, permissions));
    }
    
    public void removeUserPermission(@Nonnull final UUID uuid, @Nonnull final Set<String> permissions) {
        this.getFirstPermissionProvider().removeUserPermissions(uuid, permissions);
        HytaleServer.get().getEventBus().dispatchFor((Class<? super IEvent<Void>>)PlayerPermissionChangeEvent.PermissionsRemoved.class).dispatch(new PlayerPermissionChangeEvent.PermissionsRemoved(uuid, permissions));
    }
    
    public void addGroupPermission(@Nonnull final String group, @Nonnull final Set<String> permissions) {
        this.getFirstPermissionProvider().addGroupPermissions(group, permissions);
        HytaleServer.get().getEventBus().dispatchFor((Class<? super IEvent<Void>>)GroupPermissionChangeEvent.Added.class).dispatch(new GroupPermissionChangeEvent.Added(group, permissions));
    }
    
    public void removeGroupPermission(@Nonnull final String group, @Nonnull final Set<String> permissions) {
        this.getFirstPermissionProvider().removeGroupPermissions(group, permissions);
        HytaleServer.get().getEventBus().dispatchFor((Class<? super IEvent<Void>>)GroupPermissionChangeEvent.Removed.class).dispatch(new GroupPermissionChangeEvent.Removed(group, permissions));
    }
    
    public void addUserToGroup(@Nonnull final UUID uuid, @Nonnull final String group) {
        this.getFirstPermissionProvider().addUserToGroup(uuid, group);
        HytaleServer.get().getEventBus().dispatchFor((Class<? super IEvent<Void>>)PlayerGroupEvent.Added.class).dispatch(new PlayerGroupEvent.Added(uuid, group));
    }
    
    public void removeUserFromGroup(@Nonnull final UUID uuid, @Nonnull final String group) {
        this.getFirstPermissionProvider().removeUserFromGroup(uuid, group);
        HytaleServer.get().getEventBus().dispatchFor((Class<? super IEvent<Void>>)PlayerGroupEvent.Removed.class).dispatch(new PlayerGroupEvent.Removed(uuid, group));
    }
    
    public void setVirtualGroups(@Nonnull final Map<String, Set<String>> virtualGroups) {
        this.virtualGroups = new Object2ObjectOpenHashMap<String, Set<String>>(virtualGroups);
    }
    
    @Nonnull
    public Set<String> getGroupsForUser(@Nonnull final UUID uuid) {
        Set<String> groups = null;
        for (final PermissionProvider permissionProvider : this.providers) {
            final Set<String> providerGroups = permissionProvider.getGroupsForUser(uuid);
            if (!providerGroups.isEmpty()) {
                if (groups == null) {
                    groups = new HashSet<String>();
                }
                groups.addAll(providerGroups);
            }
        }
        return (groups != null) ? Collections.unmodifiableSet((Set<? extends String>)groups) : Collections.emptySet();
    }
    
    public boolean hasPermission(@Nonnull final UUID uuid, @Nonnull final String id) {
        return this.hasPermission(uuid, id, false);
    }
    
    public boolean hasPermission(@Nonnull final UUID uuid, @Nonnull final String id, final boolean def) {
        for (final PermissionProvider permissionProvider : this.providers) {
            final Set<String> userNodes = permissionProvider.getUserPermissions(uuid);
            final Boolean userHasPerm = hasPermission(userNodes, id);
            if (userHasPerm != null) {
                return userHasPerm;
            }
            final Set<String> groupsForUser = permissionProvider.getGroupsForUser(uuid);
            for (final String group : groupsForUser) {
                final Set<String> groupNodes = permissionProvider.getGroupPermissions(group);
                final Boolean groupHasPerm = hasPermission(groupNodes, id);
                if (groupHasPerm != null) {
                    return groupHasPerm;
                }
                final Set<String> virtualNodes = this.virtualGroups.get(group);
                final Boolean virtualHasPerm = hasPermission(virtualNodes, id);
                if (virtualHasPerm != null) {
                    return virtualHasPerm;
                }
            }
        }
        return def;
    }
    
    @Nullable
    public static Boolean hasPermission(@Nullable final Set<String> nodes, @Nonnull final String id) {
        if (nodes == null) {
            return null;
        }
        if (nodes.contains("*")) {
            return Boolean.TRUE;
        }
        if (nodes.contains("-*")) {
            return Boolean.FALSE;
        }
        if (nodes.contains(id)) {
            return Boolean.TRUE;
        }
        if (nodes.contains("-" + id)) {
            return Boolean.FALSE;
        }
        final String[] split = id.split("\\.");
        final StringBuilder completeTrace = new StringBuilder();
        for (int i = 0; i < split.length; ++i) {
            if (i > 0) {
                completeTrace.append('.');
            }
            completeTrace.append(split[i]);
            if (nodes.contains(String.valueOf(completeTrace) + ".*")) {
                return Boolean.TRUE;
            }
            if (nodes.contains("-" + completeTrace.toString() + ".*")) {
                return Boolean.FALSE;
            }
        }
        return null;
    }
    
    static {
        MANIFEST = PluginManifest.corePlugin(PermissionsModule.class).build();
    }
}
