package ru.tehkode.permissions.bukkit.regexperms;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import org.apache.commons.lang.Validate;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import ru.tehkode.permissions.PermissionCheckResult;
import ru.tehkode.permissions.PermissionManager;
import ru.tehkode.permissions.PermissionMatcher;
import ru.tehkode.permissions.PermissionUser;
import ru.tehkode.permissions.bukkit.ErrorReport;
import ru.tehkode.permissions.bukkit.Permission***;
import ru.tehkode.utils.FieldReplacer;
public class PermissiblePEX
extends PermissibleBase
{
private static final FieldReplacer<PermissibleBase, Map> PERMISSIONS_FIELD = new FieldReplacer(PermissibleBase.class, "permissions", Map.class);
private static final FieldReplacer<PermissibleBase, List> ATTACHMENTS_FIELD = new FieldReplacer(PermissibleBase.class, "attachments", List.class);
private static final Method CALC_CHILD_PERMS_METH;
private final Map<String, PermissionAttachmentInfo> permissions;
private final List<PermissionAttachment> attachments;
static
{
try
{
CALC_CHILD_PERMS_METH = PermissibleBase.class.getDeclaredMethod("calculateChildPermissions", new Class[] { Map.class, Boolean.TYPE, PermissionAttachment.class });
}
catch (NoSuchMethodException e)
{
throw new ExceptionInInitializerError(e);
}
CALC_CHILD_PERMS_METH.setAccessible(true);
}
private static final AtomicBoolean LAST_CALL_ERRORED = new AtomicBoolean(false);
protected final Player player;
protected final Permission*** plugin;
private Permissible previousPermissible = null;
protected final Map<String, PermissionCheckResult> cache = new ConcurrentHashMap();
private final Object permissionsLock = new Object();
public PermissiblePEX(Player player, Permission*** plugin)
{
super(player);
this.player = player;
this.plugin = plugin;
this.permissions = new LinkedHashMap()
{
public PermissionAttachmentInfo put(String k, PermissionAttachmentInfo v)
{
PermissionAttachmentInfo existing = (PermissionAttachmentInfo)get(k);
if (existing != null) {
return existing;
}
return (PermissionAttachmentInfo)super.put(k, v);
}
};
PERMISSIONS_FIELD.set(this, this.permissions);
this.attachments = ((List)ATTACHMENTS_FIELD.get(this));
recalculatePermissions();
}
public Permissible getPreviousPermissible()
{
return this.previousPermissible;
}
public void setPreviousPermissible(Permissible previousPermissible)
{
this.previousPermissible = previousPermissible;
}
public boolean isDebug()
{
boolean debug = this.plugin.isDebug();
try
{
PermissionUser user = this.plugin.getPermissionsManager().getUser(this.player);
if (user != null) {
debug |= user.isDebug();
}
}
catch (Throwable ignore) {}
return debug;
}
public boolean hasPermission(String permission)
{
PermissionCheckResult res = permissionValue(permission);
switch (2.$SwitchMap$ru$tehkode$permissions$PermissionCheckResult[res.ordinal()])
{
case 1:
case 2:
return res.toBoolean();
}
if (super.isPermissionSet(permission))
{
boolean ret = super.hasPermission(permission);
if (isDebug()) {
this.plugin.getLogger().info("User " + this.player.getName() + " checked for permission '" + permission + "', superperms-matched a value of " + ret);
}
return ret;
}
Permission perm = this.player.getServer().getPluginManager().getPermission(permission);
return perm == null ? Permission.DEFAULT_PERMISSION.getValue(this.player.isOp()) : perm.getDefault().getValue(this.player.isOp());
}
public boolean hasPermission(Permission permission)
{
PermissionCheckResult res = permissionValue(permission.getName());
switch (2.$SwitchMap$ru$tehkode$permissions$PermissionCheckResult[res.ordinal()])
{
case 1:
case 2:
return res.toBoolean();
}
if (super.isPermissionSet(permission.getName()))
{
boolean ret = super.hasPermission(permission);
if (isDebug()) {
this.plugin.getLogger().info("User " + this.player.getName() + " checked for permission '" + permission.getName() + "', superperms-matched a value of " + ret);
}
return ret;
}
return permission.getDefault().getValue(this.player.isOp());
}
public void recalculatePermissions()
{
if ((this.cache != null) && (this.permissions != null) && (this.attachments != null))
{
ListIterator<PermissionAttachment> it;
synchronized (this.permissionsLock)
{
clearPermissions();
this.cache.clear();
for (it = this.attachments.listIterator(this.attachments.size()); it.hasPrevious();)
{
PermissionAttachment attach = (PermissionAttachment)it.previous();
calculateChildPerms(attach.getPermissions(), false, attach);
}
for (Permission p : this.player.getServer().getPluginManager().getDefaultPermissions(isOp()))
{
this.permissions.put(p.getName(), new PermissionAttachmentInfo(this.player, p.getName(), null, true));
calculateChildPerms(p.getChildren(), false, null);
}
}
}
}
protected void calculateChildPerms(Map<String, Boolean> children, boolean invert, PermissionAttachment attachment)
{
try
{
CALC_CHILD_PERMS_METH.invoke(this, new Object[] { children, Boolean.valueOf(invert), attachment });
}
catch (IllegalAcces***ception e) {}catch (InvocationTargetException e)
{
throw new RuntimeException(e);
}
}
public boolean isPermissionSet(String permission)
{
return (super.isPermissionSet(permission)) || (permissionValue(permission) != PermissionCheckResult.UNDEFINED);
}
public Set<PermissionAttachmentInfo> getEffectivePermissions()
{
synchronized (this.permissionsLock)
{
return new LinkedHashSet(this.permissions.values());
}
}
private PermissionCheckResult checkSingle(String expression, String permission, boolean value)
{
if (this.plugin.getPermissionsManager().getPermissionMatcher().isMatches(expression, permission))
{
PermissionCheckResult res = PermissionCheckResult.fromBoolean(value);
if (isDebug()) {
this.plugin.getLogger().info("User " + this.player.getName() + " checked for permission '" + permission + "', regex-matched a value of " + res + " from " + expression + " (CACHE MISS)");
}
return res;
}
return PermissionCheckResult.UNDEFINED;
}
protected PermissionCheckResult permissionValue(String permission)
{
try
{
Validate.notNull(permission, "Permissions being checked must not be null!");
permission = permission.toLowerCase();
PermissionCheckResult res = (PermissionCheckResult)this.cache.get(permission);
if (res != null)
{
if (isDebug()) {
this.plugin.getLogger().info("User " + this.player.getName() + " checked for permission '" + permission + "', regex-matched a value of " + res + " from cache.");
}
return res;
}
res = PermissionCheckResult.UNDEFINED;
synchronized (this.permissionsLock)
{
for (PermissionAttachmentInfo pai : this.permissions.values()) {
if ((res = checkSingle(pai.getPermission(), permission, pai.getValue())) != PermissionCheckResult.UNDEFINED) {
break;
}
}
}
if (res == PermissionCheckResult.UNDEFINED) {
for (??? = this.plugin.getRegexPerms().getPermissionList().getParents(permission).iterator(); ???.hasNext();)
{
Object ent = (Map.Entry)???.next();
if ((res = permissionValue((String)((Map.Entry)ent).getKey())) != PermissionCheckResult.UNDEFINED)
{
res = PermissionCheckResult.fromBoolean(!(res.toBoolean() ^ ((Boolean)((Map.Entry)ent).getValue()).booleanValue()));
if (!isDebug()) {
break;
}
this.plugin.getLogger().info("User " + this.player.getName() + " checked for permission '" + permission + "', match from parent '" + (String)((Map.Entry)ent).getKey() + "' (CACHE MISS)"); break;
}
}
}
this.cache.put(permission, res);
if ((res == PermissionCheckResult.UNDEFINED) && (isDebug())) {
this.plugin.getLogger().info("User " + this.player.getName() + " checked for permission '" + permission + "', no match found (CACHE MISS)");
}
LAST_CALL_ERRORED.set(false);
return res;
}
catch (Throwable t)
{
if (LAST_CALL_ERRORED.compareAndSet(false, true)) {
ErrorReport.handleError("Permissible permissionValue for " + this.player.getName(), t);
}
}
return PermissionCheckResult.UNDEFINED;
}
}