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

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import net.mc_pandacraft.java.plugin.pandacraftutils.ConfigManager;
import net.mc_pandacraft.java.plugin.pandacraftutils.PandacraftUtils;
import net.mc_pandacraft.java.plugin.pandacraftutils.modules.CalculatorManager;
import net.mc_pandacraft.java.plugin.pandacraftutils.plugin_interface.EssentialsInterface;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;

import ru.tehkode.permissions.bukkit.PermissionsEx;

public class OnlinePlayer {
	private final Player player;
	private final PandacraftUtils plugin = PandacraftUtils.getInstance();
	
	public OnlinePlayer(Player p) {
		player = p;
	}
	
	public Player getPlayer() { return player; }
	
	
	
	/*
	 * Système AFK
	 */

	private long timeLastAction = System.currentTimeMillis();
	private boolean afk = false;
	
	public synchronized boolean isAfk() { return afk; }
	
	public synchronized void setAfk(boolean a) {
		if (afk == a)
			return;
		afk = a;
		String message;
		
		// on affiche pas le status AFK des joueurs vanish
		if (EssentialsInterface.isPlayerVanished(player)) return;
		
		// affichage du message
		if (afk)
			message = player.getDisplayName()+ChatColor.YELLOW+" est désormais AFK.";
		else
			message = player.getDisplayName()+ChatColor.YELLOW+" n'est plus AFK.";
		player.getServer().broadcastMessage(message);
	}
	
	public void performAfkCommand() {
		setAfk(!isAfk());
		if (!isAfk())
			isDoingAction();
	}
	
	public void adminToggleAfk() {
		setAfk(!isAfk());
		if (!isAfk())
			isDoingAction();
	}
	
	public double getDurationSinceLastAction() {
		return (System.currentTimeMillis() - timeLastAction)/1000D;
	}
	
	public void isDoingAction() {
		timeLastAction = System.currentTimeMillis();
		setAfk(false);
	}
	
	
	
	
	
	
	
	
	
	
	
	/*
	 * Système d'analyse du chat
	 */

	private String last_message = null;
	private long last_message_time = 0;
	private String last_command = null;
	private long last_command_time = 0;
	
	private int violation_level = 0;
	

	public String getLast_message() { return last_message; }
	public void setLast_message(String last_message) { this.last_message = last_message; }
	public long getLast_message_time() { return last_message_time; }
	public void setLast_message_time(long last_message_time) { this.last_message_time = last_message_time; }
	public String getLast_command() { return last_command; }
	public void setLast_command(String last_command) { this.last_command = last_command; }
	public long getLast_command_time() { return last_command_time; }
	public void setLast_command_time(long last_command_time) { this.last_command_time = last_command_time; }

	public void addVL(int nb)
	{
		violation_level += nb;
		plugin.getLogger().info("ViolationLevel for player "+player.getDisplayName()+"§r : +"+nb+" -> "+violation_level);
		if (violation_level >= ConfigManager.getInstance().ChatAnalysis_maxViolationLevel)
			Bukkit.getScheduler().runTask(plugin, new Runnable() {
	            @Override
	            public void run() {
	            	player.kickPlayer("Les spams/insultes/publicités sont interdits !");
	            }
	        });
	}
	public void removeVL(int nb)
	{
		violation_level -= nb;
		if (violation_level < 0) violation_level = 0;
	}

	public int getVL() { return violation_level; }
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	/*
	 * Sélection worldEdit
	 */
	private boolean WE_show_selection = true;
	private Set<Player> WE_other_player_selection = new HashSet<Player>();
	
	public boolean canViewWESelection() { return WE_show_selection; }
	public void enableViewingWESelection() { WE_show_selection = true; }
	public void disableViewingWESelection() {
		WE_show_selection = false;
		WE_other_player_selection = new HashSet<Player>();
	}
	/**
	 * @return la liste des joueurs dont le OnlinePlayer veut voir la sélection worldedit (Cette liste retournée est immuable)
	 */
	public Set<Player> getPlayersForViewingOthersWESelections() { return Collections.unmodifiableSet(WE_other_player_selection); }
	public void addPlayerForWiewingHisWESelection(Player p) {
		if (p == null || p == player) return;
		WE_other_player_selection.add(p);
	}
	public void removePlayerForWiewingHisWESelection(Player p) { WE_other_player_selection.remove(p); }
	public boolean hasPlayerForWiewingHisWESelection(Player p) { return WE_other_player_selection.contains(p); }
	
	
	
	
	
	
	
	
	
	/*
	 * AutomessagesData
	 */
	private boolean automessage_first_since_online = false;
	private long automessage_last_message_time = System.currentTimeMillis();
	private int automessage_last_message_id = -1;
	
	public boolean firstAutomessageCkeck(int aleaMaxDuration) {
		if (automessage_first_since_online) return true;
		automessage_first_since_online = true;
		automessage_last_message_time = System.currentTimeMillis() - (new Random()).nextInt(aleaMaxDuration)*1000;
		return false;
	}
	public void updateAutomessage_last_message_time() { automessage_last_message_time = System.currentTimeMillis(); }
	public long getAutomessage_last_message_time() { return automessage_last_message_time; }

	public int getAutomessage_last_message_id() { return automessage_last_message_id; }

	public void setAutomessage_last_message_id(int id) { automessage_last_message_id = id; }
	
	
	
	
	
	
	
	
	
	
	
	
	
	/*
	 * Historique de calcul
	 */
	private ArrayList<CalculatorManager.HistoryElement> Calculator_history = new ArrayList<CalculatorManager.HistoryElement>();
	
	public void addToCalculatorHistory(CalculatorManager.HistoryElement el) {
		Calculator_history.add(el);
		if (Calculator_history.size() > 5)
			Calculator_history.remove(0);
	}
	
	public List<CalculatorManager.HistoryElement> getCalculator_history() {
		return Collections.unmodifiableList(Calculator_history);
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	/*
	 * Utils
	 */
	
	/**
	 * Envoi un message au joueur avec un prefixe.
	 * Fait appel à <code>player.sendMessage()</code>
	 * @param message le message à envoyer au joueur
	 */
	public void sendMessageFromServer(String message) {
		player.sendMessage(ConfigManager.getInstance().ServerMessages_prefix + message);
	}
	
	
	
	
	
	/**
	 * Indique si le joueur est vanish, en se basant sur le plugin Essentials, qui
	 * gère cette foncionnalitée
	 */
	public boolean isVanished() {
		return EssentialsInterface.isPlayerVanished(player);
	}
	
	
	
	
	
	
	
	/*
	 * Grades
	 */
	/**
	 * Récupère le groupe parent direct ayant le poids le plus fort
	 * @return le groupe
	 */
	public String getGroup() {
		String[] groups = getGroups();
		return (groups != null && groups.length > 0) ? groups[0] : PermissionsEx.getPermissionManager().getDefaultGroup().getName();
	}
	
	/**
	 * Défini si le joueur à la permission dont le noeux est passé sous forme de
	 * chaine de caractère. Cetteméthode ajoute une surcouche par rapport à la méthode
	 * Player.hasPermission(String) permettant de tester si un joueur est dans un groupe, de
	 * la même manière que OnlinePlayer.isInGroup(String)
	 * @param permission la permission testée
	 * @return si le joueur a la permission
	 */
	public boolean hasPermission(String permission) {
		String permissionGroupPrefix = "pandacraft.grade.";
		if (permission != null && permission.startsWith(permissionGroupPrefix)) {
			String group = permission.substring(permissionGroupPrefix.length());
			return isInGroup(group);
		}
		return player.hasPermission(permission);
	}
	
	/**
	 * Récupère la liste des groupes dans lequel le joueur se trouve
	 * @return
	 */
	public String[] getGroups() {
		try {
		return PermissionsEx.getUser(player).getGroupsNames();
		} catch (NoClassDefFoundError e) {
			String[] g = {"default"};
			return g;
		}
	}
	/**
	 * Indique si le joueur est dans le groupe Spécifié
	 * @param group Le groupe par rapport au plugin de permission
	 * @return <i>true</i> si le joueur est dans le groupe spécifié, <i>false</i> sinon
	 */
	public boolean isInGroup(String group) {
		if (group == null) return false;
		return group.equalsIgnoreCase(getGroup());
	}
	
	/**
	 * Indique si le joueur est un nouveau joueur (si il ne s'est pas inscrit sur le site)
	 * @return <i>true</i> si le joueur n'est pas inscrit, <i>false</i> sinon
	 */
	public boolean isGuest() {
		return isInGroup("default");
	}
	
	/**
	 * Indique si le joueur s'est inscrit sur le site
	 * @return <i>true</i> si c'est le cas, <i>false</i> sinon
	 */
	public boolean isRegistered() {
		return !isGuest();
	}
	
	/**
	 * Indique si le joueur fait parti du staff
	 * @return <i>true</i> si c'est le cas, <i>false</i> sinon
	 */
	public boolean isInStaff() {
		return isInGroup("admins") ||
				isInGroup("devs") ||
				isInGroup("modos") ||
				isInGroup("archis") ||
				isInGroup("guides");
	}
}
