package net.mc_pandacraft.java.plugin.pandacraftutils.cheat_protect.no_pvp;


import java.util.List;

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

import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.player.PlayerBucketEmptyEvent;

public class NoPvpProtectManager implements Listener {
	
	private PandacraftUtils plugin;
	
	private double lava_distance = 5;
	private double fire_distance = 5;
	
	private String last_logger_message = "";
	

	public NoPvpProtectManager(PandacraftUtils pl)
	{
		plugin = pl;
		plugin.getServer().getPluginManager().registerEvents(this, plugin);
	}
	
	
	
	
	
	
	public void loggerInfo(String s)
	{
		if (s.equals(last_logger_message))
			return;
		plugin.getLogger().info(s);
		last_logger_message = s;
	}
	
	
	
	
	
	
	@EventHandler
	public void onBlockPlace(BlockPlaceEvent event)
    {
		if (event.getBlock().getWorld().getPVP())
			return;
		
		Material mat = event.getBlockPlaced().getType();
        if (mat.equals(Material.LAVA) || mat.equals(Material.FIRE))
        {	// on fait l'analyse pour le placement du bloc de lave
        	String mat_name_aff;
        	double distance;
        	if (mat.equals(Material.LAVA))
        	{
        		mat_name_aff = "de la lave";
        		distance = lava_distance;
        	}
        	else
        	{
        		mat_name_aff = "du feu";
        		distance = fire_distance;
        	}
        	
        	
            Player p = event.getPlayer();
            Location block_loc = event.getBlockPlaced().getLocation();
            List<Player> pls = block_loc.getWorld().getPlayers();
            boolean player_nearby = false;
            String nearby_pl_aff = "";
            // on fait le tour de toutes les entit§s de la map
            for (Player pl : pls)
            {
            	// on ne compte pas le poseur (sinon, on y arrivera pas x) )
            	if (pl == p || pl.getGameMode() == GameMode.CREATIVE)
            		continue;

            	Location ent_loc = pl.getLocation();
            	if (ent_loc.distance(block_loc) < distance)
            	{	// un joueur autre que celui qui a pos§ est trop proche
            		player_nearby = true;
            		nearby_pl_aff = nearby_pl_aff + " " + pl.getDisplayName();
            	}
            }
            
            if (player_nearby)
            {
            	p.sendMessage("§dDemandez aux joueurs proche de vous de s'éloigner si vous voulez poser "+mat_name_aff+" :"+nearby_pl_aff);
            	loggerInfo("§7"+p.getName()+"§r attempted to place lava block or fire block in world §7"+block_loc.getWorld().getName()+"§r near to player(s) :§7" + nearby_pl_aff);
            	event.setCancelled(true);
            }
            
        }
    }
	
	@EventHandler
	public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) {
		if (event.getBlockClicked().getWorld().getPVP())
			return;
		
		if (event.getBucket() != null && event.getBucket() == Material.LAVA_BUCKET)
        {	// on fait l'analyse pour le placement du bloc de lave
        	double distance = lava_distance;
        	
            Player p = event.getPlayer();
            Location block_loc = event.getBlockClicked().getLocation();
            List<Player> pls = block_loc.getWorld().getPlayers();
            boolean player_nearby = false;
            String nearby_pl_aff = "";
            // on fait le tour de toutes les entit§s de la map
            for (Player pl : pls)
            {
            	// on ne compte pas le poseur (sinon, on y arrivera pas x) )
            	if (pl == p || pl.getGameMode() == GameMode.CREATIVE)
            		continue;
            	

            	Location ent_loc = pl.getLocation();
            	if (ent_loc.distance(block_loc) < distance)
            	{	// un joueur autre que celui qui a pos§ est trop proche
            		player_nearby = true;
            		nearby_pl_aff = nearby_pl_aff + " " + pl.getDisplayName();
            	}
            }

            if (player_nearby)
            {
            	p.sendMessage("§dDemandez aux joueurs proche de vous de s'éloigner si vous voulez poser de la lave :"+nearby_pl_aff);
            	loggerInfo("§7"+p.getName()+"§r attempted to place lava in world §7"+block_loc.getWorld().getName()+"§r near to player(s) :§7" + nearby_pl_aff);
            	event.setCancelled(true);
            }
        }
	}
	
	@EventHandler
	public void onBlockIgnit(BlockIgniteEvent event) {
		if (event.getPlayer() == null)
			return;

		if (event.getBlock().getWorld().getPVP())
			return;
		
		if (event.getCause() == IgniteCause.FIREBALL || event.getCause() == IgniteCause.FLINT_AND_STEEL)
        {	// on fait l'analyse pour l'allumage avec un briquet
        	double distance = fire_distance;
        	
            Player p = event.getPlayer();
            Location block_loc = event.getBlock().getLocation();
            List<Player> pls = block_loc.getWorld().getPlayers();
            boolean player_nearby = false;
            String nearby_pl_aff = "";
            // on fait le tour de tout les joueurs de la map
            for (Player pl : pls)
            {
            	// on ne compte pas le poseur (sinon, on y arrivera pas x) )
            	if (pl == p || pl.getGameMode() == GameMode.CREATIVE)
            		continue;
            	

            	Location ent_loc = pl.getLocation();
            	if (ent_loc.distance(block_loc) < distance)
            	{	// un joueur autre que celui qui a pos§ est trop proche
            		player_nearby = true;
            		nearby_pl_aff = nearby_pl_aff + " " + pl.getDisplayName();
            	}
            }

            if (player_nearby)
            {
            	p.sendMessage("§dDemandez aux joueurs proche de vous de s'éloigner si vous voulez poser du feu :"+nearby_pl_aff);
            	loggerInfo("§7"+p.getName()+"§r attempted to place fire in world §7"+block_loc.getWorld().getName()+"§r near to player(s) :§7" + nearby_pl_aff);
            	event.setCancelled(true);
            }
        }
	}
	
	@EventHandler
	public void onBlockBreak(BlockBreakEvent event)
	{
		if (event.getBlock().getWorld().getPVP())
			return;
		
		Player p = event.getPlayer();
		Block b = event.getBlock();

        List<Player> pls = b.getWorld().getPlayers();

        boolean player_standing = false;
        String nearby_pl_aff = "";
        // on fait le tour de tout les joueurs de la map
        for (Player pl : pls)
        {
        	// on ne compte pas le poseur (sinon, on y arrivera pas x) ) et on ignorent ceux qui fly
        	if (pl == p || pl.isFlying())
        		continue;
        	

        	Location pl_loc = pl.getLocation().getBlock().getLocation();
        	Location pl_loc_under = new Location(pl_loc.getWorld(), pl_loc.getX(), pl_loc.getY()-1, pl_loc.getZ());
        	Location pl_loc_over = new Location(pl_loc.getWorld(), pl_loc.getX(), pl_loc.getY()+1, pl_loc.getZ());
        	if (pl_loc.equals(b.getLocation())
        			|| pl_loc_under.equals(b.getLocation())
        			|| pl_loc_over.equals(b.getLocation()))
        	{	// un joueur autre que celui qui a pos§ est trop proche
        		player_standing = true;
        		nearby_pl_aff = nearby_pl_aff + " " + pl.getDisplayName();
        	}
        }

        if (player_standing)
        {
        	p.sendMessage("§dDemandez à ces joueurs de se déplacer si vous voulez casser ce bloc :"+nearby_pl_aff);
        	loggerInfo("§7"+p.getName()+"§r attempted to brake block in world §7"+b.getWorld().getName()+"§r under player(s) :§7" + nearby_pl_aff);
        	event.setCancelled(true);
        }
	}
	
	
	@EventHandler
	public void onBlockFromTo(BlockFromToEvent event)
	{
		if (event.getBlock().getWorld().getPVP())
			return;

		Block bf = event.getBlock();
		Block bt = event.getToBlock();
		Location loc_bt = bt.getLocation();

        List<Player> pls = bf.getWorld().getPlayers();

        boolean player_standing = false;
        String nearby_pl_aff = "";
        // on fait le tour de tout les joueurs de la map
        for (Player pl : pls)
        {
        	// on ignore ceux en cr§atif
        	if (pl.getGameMode() == GameMode.CREATIVE)
        		continue;
        	
        	
        	Location pl_loc = pl.getLocation().getBlock().getLocation();
        	
        	
        	
        	// si la distance par rapport au joueur courant est > 5 bloc, on ignore
        	// c'est pour optimiser car les calculs qui suits semblent onéreuses en temps de calcul x)
        	if (pl_loc.distanceSquared(loc_bt) > 5*5)
        		continue;
        	
        	
        	
        	
        	
        	
        	Location pl_loc_floor = new Location(pl_loc.getWorld(), Math.floor(pl.getLocation().getX()), Math.floor(pl.getLocation().getY()), Math.floor(pl.getLocation().getZ()));
        	
        	Location pl_loc_inner_block = pl.getLocation().subtract(pl_loc_floor);
        	
        	
        	int x_min = (int)Math.round(pl_loc.getX())-((pl_loc_inner_block.getX()<=0.3)?1:0);
        	int y_min = (int)Math.round(pl_loc.getY())-1;
        	int z_min = (int)Math.round(pl_loc.getZ())-((pl_loc_inner_block.getZ()<=0.3)?1:0);
        	
        	int x_max = (int)Math.round(pl_loc.getX())+((pl_loc_inner_block.getX()>=0.7)?1:0);
        	int y_max = (int)Math.round(pl_loc.getY())+((pl_loc_inner_block.getY()>=0.2)?2:1);
        	int z_max = (int)Math.round(pl_loc.getZ())+((pl_loc_inner_block.getZ()>=0.7)?1:0);
        	for (int x = x_min; x <= x_max; x++)
        		for (int y = y_min; y <= y_max; y++)
        			for (int z = z_min; z <= z_max; z++)
        				if ((new Location(pl_loc.getWorld(), x, y, z)).equals(loc_bt))
        				{
        	        		player_standing = true;
        	        		nearby_pl_aff = nearby_pl_aff + " " + pl.getDisplayName();
        				}
        	
        }

        if (player_standing)
        {
        	event.setCancelled(true);
        }
	}
}

