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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils;
import net.mc_pandacraft.java.util.bukkit.protocol.ParticleEffect;

import org.bukkit.ChatColor;
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.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitRunnable;

import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
import com.sk89q.worldedit.bukkit.selections.Selection;

public class CommandWandSelection extends BukkitRunnable implements CommandExecutor, Listener {
	
	private PandacraftUtils plugin;
	
	private Map<Player, List<Player>> players = new HashMap<Player, List<Player>>();
	
	
	
	public CommandWandSelection(PandacraftUtils pl)
	{
		plugin = pl;
		
        plugin.getCommand("/selection").setExecutor(this);
        plugin.getServer().getScheduler().runTaskTimer(plugin, this, 20L, 20L);
        plugin.getServer().getPluginManager().registerEvents(this, plugin);
        
        for (Player p : plugin.getServer().getOnlinePlayers())
        	players.put(p, new ArrayList<Player>());
	}
	
	
	/*
	 * Commande //selection
	 */
	
	
	
	
	
	// permet d'activer / désactiver l'affichage du cubo
	@Override
	public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
		
		if (! (sender instanceof Player))
		{
			sender.sendMessage(ChatColor.RED+"Seul un joueur en ligne peut effectuer cette commande");
			return false;
		}
		
		if (plugin.getServer().getPluginManager().getPlugin("WorldEdit") == null)
		{
			sender.sendMessage(ChatColor.RED+"Plugin WorldEdit non installé");
			return false;
		}
		
		Player p = (Player) sender;
		
		
		Player otherP = null;
		if (args.length > 0)
		{
			otherP = plugin.getServer().getPlayer(args[0]);
			if (otherP == null)
			{
				sender.sendMessage(ChatColor.RED+"Le joueur indiqué n'existe pas");
				return true;
			}
		}
			
		
		if (players.containsKey(p) && otherP == null)
		{	// le joueur ne veut plus voir de cubo
			players.remove(p);
			sender.sendMessage(ChatColor.GREEN+"Affichage de la sélection désactivé.");
		}
		else if (players.containsKey(p))
		{
			if (players.get(p).contains(otherP))
			{
				players.get(p).remove(otherP);
				sender.sendMessage(ChatColor.GREEN+"Affichage de la sélection de "+ChatColor.GRAY+otherP.getName()+ChatColor.GREEN+" désactivé.");
			}
			else
			{
				players.get(p).add(otherP);
				sender.sendMessage(ChatColor.GREEN+"Affichage de la sélection de "+ChatColor.GRAY+otherP.getName()+ChatColor.GREEN+" activé.");
			}
				
		}
		else
		{
			players.put(p, new ArrayList<Player>());
			sender.sendMessage(ChatColor.GREEN+"Affichage de la sélection activé. Si vous ne voyez pas les particules, activez les dans vos options Minecraft.");
			if (otherP != null) {
				players.get(p).add(otherP);
				sender.sendMessage(ChatColor.GREEN+"Affichage de la sélection de "+ChatColor.GRAY+otherP.getName()+ChatColor.GREEN+" activé.");
			}
		}
		
		return true;
	}
	
	
	// supprime automatiquement un joueur qui se déconnecte
	@EventHandler
	public void onPlayerQuit(PlayerQuitEvent event)
	{
		if (players.containsKey(event.getPlayer()))
			players.remove(event.getPlayer());
	}
	
	
	@EventHandler
	public void onPlayerJoin(PlayerJoinEvent event)
	{
		if (!players.containsKey(event.getPlayer()))
			players.put(event.getPlayer(), new ArrayList<Player>());
	}
	
	
	
	// pour mettre à jour l'affichage du cubo
	@Override
	public void run() {
		
		
		try
		{
			
			for (Entry<Player, List<Player>> pl : players.entrySet())
			{
				Player p = pl.getKey();
				// on vérifie que le joueur soit en ligne
				if (p == null || !p.isOnline())
					continue;
				
				CuboidSelection cubo = getPlayerCuboSelection(p);
				
				// le joueur doit être dans le même monde que sa propre sélection
				if (cubo != null && cubo.getWorld() == p.getWorld())
					drawCuboid(cubo, p, true);
				
				if (pl.getValue() == null)
					continue;
				
				for (Player po : pl.getValue()){
					if (po == null || !po.isOnline()) continue;
					
					cubo = getPlayerCuboSelection(po);
					
					if (cubo != null && cubo.getWorld() == p.getWorld())
						drawCuboid(cubo, p, false);
				}
				
			}
		}
		catch (Exception e) { e.printStackTrace(); }
		
		
		
		
	}
	
	
	
	private CuboidSelection getPlayerCuboSelection(Player p) {
		WorldEditPlugin wePlugin = (WorldEditPlugin) plugin.getServer().getPluginManager().getPlugin("WorldEdit");
		if (wePlugin == null) return null;
		Selection sel = wePlugin.getSelection(p);
		if (sel == null) return null;
		// on garde que les cuboïdes (pas les autres formes)
		if (!(sel instanceof CuboidSelection))
			return null;
		return (CuboidSelection) sel;
		
	}
	
	
	
	private void drawCuboid(CuboidSelection cubo, Player p, boolean self)
	{
		List<Player> pls = new ArrayList<Player>(1);
		pls.add(p);
		
		Location p1 = cubo.getMinimumPoint(),
				p2 = cubo.getMaximumPoint().add(1, 1, 1);
		
		
		long x1 = Math.round(p1.getX()),
				x2 = Math.round(p2.getX()),
				y1 = Math.round(p1.getY()),
				y2 = Math.round(p2.getY()),
				z1 = Math.round(p1.getZ()),
				z2 = Math.round(p2.getZ());
		
		float offset = 0F;
		float distance = 17;
		for (long i=x1; i<=x2; i++)
			for (long j=y1; j<=y2; j++)
				for (long k=z1; k<=z2; k++)
				{
					// exclus les points qui ne sont pas en contact avec l'extérieur de la sélection
					if (!(i == x1 || i == x2 || j == y1 || j == y2 || k == z1 || k == z2))
						continue;
					Location l = new Location(p1.getWorld(), i, j, k);
					if (l.distanceSquared(p.getLocation()) < distance*distance){
						if (self)
							ParticleEffect.HAPPY_VILLAGER.display(offset, offset, offset, 0F, 1, l, pls);
						else
							ParticleEffect.FLAME.display(offset, offset, offset, 0F, 5, l, pls);
					}
				
				}
	}

}
