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

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;

import net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils;
import net.mc_pandacraft.java.util.MemoryUtil;
import net.mc_pandacraft.java.util.TimeUtil;
import net.mc_pandacraft.java.util.bukkit.TextProgressBar;

import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;

public class CommandSystem implements CommandExecutor {
	private PandacraftUtils plugin;
	private TPSAnalyser tpsAnalyser;

	public CommandSystem(PandacraftUtils pl)
	{
		plugin = pl;
		
		plugin.getCommand("system").setExecutor(this);
		
		tpsAnalyser = new TPSAnalyser(plugin);
		
	}


	@Override
	public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args)
	{
		String decoration_color = "§6";
		
		
		sender.sendMessage(decoration_color+"---- Information sur les performances -----");
		
		
		

		if (args.length > 0 && (args[0].equalsIgnoreCase("world") || args[0].equalsIgnoreCase("worlds")))
		{
			
			if (args.length > 1 && plugin.getServer().getWorld(args[1]) != null)
			{
				World w = plugin.getServer().getWorld(args[1]);
				String name = w.getName();
				int nbChunk = w.getLoadedChunks().length;
				int nbEntity = w.getEntities().size();
				sender.sendMessage("§7"+name+"§r : chunks=§e"+nbChunk+"§r ; entity=§e"+nbEntity);
				
				Map <EntityType, AtomicInteger> entity_count = new HashMap<EntityType, AtomicInteger>();
				for (Entity e : w.getEntities())
				{
					EntityType type = e.getType();
					if (entity_count.containsKey(type))
						entity_count.get(type).incrementAndGet();
					else
						entity_count.put(type, new AtomicInteger(1));
				}
				// on trie les valeurs
				Map <EntityType, AtomicInteger> entity_tree = new TreeMap<EntityType, AtomicInteger>(new Comparator<EntityType>() {
					private Map <EntityType, AtomicInteger> base;
					public Comparator<EntityType> init(Map <EntityType, AtomicInteger> b)
					{
						base = b;
						return this;
					}
					@Override
					public int compare(EntityType o1, EntityType o2) {
						AtomicInteger v1 = base.get(o1);
						AtomicInteger v2 = base.get(o2);
						if (v1.get() < v2.get())	// tri par ordre d§croissant
							return 1;
						else
							return -1;
					}
				}.init(entity_count)  );
				entity_tree.putAll(entity_count);
				for (Entry<EntityType, AtomicInteger> val : entity_tree.entrySet())
				{
					String typeS = val.getKey().name().toLowerCase();
					int nbr = (val.getValue() != null) ? val.getValue().get() : -1;
					sender.sendMessage("- §7"+typeS+"§r : "+nbr);
				}
					
				
			}
			else
			{
				// r§sum§ de tout les mondes
				sender.sendMessage(decoration_color+"------------- Mondes chargés --------------");
				List<World> worlds = plugin.getServer().getWorlds();
				for (World w : worlds)
				{
					String name = w.getName();
					int nbChunk = w.getLoadedChunks().length;
					int nbEntity = w.getEntities().size();
					sender.sendMessage("§7"+name+"§r : chunks=§e"+nbChunk+"§r ; entités=§e"+nbEntity);
					
				}
			}
			
		}
		else if (args.length > 0 && (args[0].equalsIgnoreCase("thread") || args[0].equalsIgnoreCase("threads")))
		{
			sender.sendMessage(decoration_color+"------------- Threads chargés -------------");
			try
			{
				ThreadInfo[] threadsInfo = ManagementFactory.getThreadMXBean().dumpAllThreads(false, false);
				
				int count = 0;
				for(ThreadInfo thrd : threadsInfo)
				{
					if (thrd == null)
						continue;
					count++;
					
					sender.sendMessage("#"+thrd.getThreadId()+" §7"+thrd.getThreadName()+"§r : "+thrd.getThreadState().toString().toLowerCase());
					
				}
				sender.sendMessage(decoration_color+"Total : §7"+count+" thread"+((count>1)?"s":""));
				
				
			}
			catch(Exception e)
			{
				plugin.getLogger().warning("Erreur lors de l'exécution de la commande "+cmd+" : "+e.getMessage());
				sender.sendMessage(ChatColor.RED+"Erreur lors de l'exécution de la commande.");
			}
			
		}
		else if (args.length > 0 && args[0].equalsIgnoreCase("tps_graph"))
		{
			if (!(sender instanceof ConsoleCommandSender))
				sender.sendMessage("Graph envoyé sur la console");
			
			
			ConsoleCommandSender console = plugin.getServer().getConsoleSender();
			console.sendMessage(tpsAnalyser.getStringTPSHistory(20*20));
			
		}
		else
		{
			// ----- infos générales -----
			
			// m§moire
			long maxMem = Runtime.getRuntime().maxMemory();
			long allocMem = Runtime.getRuntime().totalMemory();
			long freeMem = Runtime.getRuntime().freeMemory();
			sender.sendMessage(decoration_color+"Mémoire : §cUtil:"+MemoryUtil.humanReadableSize(allocMem - freeMem)+
											" §eAllouée:"+MemoryUtil.humanReadableSize(allocMem)+
											" §rMaxi:"+MemoryUtil.humanReadableSize(maxMem));
			double[] values_bar = new double[2];
			values_bar[0] = allocMem - freeMem;
			values_bar[1] = freeMem;
			ChatColor[] colors_bar = new ChatColor[2];
			colors_bar[0] = ChatColor.RED;
			colors_bar[1] = ChatColor.YELLOW;
			sender.sendMessage(TextProgressBar.progressBar(values_bar, colors_bar, maxMem, ((sender instanceof Player)?155:43)));
			
			// tps
			double tps = tpsAnalyser.getTPS();
			String val_tps;
			if (Double.isNaN(tps))
			{
				val_tps = "N/A";
				tps = 0;
			}
			else
				val_tps = (Math.round(tps*10)/10D)+"";
			ChatColor color_bar = (tps >= 18)?ChatColor.GREEN:
									(tps >=13)?ChatColor.YELLOW:
									(tps >= 8)?ChatColor.GOLD:
									(tps >= 4)?ChatColor.RED:
										ChatColor.DARK_RED;
			sender.sendMessage(decoration_color+"Tick par seconde : "+color_bar+val_tps+"/20");
				sender.sendMessage(TextProgressBar.progressBar(tps, color_bar, 20, ((sender instanceof Player)?155:43)));
				
			// uptime
			long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
			sender.sendMessage(decoration_color+"Uptime : §7"+TimeUtil.durationToString(uptime));
			
			
			
			
		}
		
		
		return true;
	}

}
