package ru.tehkode.permissions.bukkit.regexperms;

import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.permissions.Permissible;
import ru.tehkode.permissions.PermissionManager;
import ru.tehkode.permissions.bukkit.PermissionsEx;
import ru.tehkode.permissions.events.PermissionSystemEvent;

import java.util.logging.Level;

import static ru.tehkode.permissions.bukkit.CraftBukkitInterface.getCBClassName;

/**
 * @author zml2008
 */
public class RegexPermissions {
	private final PermissionsEx plugin;
	private PermissionList permsList;
	// Permissions subscriptions handling
	private PEXPermissionSubscriptionMap subscriptionHandler;

	public RegexPermissions(PermissionsEx plugin) {
		this.plugin = plugin;
		subscriptionHandler = PEXPermissionSubscriptionMap.inject(plugin, plugin.getServer().getPluginManager());
		permsList = PermissionList.inject(plugin.getServer().getPluginManager());
		plugin.getServer().getPluginManager().registerEvents(new EventListener(), plugin);
		injectAllPermissibles();
	}

	protected static final PermissibleInjector[] injectors = new PermissibleInjector[] {
			new PermissibleInjector.ClassPresencePermissibleInjector("net.glowstone.entity.GlowHumanEntity", "permissions", true),
			new PermissibleInjector.ClassPresencePermissibleInjector("org.getspout.server.entity.SpoutHumanEntity", "permissions", true),
			new PermissibleInjector.ClassNameRegexPermissibleInjector("org.getspout.spout.player.SpoutCraftPlayer", "perm", false, "org\\.getspout\\.spout\\.player\\.SpoutCraftPlayer"),
			new PermissibleInjector.ClassPresencePermissibleInjector(getCBClassName("entity.CraftHumanEntity"), "perm", true),
	};

	public void onDisable() {
		subscriptionHandler.uninject();
		uninjectAllPermissibles();
	}

	public boolean hasDebugMode() {
		PermissionManager manager = plugin.getPermissionsManager();
		return manager != null && manager.isDebug();
	}

	public PermissionList getPermissionList() {
		return permsList;
	}

	public void injectPermissible(Player player) {
		if (player.hasPermission("permissionsex.disabled")) { // this user shouldn't get permissionsex matching
			System.out.println("User has permissionsex.disable set, do not register!");
			return;
		}

		try {
			PermissiblePEX permissible = new PermissiblePEX(player, plugin);

			boolean success = false, found = false;
			for (PermissibleInjector injector : injectors) {
				if (injector.isApplicable(player)) {
					found = true;
					Permissible oldPerm = injector.inject(player, permissible);
					if (oldPerm != null) {
						permissible.setPreviousPermissible(oldPerm);
						success = true;
						break;
					}
				}
			}

			if (!found) {
				plugin.getLogger().warning("No Permissible injector found for your server implementation!");
			} else if (!success) {
				plugin.getLogger().warning("Unable to inject PEX's permissible for " + player.getName());
			}

			permissible.recalculatePermissions();

			if (success && hasDebugMode()) {
				plugin.getLogger().info("Permissions handler for " + player.getName() + " successfully injected");
			}
		} catch (Throwable e) {
			plugin.getLogger().log(Level.SEVERE, "Unable to inject permissible for " + player.getName(), e);
		}
	}

	private void injectAllPermissibles() {
		for (Player player : plugin.getServer().getOnlinePlayers()) {
			injectPermissible(player);
		}
	}

	private void uninjectPermissible(Player player) {
		if (player.hasPermission("permissionsex.disabled")) { // this user shouldn't get permissionsex matching
			return;
		}

		try {
			boolean success = false;
			for (PermissibleInjector injector : injectors) {
				if (injector.isApplicable(player)) {
					Permissible pexPerm = injector.getPermissible(player);
					if (pexPerm instanceof PermissiblePEX) {
						if (injector.inject(player, ((PermissiblePEX) pexPerm).getPreviousPermissible()) != null) {
							success = true;
							break;
						}
					}
				}
			}

			if (!success) {
				plugin.getLogger().warning("No Permissible injector found for your server implementation (while uninjecting for " + player.getName() + "!");
			} else if (hasDebugMode()) {
				plugin.getLogger().info("Permissions handler for " + player.getName() + " successfully uninjected");
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	private void uninjectAllPermissibles() {
		for (Player player : plugin.getServer().getOnlinePlayers()) {
			injectPermissible(player);
		}
	}

	private class EventListener implements Listener {
		@EventHandler(priority = EventPriority.LOWEST)
		public void onPlayerLogin(PlayerLoginEvent event) {
			System.out.println("Injecting permissible for " + event.getPlayer().getName());
			injectPermissible(event.getPlayer());
		}

		@EventHandler(priority = EventPriority.MONITOR)
		// Technically not supposed to use MONITOR for this, but we don't want to remove before other plugins are done checking permissions
		public void onPlayerQuit(PlayerQuitEvent event) {
			uninjectPermissible(event.getPlayer());
		}

		@EventHandler(priority = EventPriority.LOWEST)
		public void onPermissionSystemEvent(PermissionSystemEvent event) {
			switch (event.getAction()) {
				case REINJECT_PERMISSIBLES:
				case RELOADED:
					uninjectAllPermissibles();
					injectAllPermissibles();
					break;
				default:
					return;
			}
		}
	}

}

@@ -2312,87 +2312,8 @@
 ing%0A
-%09%09%09System.out.println(%22User has permissionsex.disable set, do not register!%22);%0A
 %09%09%09r
@@ -4692,91 +4692,8 @@
 ) %7B%0A
-%09%09%09System.out.println(%22Injecting permissible for %22 + event.getPlayer().getName());%0A
 %09%09%09i

remove debug