package me.happypikachu.TorchLight;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import net.minecraft.server.ChunkCoordIntPair;
import net.minecraft.server.EntityPlayer;
import net.minecraft.server.EnumSkyBlock;

import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;

public class TL extends JavaPlugin {
	public Set<Player> isUsing = new HashSet<Player>();
	public boolean enableOnLoad = false;
	public static HashMap<Location, Integer> playerBlocks = new HashMap<Location, Integer>();
	
	@Override
	public void onDisable() {
	}
	
	@Override
	public void onEnable() {
		PluginDescriptionFile pdFile = getDescription();
		try {
			FileConfiguration fc = getConfig();
			if (!new File(getDataFolder(), "config.yml").exists()) {
				fc.options().header("TorchLight+ v" + pdFile.getVersion() + " Configuration" + 
					"\nby HappyPikachu -aka- FlyingPikachu" + 
					"\n" + 
			        "\nIf you experience a problem with this config when starting" +
			        "\nyour server, make sure that you're using spaces and not tabs." + 
			        "\nCheck that all apostrophes are escaped. For example, \"can't\"" + 
			        "\nbecomes \"can\\'t\"." +
			        "\n" +
			        "\nThanks to desht for the latest lighting methods." + 
					"\n");
				fc.addDefault("ItemIDs.slot1", 10);
				fc.addDefault("ItemIDs.slot2", 11);
				fc.addDefault("ItemIDs.slot3", 50);
				fc.addDefault("ItemIDs.slot4", 51);
				fc.addDefault("ItemIDs.slot5", 76);
				fc.addDefault("ItemIDs.slot6", 89);
				fc.addDefault("ItemIDs.slot7", 91);
				fc.addDefault("ItemIDs.slot8", 327);
				fc.addDefault("ItemIDs.slot9", 369);
				fc.addDefault("Plugin.enable-on-login", false);
				fc.addDefault("Strings.activate", "TorchLight+ activated.");
				fc.addDefault("Strings.deactivate", "TorchLight+ deactivated.");
				fc.addDefault("Strings.disabled", "Plugin is disabled in this world.");
				fc.addDefault("Strings.no-permission", "You do not have permission to perform this command.");
				List<World> worlds = getServer().getWorlds();
				for (World world: worlds) {
					fc.addDefault("Worlds." + world.getName(), true);
				}
				fc.options().copyDefaults(true);
				saveConfig();
				fc.options().copyDefaults(false);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		getServer().getPluginManager().registerEvents(new TLBlock(this), this);
		getServer().getPluginManager().registerEvents(new TLPlayer(this), this);
	}
	
	public static void lightUp(int x, int y, int z, int level, int spacing, CraftWorld world, Player player) {
		int radius = level / spacing;
		resetLight(x, y, z, world, player);
		for (int i = -radius; i <= radius; i++) {
			for (int j = -radius; j <= radius; j++) {
				for (int k = -radius; k <= radius; k++) {
					int oldLevel = world.getHandle().getLightLevel(x + i, y + j, z + k);
					int newLevel = level - (Math.abs(i) + Math.abs(j) + Math.abs(k));
					if (newLevel > oldLevel) {
						world.getHandle().a(EnumSkyBlock.BLOCK, x + i, y + j, z + k, newLevel);
					}
				}
			}
		}
		sendClientChanges(player);
	}

	public static void resetLight(int x, int y, int z, CraftWorld world, Player player) {
		int radius = 12;
		for (int i = -radius; i <= radius; i++) {
			for (int j = -radius; j <= radius; j++) {
				for (int k = -radius; k <= radius; k++) {
					world.getHandle().a(EnumSkyBlock.BLOCK, x + i, y + j, z + k, 0);
				}
			}
		}
		sendClientChanges(player);
	}
	
	public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
		if (sender instanceof Player & (cmd.getName().equalsIgnoreCase("tl") || cmd.getName().equalsIgnoreCase("torchlight"))) {
			if(args.length == 0) {
				if (getConfig().getBoolean("Worlds." + ((Player)sender).getWorld().getName()) || ((Player)sender).getPlayer().isOp()) {
					CraftBlock block = (CraftBlock)((Player)sender).getLocation().getBlock();
					CraftWorld world = (CraftWorld)block.getWorld();
					int x = block.getX();
					int y = block.getY();
					int z = block.getZ();
					if (!this.isUsing.contains(sender)) {
						this.isUsing.add((Player)sender);
						if (isValid(((Player)sender).getItemInHand().getTypeId())) {
							lightUp(x, y + 1, z, 15, 3, world, (Player)sender);
						}
						sender.sendMessage(ChatColor.GRAY + getConfig().getString("Strings.activate"));
					} else {
						if (isValid(((Player)sender).getItemInHand().getTypeId())) {
							resetLight(x, y + 1, z, world, (Player) sender);
						}
						this.isUsing.remove((Player)sender);
						sender.sendMessage(ChatColor.GRAY + getConfig().getString("Strings.deactivate"));
					}
					return true;
				} else if (!getConfig().getBoolean("Worlds." + ((Player)sender).getWorld().getName())) {
					sender.sendMessage(ChatColor.RED + getConfig().getString("Strings.disabled"));
					return true;
				} else {
					sender.sendMessage(ChatColor.RED + getConfig().getString("Strings.no-permission"));
				}
			}
			if (args.length > 0) {
				if (args[0].equalsIgnoreCase("i") || args[0].toLowerCase(Locale.ENGLISH).startsWith("info")) {
					PluginDescriptionFile pdFile = getDescription();
					sender.sendMessage(ChatColor.RED + "TorchLight+ v" + pdFile.getVersion() + ChatColor.GRAY + " " + pdFile.getAuthors().toString());
					sender.sendMessage(pdFile.getDescription());
					return true;
				}
			}
		} else if (!(sender instanceof Player) & (cmd.getName().equalsIgnoreCase("tl") || cmd.getName().equalsIgnoreCase("torchlight"))) {
			if(args.length == 0) {
				sender.sendMessage("This command cannot be used from the console.");
				return true;
			}
			if (args.length > 0) {
				if (args[0].equalsIgnoreCase("i") || args[0].toLowerCase(Locale.ENGLISH).startsWith("info")) {
					PluginDescriptionFile pdFile = getDescription();
					sender.sendMessage(ChatColor.RED + "TorchLight+ v" + pdFile.getVersion() + ChatColor.GRAY + " " + pdFile.getAuthors().toString());
					sender.sendMessage(pdFile.getDescription());
					return true;
				}
			}
		}
		return false;
	}
	
	public boolean isValid(int itemID) {
		if (itemID == getConfig().getInt("ItemIDs.slot1")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot2")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot3")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot4")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot5")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot6")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot7")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot8")) {
			return true;
		} else if (itemID == getConfig().getInt("ItemIDs.slot9")) {
			return true;
		}
		return false;
	}
	
	public static List<Chunk> getChunks(Player p) {
		List<Chunk> res = new ArrayList<Chunk>();
		double x = p.getLocation().getX();
		double y = p.getLocation().getY();
		double z = p.getLocation().getZ();
		Location loc = new Location(p.getWorld(), x, y, z);
		Location posx = new Location(p.getWorld(), x + 16, y, z);
		Location negx = new Location(p.getWorld(), x - 16, y, z);
		Location posz = new Location(p.getWorld(), x, y, z + 16);
		Location negz = new Location(p.getWorld(), x, y, z - 16);
		Location diag1 = new Location(p.getWorld(), x + 16, y, z + 16);
		Location diag2 = new Location(p.getWorld(), x - 16, y, z + 16);
		Location diag3 = new Location(p.getWorld(), x + 16, y, z - 16);
		Location diag4 = new Location(p.getWorld(), x - 16, y, z - 16);
		res.add(loc.getChunk());
		res.add(posx.getChunk());
		res.add(negx.getChunk());
		res.add(posz.getChunk());
		res.add(negz.getChunk());
		res.add(diag1.getChunk());
		res.add(diag2.getChunk());
		res.add(diag3.getChunk());
		res.add(diag4.getChunk());
		return res;
		}
	
	public static void sendClientChanges(Player p) {
		List<ChunkCoordIntPair> pairs = new ArrayList<ChunkCoordIntPair>();
		for (Chunk c : getChunks(p)) {
			pairs.add(new ChunkCoordIntPair(c.getX(), c.getZ()));
		}
		EntityPlayer ep = ((CraftPlayer) p).getHandle();
		queueChunks(ep, pairs);
	}

	@SuppressWarnings("unchecked")
	private static void queueChunks(EntityPlayer ep, List<ChunkCoordIntPair> pairs) {
		Set<ChunkCoordIntPair> queued = new HashSet<ChunkCoordIntPair>();
		for (Object o : ep.chunkCoordIntPairQueue) {
			queued.add((ChunkCoordIntPair) o);
		}
		for (ChunkCoordIntPair pair : pairs) {
			if (!queued.contains(pair)) {
				ep.chunkCoordIntPairQueue.add(pair);
			}
		}
	}
}