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

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils;
import net.mc_pandacraft.java.plugin.pandacraftutils.ConfigManager;
import net.mc_pandacraft.java.plugin.pandacraftutils.ConfigManager.WorldBorderConfig;
import net.mc_pandacraft.java.plugin.pandacraftutils.players.OnlinePlayer;
import net.mc_pandacraft.java.plugin.pandacraftutils.players.OnlinePlayerManager;
import net.mc_pandacraft.java.util.bukkit.protocol.ParticleEffect;

import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.scheduler.BukkitRunnable;

public class WorldBorderManager extends BukkitRunnable implements Listener {
	private PandacraftUtils plugin = PandacraftUtils.getInstance();
	

	
	public WorldBorderManager()
	{
        plugin.getServer().getScheduler().runTaskTimer(plugin, this, 2L, 20L);
        plugin.getServer().getPluginManager().registerEvents(this, plugin);
	}

	
	
	
	
	@Override
	public void run() {
		
		Collection<OnlinePlayer> players = OnlinePlayerManager.getAll();
		
		Map<String, WorldBorderConfig> configs = ConfigManager.getInstance().WorldBorder_config;
		
		
		for (OnlinePlayer op : players) {
			WorldBorderConfig config = configs.get(op.getPlayer().getWorld().getName());

			if (config == null) continue;
			
			// vérifier la position
			Location newLoc = checkPosition(op.getPlayer().getLocation(), config);
			
			if (newLoc != null) { // le joueur dépasse la bordure
				op.getPlayer().teleport(newLoc);
				op.getPlayer().sendMessage(ChatColor.RED+"Vous avez été téléporté car vous avez passé la limite de la carte");
			}
			
			// afficher la limite
			drawLimit(op.getPlayer(), config);
			
		}
		
		
	}
	
	
	public void onPlayerTeleport(PlayerTeleportEvent event) {
		
		Location l = event.getTo();
		
		WorldBorderConfig config = ConfigManager.getInstance().WorldBorder_config.get(l.getWorld().getName());
		
		if (config == null) return;
		
		Location newLoc = checkPosition(l, config);
		
		if (newLoc == null) return;
		
		event.setTo(newLoc);
		
	}
	
	
	
	
	
	
	
	
	/**
	 * Vérifie la position donnée et donne une nouvelle position si nécessaire
	 * @param l la localisation vérifiée
	 * @param config la configuration sur lequel confronter la position
	 * @return une nouvelle position si le joueur doit bouger, ou null si ce n'est pas nécessaire
	 */
	public Location checkPosition(Location l, WorldBorderConfig config) {
		
		// si le joueur ne dépasse pas la bordure
		if (isInSquare(l, config)) return null;

		double x = l.getX();
		double z = l.getZ();

		if (x < config.getMinX())
			x = config.getMinX() + 1;
		else if (x > config.getMaxX())
			x = config.getMaxX() - 1;
		
		if (z < config.getMinZ())
			z = config.getMinZ() + 1;
		else if (z > config.getMaxZ())
			z = config.getMaxZ() - 1;
		
		return new Location(l.getWorld(), x, l.getY(), z, l.getYaw(),l.getPitch());
	}
	
	
	
	
	
	
	
	
	public boolean isInSquare(Location pLoc, WorldBorderConfig config) {
		if (Math.abs(config.X - pLoc.getX()) > config.radius)
			return false;
		if (Math.abs(config.Z - pLoc.getZ()) > config.radius)
			return false;
		return true;
	}
	
	
	
	
	
	
	
	public void drawLimit(Player p, WorldBorderConfig config) {

		List<Player> pls = new ArrayList<Player>(1);
		pls.add(p);

		long x1 = Math.round(config.getMinX()),
				x2 = Math.round(config.getMaxX()),
				z1 = Math.round(config.getMinZ()),
				z2 = Math.round(config.getMaxZ());
		
		Location pLoc = p.getLocation();

		int distance = 17;
		float offset = 0F;
		
		for (long i = Math.max(pLoc.getBlockX() - distance, x1); i <= Math.min(pLoc.getBlockX() + distance, x2); i++)
			for (int j = pLoc.getBlockY() - distance; j <= pLoc.getBlockY() + distance; j++)
				for (long k = Math.max(pLoc.getBlockZ() - distance, z1); k <= Math.min(pLoc.getBlockZ() + distance, z2); k++) {

					// exclus les points qui ne sont pas en contact avec l'extérieur de la sélection
					if (!(i == x1 || i == x2 || k == z1 || k == z2))
						continue;
					
					Location l = new Location(pLoc.getWorld(), i, j, k);
					
					if(l.distanceSquared(pLoc) < distance*distance)
						ParticleEffect.FLAME.display(offset, offset, offset, 0F, 4, l, pls);
				}
		
		
	}
	
	
	
	
	
	

}
