package net.mc_pandacraft.java.plugin.pandacraftutils.afk;


import net.mc_pandacraft.java.plugin.pandacraftutils.ConfigManager;
import net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils;

import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerEggThrowEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerToggleFlightEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.event.player.PlayerToggleSprintEvent;
import org.bukkit.scheduler.BukkitRunnable;

public class CommandAfk extends BukkitRunnable implements CommandExecutor, Listener  {
	private PandacraftUtils plugin;
	private AfkPlayer[] players;

	private int timeoutAutoAfkMessage = ConfigManager.getInstance().AFK_timeoutAutoAfkMessage;
	private int timeoutAutoAfkKick = ConfigManager.getInstance().AFK_timeoutAutoAfkKick;
	
	
	public CommandAfk(PandacraftUtils pl)
	{
		plugin = pl;
		players = new AfkPlayer[plugin.getServer().getMaxPlayers()];
		
		// analyse des joueurs déjà en ligne (/reload)
		for (Player p : plugin.getServer().getOnlinePlayers())
			addPlayer(p);
		

        plugin.getCommand("afk").setExecutor(this);
        plugin.getServer().getScheduler().runTaskTimer(plugin, this, 5*20L, 20L);
        plugin.getServer().getPluginManager().registerEvents(this, plugin);
        
		
	}
	
	
	
	
	
	
	
	// ----------------------------------------
	// ------------ Commande /AFK -------------
	// ----------------------------------------
	@Override
	public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args)
	{
		boolean execute_self = false;
		boolean execute_other = false;
		Player other_player = null;
		
		if(sender instanceof Player)
		{
			if (args.length > 0)
			{
				if (((Player)sender).hasPermission("pandacraft.afk.other"))
				{
					if (plugin.getServer().getPlayer(args[0]) != null)
					{
						other_player = plugin.getServer().getPlayer(args[0]);
						execute_other = true;
					}
					else
						sender.sendMessage("§cLe joueur n'existe pas.");
				}
				else
				{
					sender.sendMessage("§cVous n'avez pas la permission d'effectuer cette action sur un autre joueur.");
				}
			}
			else
				execute_self = true;
	    }
		else
		{
			if (args.length > 0)
			{
				if (plugin.getServer().getPlayer(args[0]) != null)
				{
					other_player = plugin.getServer().getPlayer(args[0]);
					execute_other = true;
				}
				else
					sender.sendMessage("§cLe joueur n'existe pas.");
			}
			else
				sender.sendMessage("§cVeuillez indiquer un joueur.");
			
		}
		
		
		if (execute_self)
		{
			Player p = (Player)sender;
			AfkPlayer ap = getAfkPlayer(p);
			if (ap == null)
				plugin.getLogger().severe("Cant find AfkPlayer with name "+p.getName()+" when performing command /afk");
			else
				ap.performAfkCommand();
			return true;
		}
		else if (execute_other && other_player != null)
		{
			AfkPlayer ap = getAfkPlayer(other_player);
			if (ap == null)
				plugin.getLogger().severe("Cant find AfkPlayer with name "+other_player.getName()+" when performing command /afk <player>");
			ap.adminToggleAfk();
			return true;
		}
		
		
		
		
		
		return false;
	}
	
	
	
	
	
	
	
	
	
	
	

	
	// ----------------------------------------
	// ----------- Analyse Auto-AFK -----------
	// ----------------------------------------

	@Override
	public void run() {
		// methode exécutée toute les secondes
		for (AfkPlayer ap : players)
		{	// parcours de tout les joueurs
			if (ap == null)
				continue;
			
			
			if (ap.getPlayer().hasPermission("pandacraft.afk.exempt.autoafk"))
				continue;	// les joueurs exemptés de l'auto-afk sont ignorés
			
			Player p = ap.getPlayer();
			
			double timeElapsed = ap.getDurationSinceLastAction();
			
			if (!ap.isAfk() && timeElapsed > timeoutAutoAfkMessage)
				ap.setAfk(true);	// on indique le changement d'état AFK de la personne
			else if (ap.isAfk() && timeElapsed > timeoutAutoAfkKick && !p.hasPermission("pandacraft.afk.exempt.kick"))
				p.kickPlayer("Vous avez été inactif pendant plus de "+Math.floor(timeoutAutoAfkKick/60)+" minutes");
							// on kick le joueur restant trop longtemps, si il n'est pas exempt� du kick
			
			
		}
	}
	
	
	
	
	
	

	
	// ----------------------------------------
	// -------------- Evènements --------------
	// ----------------------------------------
	@EventHandler
	public void onPlayerJoin (PlayerJoinEvent event)
	{
		addPlayer(event.getPlayer());
	}

	@EventHandler
	public void onPlayerQuit (PlayerQuitEvent event)
	{
		removePlayer(event.getPlayer());
	}
	
	@EventHandler
	public void onPlayerMove (PlayerMoveEvent event)
	{
		Location from = event.getFrom();
		Location to = event.getTo();
		
		if (	(from.getPitch() == to.getPitch() && from.getYaw() == to.getYaw())
			|| 	(from.getX() == to.getX() && from.getY() == to.getY() && from.getZ() == to.getZ()))
			return;
		getAfkPlayer(event.getPlayer()).isDoingAction();
	}
	
	
	@EventHandler
	public void onPlayerCommandPreprocess (PlayerCommandPreprocessEvent event)
	{
		if (event.getPlayer().hasPermission("pandacraft.afk.exempt.commandcheck"))
			return;

		String[] split = event.getMessage().split(" ");
		if (split.length > 0 &&
					(
					   split[0].equalsIgnoreCase("/afk")
					|| split[0].equalsIgnoreCase("/away")
					|| split[0].equalsIgnoreCase("/mail")
					|| split[0].equalsIgnoreCase("/email")
					|| split[0].equalsIgnoreCase("/m")
					|| split[0].equalsIgnoreCase("/msg")
					|| split[0].equalsIgnoreCase("/t")
					|| split[0].equalsIgnoreCase("/tell")
					|| split[0].equalsIgnoreCase("/w")
					|| split[0].equalsIgnoreCase("/whisper")
					|| split[0].equalsIgnoreCase("/r")
					|| split[0].equalsIgnoreCase("/reply")
					)
			)
				return;
		
		
		getAfkPlayer(event.getPlayer()).isDoingAction();
	}
	
	@EventHandler
	public void onPlayerInteract (PlayerInteractEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}
	
	@EventHandler
	public void onPlayerInteractEntity (PlayerInteractEntityEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}
	
	@EventHandler
	public void onPlayerTeleport (PlayerTeleportEvent event)
	{
		try
		{
			// on sors de l'AFK que si la téléportation ne se fait qu'à partir de 2 blocs d'espace
			// pour éviter qu'on sorte de l'AFK en se faisait pousser par des pistons
			// car un piston "téléporte" le joueur (techniquement parlant, dans le jeu) à 1 bloc de distance
			if (event.getFrom().getWorld() != event.getTo().getWorld()
					|| event.getFrom().distanceSquared(event.getTo()) > 2*2)
				getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}

	@EventHandler
	public void onPlayerToggleSprint (PlayerToggleSprintEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}
	@EventHandler
	public void onPlayerToggleFlight (PlayerToggleFlightEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}
	@EventHandler
	public void onPlayerToggleSneak (PlayerToggleSneakEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}

	@EventHandler
	public void onAsyncPlayerChat (AsyncPlayerChatEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}

	@EventHandler
	public void onPlayerDropItem (PlayerDropItemEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}

	@EventHandler
	public void onPlayerEggThrow (PlayerEggThrowEvent event)
	{
		try
		{
			getAfkPlayer(event.getPlayer()).isDoingAction();
		}
		catch (NullPointerException e) { }
	}
	
	
	

	
	// -----------------------------------------
	// ---------- Gestion des données ----------
	// -----------------------------------------
	public AfkPlayer getAfkPlayer(Player p)
	{
		for (AfkPlayer ap : players)
		{
			if (ap == null)
				continue;
			if (ap.getPlayer() == p)
				return ap;
		}
		return null;
	}
	
	
	private void addPlayer(Player p)
	{
		int i=0;
		while (players[i] != null && i<players.length-1) i++;
		players[i] = new AfkPlayer(p);
	}
	
	
	
	private void removePlayer(Player p)
	{
		
		for (int i=0; i<players.length; i++)
		{
			if (players[i] == null)
				continue;
			if (players[i].getPlayer() == p)
				players[i] = null;
		}
	}
	
}

