abstract public class Commands {
    private static HashMap<String, ArrayList<CommandDef>> commands = new HashMap<String, ArrayList<CommandDef>>();
    private static TCharObjectHashMap<Class<? extends CommandArgument>> argTypes = new TCharObjectHashMap<Class<? extends CommandArgument>>();

    static {
        argTypes.put('s', ArgumentString.class);
        argTypes.put('i', ArgumentInteger.class);
        argTypes.put('f', ArgumentDouble.class);
        argTypes.put('p', ArgumentPlayer.class);
        argTypes.put('o', ArgumentOption.class);
        argTypes.put('n', ArgumentItem.class);
        argTypes.put('m', ArgumentMaterial.class);
        argTypes.put('e', ArgumentEnum.class);
    }

    public static void exec(CommandSender sender, String com) {
        com = com.trim();
        if (com.length() == 0)
            return;
        String comName;
        int pos = com.indexOf(' ');
        if (pos == -1) {
            comName = com;
        } else {
            comName = com.substring(0, pos);
        }
        com = com.substring(pos + 1);

        String locale = sender instanceof Player ? Locale.getPlayerLocale((Player)sender) : "en_GB";
        
        ArrayList<CommandDef> command = commands.get(comName);
        if (command == null) {
            sender.sendMessage(ChatColor.RED + String.format(Locale.get("message.error.unknown.command", locale), comName));
            return;
        }

        if (pos == -1) {
            for (CommandDef c : command) {
                if (c.arguments.length == 0) {
                    try {
                        if (c.handlePermissions || sender.hasPermission("rpgitem"))
                            c.method.invoke(c.handler, sender);
                        else
                            sender.sendMessage(ChatColor.RED + Locale.get("message.error.permission", locale));
                    } catch (IllegalAccessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return;
                }
            }
            // Print usage
            if (sender.hasPermission("rpgitem")) {
                sender.sendMessage(String.format(ChatColor.GREEN + Locale.get("message.command.usage", locale), comName, Plugin.plugin.getDescription().getVersion()));
                for (CommandDef c : command) {
                    StringBuilder buf = new StringBuilder();
                    buf.append(ChatColor.GREEN).append('/').append(comName);
                    for (CommandArgument a : c.arguments) {
                        buf.append(' ');
                        if (a.name.length() != 0) {
                            buf.append(ChatColor.RED);
                            buf.append(Locale.get("command.info." + a.name, locale));
                        }
                        buf.append(a.isConst() ? ChatColor.GREEN : ChatColor.GOLD);
                        buf.append(a.printable(locale));
                    }
                    sender.sendMessage(buf.toString());
                }
                sender.sendMessage(ChatColor.GREEN + Locale.get("message.command.info", locale));
            } else
                sender.sendMessage(ChatColor.RED + Locale.get("message.error.permission", locale));
            return;
        }
        ArrayList<String> args = new ArrayList<String>();
        while (true) {
            int end;
            if (com.length() == 0) {
                break;
            }
            boolean quote = false;
            if (com.charAt(0) == '`') {
                com = com.substring(1);
                end = com.indexOf('`');
                quote = true;
            } else {
                end = com.indexOf(' ');
            }
            if (end == -1) {
                args.add(com);
            } else {
                args.add(com.substring(0, end));
            }
            if (quote) {
                com = com.substring(end + 1);
                end = com.indexOf(' ');
            }
            if (end != -1) {
                com = com.substring(end + 1);
            } else {
                break;
            }
        }
        CommandError lastError = null;
        comLoop: for (CommandDef c : command) {
            if (c.arguments.length != args.size()) {
                if (c.arguments.length != 0 && c.arguments[c.arguments.length - 1] instanceof ArgumentString) {
                    if (args.size() < c.arguments.length)
                        continue;
                } else {
                    continue;
                }
            }
            ArrayList<Object> outArgs = new ArrayList<Object>();
            outArgs.add(sender);
            for (int i = 0; i < c.arguments.length; i++) {
                CommandArgument a = c.arguments[i];
                if (!a.isConst()) {
                    if (i == c.arguments.length - 1) {
                        // Special case for strings so they do not need to be quoted
                        if (a instanceof ArgumentString) {
                            StringBuilder joined = new StringBuilder();
                            for (int j = i; j < args.size(); j++) {
                                joined.append(args.get(j)).append(' ');
                            }
                            args.set(i, joined.toString().trim());
                        }
                    }
                    Object res = a.parse(args.get(i), locale);
                    if (res instanceof CommandError) {
                        lastError = (CommandError) res;
                        continue comLoop;
                    }
                    outArgs.add(res);
                } else {
                    ArgumentConst cst = (ArgumentConst) a;
                    if (!cst.value.equals(args.get(i))) {
                        continue comLoop;
                    }
                }
            }
            try {
                if (c.handlePermissions || sender.hasPermission("rpgitem"))
                    c.method.invoke(c.handler, outArgs.toArray());
                else
                    sender.sendMessage(ChatColor.RED + Locale.get("message.error.permission", locale));
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return;
        }
        if (sender.hasPermission("rpgitem")) {
            if (lastError != null) {
                sender.sendMessage(ChatColor.RED + String.format(Locale.get("message.error.command", locale), lastError.error));
            } else {
                ArrayList<String> consts = new ArrayList<String>();
                comLoop: for (CommandDef c : command) {
                    for (int i = 0; i < c.arguments.length; i++) {
                        if (i >= args.size())
                            break;
                        CommandArgument a = c.arguments[i];
                        if (!a.isConst()) {
                            if (i == c.arguments.length - 1) {
                                // Special case for strings so they do not need to be quoted
                                if (a instanceof ArgumentString) {
                                    StringBuilder joined = new StringBuilder();
                                    for (int j = i; j < args.size(); j++) {
                                        joined.append(args.get(j)).append(' ');
                                    }
                                    args.set(i, joined.toString().trim());
                                }
                            }
                            Object res = a.parse(args.get(i), locale);
                            if (res instanceof CommandError) {
                                lastError = (CommandError) res;
                                continue comLoop;
                            }
                        } else {
                            ArgumentConst cst = (ArgumentConst) a;
                            if (!cst.value.equals(args.get(i))) {
                                continue comLoop;
                            } else {
                                consts.add(cst.value);
                            }
                        }
                    }
                }
                StringBuilder search = new StringBuilder();
                for (String term : consts) {
                    search.append(term).append(' ');
                }
                searchHelp(sender, search.toString());
            }
        } else
            sender.sendMessage(ChatColor.RED + Locale.get("message.error.permission", locale));
    }

    public static List<String> complete(CommandSender sender, String com) {
        com = com.trim();
        if (com.length() == 0) {
            return new ArrayList<String>();
        }
        String comName;
        int pos = com.indexOf(' ');
        if (pos == -1) {
            comName = com;
        } else {
            comName = com.substring(0, pos);
        }
        com = com.substring(pos + 1);

        String locale = sender instanceof Player ? Locale.getPlayerLocale((Player)sender) : "en_GB";
        
        ArrayList<CommandDef> command = commands.get(comName);

        if (command == null) {
            if (pos == -1) {
                ArrayList<String> out = new ArrayList<String>();
                for (String n : commands.keySet()) {
                    if (n.startsWith(comName)) {
                        out.add("/" + n);
                    }
                }
                return out;
            }
            return new ArrayList<String>();
        }
        ArrayList<String> args = new ArrayList<String>();
        while (true) {
            int end;
            if (com.length() == 0) {
                break;
            }
            boolean quote = false;
            if (com.charAt(0) == '`') {
                com = com.substring(1);
                end = com.indexOf('`');
                quote = true;
            } else {
                end = com.indexOf(' ');
            }
            if (end == -1) {
                args.add(com);
            } else {
                args.add(com.substring(0, end));
            }
            if (quote) {
                com = com.substring(end + 1);
                end = com.indexOf(' ');
            }
            if (end != -1) {
                com = com.substring(end + 1);
            } else {
                break;
            }
        }
        HashMap<String, Boolean> out = new HashMap<String, Boolean>();

        comLoop: for (CommandDef c : command) {
            for (int i = 0; i < c.arguments.length; i++) {
                CommandArgument a = c.arguments[i];
                if (i == args.size() - 1) {
                    List<String> res = a.tabComplete(args.get(i));
                    if (res != null) {
                        for (String s : res) {
                            out.put(s, true);
                        }
                        continue comLoop;
                    }
                } else {
                    if (!a.isConst()) {
                        Object res = a.parse(args.get(i), locale);
                        if (res instanceof CommandError) {
                            continue comLoop;
                        }
                    } else {
                        ArgumentConst cst = (ArgumentConst) a;
                        if (!cst.value.equals(args.get(i))) {
                            continue comLoop;
                        }
                    }
                }
            }
        }
        ArrayList<String> outList = new ArrayList<String>();
        for (String s : out.keySet()) {
            outList.add(s);
        }
        return outList;
    }

    public static void register(CommandHandler handler) {
        Method[] methods = handler.getClass().getMethods();
        for (Method method : methods) {
            Class<?>[] params = method.getParameterTypes();
            CommandString comString = method.getAnnotation(CommandString.class);
            if (comString == null) {
                continue;
            }
            if (params.length == 0 || !params[0].isAssignableFrom(CommandSender.class)) {
                throw new RuntimeException("First argument must be CommandSender @ " + method.getName());
            }
            add(comString.value(), method, handler);
        }
        Collection<ArrayList<CommandDef>> coms = commands.values();
        for (ArrayList<CommandDef> c : coms) {
            Collections.sort(c);
        }
    }

    private static void add(String com, Method method, CommandHandler handler) {
        com = com.trim();
        int pos = com.indexOf(' ');
        String comName;
        if (pos == -1) {
            comName = com;
        } else {
            comName = com.substring(0, pos);
        }

        CommandDef def = new CommandDef();
        def.commandString = com;
        def.method = method;
        def.handler = handler;
        Class<?>[] params = method.getParameterTypes();
        if (method.isAnnotationPresent(CommandDocumentation.class)) {
            def.documentation = method.getAnnotation(CommandDocumentation.class).value();
        } else {
            def.documentation = "";
        }
        if (method.isAnnotationPresent(CommandGroup.class)) {
            def.sortKey = method.getAnnotation(CommandGroup.class).value();
        } else {
            def.sortKey = "";
        }
        CommandString comString = method.getAnnotation(CommandString.class);
        def.handlePermissions = comString.handlePermissions();

        if (!commands.containsKey(comName)) {
            commands.put(comName, new ArrayList<CommandDef>());
        }
        commands.get(comName).add(def);
        if (pos == -1) {
            def.arguments = new CommandArgument[0];
            return;
        }
        com = com.substring(pos + 1);
        ArrayList<CommandArgument> arguments = new ArrayList<CommandArgument>();
        int realArgumentsCount = 0;
        while (true) {
            pos = com.indexOf(' ');
            String a;
            if (pos == -1) {
                a = com;
            } else {
                a = com.substring(0, pos);
                com = com.substring(pos + 1);
            }
            if (a.charAt(0) == '$') { // Variable
                String name = "";
                if (a.contains(":")) {
                    String[] as = a.split(":");
                    name = as[0].substring(1);
                    a = "$" + as[1];
                }
                char t = a.charAt(1);
                Class<? extends CommandArgument> cAT = argTypes.get(t);
                if (cAT == null) {
                    throw new RuntimeException("Invalid command argument type " + t);
                }
                CommandArgument arg;
                try {
                    arg = cAT.newInstance();
                    arg.init(a.substring(3, a.length() - 1));
                    if (!params[realArgumentsCount + 1].isAssignableFrom(arg.getType())) {
                        throw new RuntimeException("Type mismatch for " + method.getName());
                    }
                    arg.name = name;
                    arguments.add(arg);
                    realArgumentsCount++;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else { // Const
                arguments.add(new ArgumentConst(a));
            }
            if (pos == -1) {
                break;
            }
        }
        if (params.length != realArgumentsCount + 1) {
            throw new RuntimeException("Argument count mis-match for " + method.getName());
        }
        def.arguments = new CommandArgument[arguments.size()];
        arguments.toArray(def.arguments);
    }

    static {
        register(new CommandHandler() {

            @CommandString("rpgitem help $terms:s[]")
            @CommandDocumentation("$command.rpgitem.help")
            @CommandGroup("help")
            public void help(CommandSender sender, String query) {
                searchHelp(sender, query);
            }
        });
    }

    public static void searchHelp(CommandSender sender, String terms) {
        if (terms.equalsIgnoreCase("_genhelp")) {
            for (String locale : Locale.getLocales()) {
                generateHelp(locale);
            }
            return;
        }
        String locale = sender instanceof Player ? Locale.getPlayerLocale((Player) sender) : "en_GB";
        sender.sendMessage(ChatColor.GREEN + String.format(Locale.get("message.help.for", locale), terms));
        String[] term = terms.toLowerCase().split(" ");
        for (Entry<String, ArrayList<CommandDef>> command : commands.entrySet()) {
            for (CommandDef c : command.getValue()) {
                int count = 0;
                for (String t : term) {
                    if (c.commandString.toLowerCase().contains(t)) {
                        count++;
                    }
                }
                if (count == term.length) {
                    StringBuilder buf = new StringBuilder();
                    buf.append(ChatColor.GREEN).append(ChatColor.BOLD).append('/').append(command.getKey());
                    for (CommandArgument a : c.arguments) {
                        buf.append(' ');
                        if (a.name.length() != 0) {
                            buf.append(ChatColor.RED).append(ChatColor.BOLD);
                            buf.append(Locale.get("command.info." + a.name, locale));
                        }
                        buf.append(a.isConst() ? ChatColor.GREEN : ChatColor.GOLD).append(ChatColor.BOLD);
                        buf.append(a.printable(locale));
                    }
                    sender.sendMessage(buf.toString());
                    String docStr = c.documentation;
                    if (docStr.charAt(0) == '$') {
                        if (docStr.contains("+")) {
                            String[] dArgs = docStr.split("\\+");
                            docStr = Locale.get(dArgs[0].substring(1), locale);
                            if (dArgs[1].equalsIgnoreCase("PotionEffectType")) {
                                StringBuilder out = new StringBuilder();
                                for (PotionEffectType type : PotionEffectType.values()) {
                                    if (type != null)
                                        out.append(type.getName().toLowerCase()).append(", ");
                                }
                                docStr += out.toString();
                            }
                        } else {
                            docStr = Locale.get(docStr.substring(1), locale);
                        }
                    }
                    docStr = docStr.replaceAll("@", "" + ChatColor.BLUE).replaceAll("#", "" + ChatColor.WHITE);
                    
                    StringBuilder docBuf = new StringBuilder();
                    char[] chars = docStr.toCharArray();
                    docBuf.append(ChatColor.WHITE);
                    for (int i = 0; i < chars.length; i++) {
                        char l = chars[i];
                        if (l == '&') {
                            i++;
                            l = chars[i];
                            switch (l) {
                            case '0':
                                docBuf.append(ChatColor.BLACK);
                                break;
                            case '1':
                                docBuf.append(ChatColor.DARK_BLUE);
                                break;
                            case '2':
                                docBuf.append(ChatColor.DARK_GREEN);
                                break;
                            case '3':
                                docBuf.append(ChatColor.DARK_AQUA);
                                break;
                            case '4':
                                docBuf.append(ChatColor.DARK_RED);
                                break;
                            case '5':
                                docBuf.append(ChatColor.DARK_PURPLE);
                                break;
                            case '6':
                                docBuf.append(ChatColor.GOLD);
                                break;
                            case '7':
                                docBuf.append(ChatColor.GRAY);
                                break;
                            case '8':
                                docBuf.append(ChatColor.DARK_GRAY);
                                break;
                            case '9':
                                docBuf.append(ChatColor.BLUE);
                                break;
                            case 'a':
                                docBuf.append(ChatColor.GREEN);
                                break;
                            case 'b':
                                docBuf.append(ChatColor.AQUA);
                                break;
                            case 'c':
                                docBuf.append(ChatColor.RED);
                                break;
                            case 'd':
                                docBuf.append(ChatColor.LIGHT_PURPLE);
                                break;
                            case 'e':
                                docBuf.append(ChatColor.YELLOW);
                                break;
                            case 'f':
                                docBuf.append(ChatColor.WHITE);
                                break;
                            case 'r':
                                docBuf.append(ChatColor.WHITE);
                                break;
                            }
                        } else {
                            docBuf.append(l);
                        }
                    }
                    sender.sendMessage(docBuf.toString());
                }
            }
        }
    }

    private static HashMap<String, String> getMap() {
        HashMap<String, String> langMap = new HashMap<String, String>();
        langMap.put("en_US", "English (US)");
        BufferedReader r = null;
        try {
            r = new BufferedReader(new InputStreamReader(Plugin.plugin.getResource("languages.txt"), "UTF-8"));
            String line = null;
            while ((line = r.readLine()) != null) {
                String []args = line.split("=");
                langMap.put(args[0], args[1]);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                r.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return langMap;        
    }
    
    public static void generateHelp(String locale) {
        BufferedWriter w = null;
        
        HashMap<String, String> langMap = getMap();
        
        try {
            File out = new File(Plugin.plugin.getDataFolder(), Calendar.getInstance().get(Calendar.YEAR) + "-" + Calendar.getInstance().get(Calendar.MONTH) + "-" + Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + "-" + locale + ".md");
            if (out.exists()) {
                out.delete();
            }
            w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(out), "UTF-8"));
            w.write("---\n");
            w.write("layout: locale\n");
            w.write("title: " + langMap.get(locale) + "\n");
            w.write("permalink: " + locale + ".html\n");
            w.write("---\n");
            for (Entry<String, ArrayList<CommandDef>> command : commands.entrySet()) {
                w.write(String.format("## Commands /%s ", command.getKey()));
                w.write("\n\n");
                for (CommandDef c : command.getValue()) {
                    StringBuilder buf = new StringBuilder();
                    buf.append("### /");
                    buf.append(command.getKey()).append(" ");
                    for (CommandArgument a : c.arguments) {
                        if (a.name.length() != 0) {
                            buf.append("<span style='color:#006EFF'>");
                            buf.append(Locale.get("command.info." + a.name, locale));
                            buf.append("</span>");
                        }
                        if (a.isConst())
                            buf.append("<span style='color:#b5e853'>");
                        else
                            buf.append("<span style='color:#1BE0BF'>");
                        buf.append(a.printable(locale));
                        buf.append("</span> ");
                    }
                    buf.append("\n");
                    String docStr = c.documentation;
                    if (docStr.charAt(0) == '$') {
                        if (docStr.contains("+")) {
                            String[] dArgs = docStr.split("\\+");
                            docStr = Locale.get(dArgs[0].substring(1), locale);
                            if (dArgs[1].equalsIgnoreCase("PotionEffectType")) {
                                StringBuilder out2 = new StringBuilder();
                                for (PotionEffectType type : PotionEffectType.values()) {
                                    if (type != null)
                                        out2.append(type.getName().toLowerCase()).append(", ");
                                }
                                docStr += out2.toString();
                            }
                        } else {
                            docStr = Locale.get(docStr.substring(1), locale);
                        }
                    }
                    docStr = docStr.replaceAll("#", "</span>").replaceAll("@", "<span style='color:#0000ff'>").replaceAll("`", "`` ` ``");
                    StringBuilder docBuf = new StringBuilder();
                    char[] chars = docStr.toCharArray();
                    for (int i = 0; i < chars.length; i++) {
                        char l = chars[i];
                        if (l == '&') {
                            i++;
                            l = chars[i];
                            if (l != 'r') {
                                docBuf.append("<span style='color:#");
                            }
                            switch (l) {
                            case '0':
                                docBuf.append("000000");
                                break;
                            case '1':
                                docBuf.append("0000aa");
                                break;
                            case '2':
                                docBuf.append("00aa00");
                                break;
                            case '3':
                                docBuf.append("00aaaa");
                                break;
                            case '4':
                                docBuf.append("aa0000");
                                break;
                            case '5':
                                docBuf.append("aa00aa");
                                break;
                            case '6':
                                docBuf.append("ffaa00");
                                break;
                            case '7':
                                docBuf.append("aaaaaa");
                                break;
                            case '8':
                                docBuf.append("555555");
                                break;
                            case '9':
                                docBuf.append("5555ff");
                                break;
                            case 'a':
                                docBuf.append("55ff55");
                                break;
                            case 'b':
                                docBuf.append("55ffff");
                                break;
                            case 'c':
                                docBuf.append("ff5555");
                                break;
                            case 'd':
                                docBuf.append("ff55ff");
                                break;
                            case 'e':
                                docBuf.append("ffff55");
                                break;
                            case 'f':
                                docBuf.append("ffffff");
                                break;
                            case 'r':
                                docBuf.append("'></span'");
                                break;
                            }
                            docBuf.append("'>");
                        } else {
                            docBuf.append(l);
                        }
                    }
                    buf.append(docBuf.toString());
                    buf.append("\n\n");
                    w.write(buf.toString());
                }
            }
            w.write("\n\n");
            w.write("Generated at: ");
            SimpleDateFormat sdf = new SimpleDateFormat();
            sdf.setTimeZone(new SimpleTimeZone(0, "GMT"));
            sdf.applyPattern("dd MMM yyyy HH:mm:ss z");
            w.write(sdf.format(new Date()));

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                w.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
} public class ConfigUpdater {

    final static String CONFIG_VERSION = "0.5";

    static HashMap<String, Updater> updates;
    static {
        updates = new HashMap<String, Updater>();
        updates.put("0.1", new Update01To02());
        updates.put("0.2", new Update02To03());
        updates.put("0.3", new Update03To04());
        updates.put("0.4", new Update04To05());
    }

    public static void updateConfig(ConfigurationSection conf) {
        while (!conf.getString("version", "0.0").equals(CONFIG_VERSION)) {
            if (!conf.contains("version")) {
                if (!conf.contains("autoupdate")) {
                    conf.set("autoupdate", true);
                }
                if (!conf.contains("defaults.hand")) {
                    conf.set("defaults.hand", "One handed");
                }
                if (!conf.contains("defaults.sword")) {
                    conf.set("defaults.sword", "Sword");
                }
                if (!conf.contains("defaults.damage")) {
                    conf.set("defaults.damage", "Damage");
                }
                if (!conf.contains("defaults.armour")) {
                    conf.set("defaults.armour", "Armour");
                }
                if (!conf.contains("support.worldguard")) {
                    conf.set("support.worldguard", false);
                }
                conf.set("version", "0.1");
                Plugin.plugin.saveConfig();
            } else {
                if (updates.containsKey(conf.get("version"))) {
                    updates.get(conf.get("version")).update(conf);
                } else {
                    break;
                }
            }
        }
        updates.clear();
    }
  } public class Font {
    public static int[] widths;

    public static void load() {
        widths = new int[0xFFFF];

        try {
            InputStream in = Plugin.plugin.getResource("font.bin");
            for (int i = 0; i < widths.length; i++) {
                widths[i] = in.read();
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
} public class Locale extends BukkitRunnable {
    
    private static HashMap<String, HashMap<String, String>> localeStrings = new HashMap<String, HashMap<String,String>>();
    private static FileConfiguration config = think.rpgitems.Plugin.config;
    private Plugin plugin;
    private long lastUpdate = 0;
    private File dataFolder;
    private String version;
    private Locale(Plugin plugin) {
        this.plugin = plugin;
        lastUpdate = plugin.getConfig().getLong("lastLocaleUpdate", 0);
        version = plugin.getDescription().getVersion();
        if (!plugin.getConfig().getString("pluginVersion", "0.0").equals(version)) {
            lastUpdate = 0;
            plugin.getConfig().set("pluginVersion", version);
            plugin.saveConfig();
        }
        dataFolder = plugin.getDataFolder();
        reloadLocales(plugin);
        if (!plugin.getConfig().contains("localeDownload")) {
            plugin.getConfig().set("localeDownload", true);
            plugin.saveConfig();
        }
    }
    
    private final static String localeUpdateURL = "http://198.199.127.128/rpgitems/index.php?page=localeget&lastupdate=";
    private final static String localeDownloadURL = "http://www.rpgitems2.bugs3.com/locale/%s/%s.lang";
    
    public static Set<String> getLocales() {
        return localeStrings.keySet();
    }

    @Override
    public void run() {
        if (!plugin.getConfig().getBoolean("localeDownload", true)) {
            cancel();
        }
        try {
            URL updateURL = new URL(localeUpdateURL + lastUpdate);
            lastUpdate = System.currentTimeMillis();
            URLConnection conn = updateURL.openConnection();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));     
            ArrayList<String> locales = new ArrayList<String>();
            String line = null;
            while ((line = reader.readLine()) != null) {
                locales.add(line);
            }
            reader.close();
            File localesFolder = new File(dataFolder, "locale/");
            localesFolder.mkdirs();
            for (String locale : locales) {
                URL downloadURL = new URL(String.format(localeDownloadURL, version, locale));
                File outFile = new File(dataFolder, "locale/" + locale + ".lang");
                InputStream in = downloadURL.openStream();
                FileOutputStream out = new FileOutputStream(outFile);
                byte []buf = new byte[1024];
                int bytesRead;
                while ((bytesRead = in.read(buf)) != -1) {
                    out.write(buf, 0, bytesRead);
                }
                in.close();
                out.close();
            }
        } catch (Exception e) {
            return;
        }
        (new BukkitRunnable() {            
            @Override
            public void run() {
                ConfigurationSection config = plugin.getConfig();
                config.set("lastLocaleUpdate", lastUpdate);
                plugin.saveConfig();
                reloadLocales(plugin);
                for (RPGItem item : ItemManager.itemById.valueCollection()) {
                    item.rebuild();
                }
            }
        }).runTask(plugin);
    }
    
    public static void reloadLocales(Plugin plugin) {
        localeStrings.clear();
        localeStrings.put("en_GB", loadLocaleStream(plugin.getResource("locale/en_GB.lang")));
        localeStrings.put("fr_FR", loadLocaleStream(plugin.getResource("locale/fr_FR.lang")));
        localeStrings.put("es_ES", loadLocaleStream(plugin.getResource("locale/es_ES.lang")));
    }
    
    private static HashMap<String, String> loadLocaleStream(InputStream in, HashMap<String, String> map) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
            String line = null;
            while((line = reader.readLine()) != null) {
                if (line.startsWith("#")) continue;
                String[] args = line.split("=");
                map.put(args[0].trim(), args[1].trim());
            }
            return map;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    private static HashMap<String, String> loadLocaleStream(InputStream in) {
        return loadLocaleStream(in, new HashMap<String, String>());
    }

    public static String getPlayerLocale(Player player) {
    	String language = config.getString("language");
    	
    	if(language.equals("es_ES")){
    		return "es_ES";
    	}else if(language.equals("fr_FR")){
    		return "fr_FR";
    	}else if(language.equals("en_GB")){
    		return "en_GB";
    	}else{
    		Plugin.plugin.getLogger().warning("Error language you've set : '" + language + "' isn't supported or don't exist ! Languages aviables are es_ES, fr_FR and en_GB");
    		return "en_GB";
    	}
    }

    public static void init(Plugin plugin) {
        (new Locale(plugin)).runTaskTimerAsynchronously(plugin, 0, 24l * 60l * 60l * 20l);
    }
    
    public static String get(String key, String locale) {
        if (!localeStrings.containsKey(locale))
            return get(key);
        HashMap<String, String> strings = localeStrings.get(locale);
        if (strings == null || !strings.containsKey(key)){
        	return get(key);
        }
        return strings.get(key);
    }
    
    private static String get(String key) {
        HashMap<String, String> strings = localeStrings.get("en_GB");
        if (!strings.containsKey(key))
            return "!" + key + "!";
        return strings.get(key);
    }
} public class ItemManager {
    public static TIntObjectHashMap<RPGItem> itemById = new TIntObjectHashMap<RPGItem>();
    public static HashMap<String, RPGItem> itemByName = new HashMap<String, RPGItem>();
    public static HashMap<String, ItemGroup> groups = new HashMap<String, ItemGroup>();
    public static int currentPos = 0;

    public static void load(Plugin plugin) {
        try {
            FileInputStream in = null;
            YamlConfiguration itemStorage = null;
            try {
                File f = new File(plugin.getDataFolder(), "items.yml");
                in = new FileInputStream(f);
                byte[] data = new byte[(int) f.length()];
                in.read(data);
                itemStorage = new YamlConfiguration();
                String str = new String(data, "UTF-8");
                itemStorage.loadFromString(str);
            } catch (FileNotFoundException e) {
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InvalidConfigurationException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (in != null)
                        in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            currentPos = itemStorage.getInt("pos", 0);
            ConfigurationSection section = itemStorage.getConfigurationSection("items");
            if (section == null) return;
            for (String key : section.getKeys(false)) {
                RPGItem item = new RPGItem(section.getConfigurationSection(key));
                itemById.put(item.getID(), item);
                itemByName.put(item.getName(), item);
                for (Power power : item.powers) {
                    Power.powerUsage.put(power.getName(), Power.powerUsage.get(power.getName()) + 1);
                }
            }
            
            if (itemStorage.contains("groups")) {
                ConfigurationSection gSection = itemStorage.getConfigurationSection("groups");
                for (String key : gSection.getKeys(false)) {
                    ItemGroup group = new ItemGroup(gSection.getConfigurationSection(key));
                    groups.put(group.getName(), group);
                }
            }
        } catch (Exception e) {
            //Something went wrong
            plugin.getLogger().severe("Error loading items.yml. Creating backup");
            File file = new File(plugin.getDataFolder(), "items.yml");
            long time = System.currentTimeMillis();
            File backup = new File(plugin.getDataFolder(), time + "-items.yml");
            FileUtil.copy(file, backup);
            File log = new File(plugin.getDataFolder(), time + "-log.txt");
            PrintStream ps = null;
            try {
                ps = new PrintStream(log);
                ps.printf("RPGItems (%s) ItemManager.load\r\n", plugin.getDescription().getVersion());
                e.printStackTrace(ps);
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            } finally {
                ps.close();
            }
        }
    }

    public static void save(Plugin plugin) {

        YamlConfiguration itemStorage = new YamlConfiguration();

        itemStorage.set("items", null);
        itemStorage.set("pos", currentPos);
        ConfigurationSection newSection = itemStorage.createSection("items");
        for (RPGItem item : itemById.valueCollection()) {
            ConfigurationSection itemSection = newSection.getConfigurationSection(item.getName());
            if (itemSection == null) {
                itemSection = newSection.createSection(item.getName());
            }
            item.save(itemSection);
        }

        ConfigurationSection groupsSection = itemStorage.createSection("groups");
        
        for (Entry<String, ItemGroup> group : groups.entrySet()) {
            ConfigurationSection groupSection = groupsSection.createSection(group.getKey());
            group.getValue().save(groupSection);
        }
        
        FileOutputStream out = null;
        try {
            File f = new File(plugin.getDataFolder(), "items.yml");
            out = new FileOutputStream(f);
            out.write(itemStorage.saveToString().getBytes("UTF-8"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static RPGItem toRPGItem(ItemStack item) {
        if (item == null)
            return null;
        if (!item.hasItemMeta())
            return null;
        ItemMeta meta = item.getItemMeta();
        if (!meta.hasDisplayName())
            return null;
        try {
            int id = ItemManager.decodeId(meta.getDisplayName());
            RPGItem rItem = ItemManager.getItemById(id);
            return rItem;
        } catch (Exception e) {
            return null;
        }
    }

    public static RPGItem newItem(String name) {
        if (itemByName.containsKey(name))
            return null;
        int free = 0;
        while (true) {
            free = currentPos++;
            if (!itemById.containsKey(free))
                break;
        }
        RPGItem item = new RPGItem(name, free);
        itemById.put(free, item);
        itemByName.put(name, item);
        return item;
    }

    public static RPGItem getItemById(int id) {
        return itemById.get(id);
    }

    public static RPGItem getItemByName(String uid) {
        return itemByName.get(uid);
    }

    public static int decodeId(String str) throws Exception {
        if (str.length() < 16) {
            throw new Exception();
        }
        StringBuilder out = new StringBuilder();
        for (int i = 0; i < 16; i++) {
            if (str.charAt(i) != ChatColor.COLOR_CHAR)
                throw new Exception();
            i++;
            out.append(str.charAt(i));
        }
        return Integer.parseInt(out.toString(), 16);
    }

    public static void remove(RPGItem item) {
        itemByName.remove(item.getName());
        itemById.remove(item.getID());
    }

} public abstract class Power {

    public static HashMap<String, Class<? extends Power>> powers = new HashMap<String, Class<? extends Power>>();
    public static TObjectIntHashMap<String> powerUsage = new TObjectIntHashMap<String>();

    public RPGItem item;

    public Power() {

    }

    public abstract void init(ConfigurationSection s);

    public abstract void save(ConfigurationSection s);

    public abstract String getName();

    public abstract String displayText(String locale);

    public static Entity[] getNearbyEntities(Location l, double radius) {
        int iRadius = (int) radius;
        int chunkRadius = iRadius < 16 ? 1 : (iRadius - (iRadius % 16)) / 16;
        HashSet<Entity> radiusEntities = new HashSet<Entity>();
        for (int chX = 0 - chunkRadius; chX <= chunkRadius; chX++) {
            for (int chZ = 0 - chunkRadius; chZ <= chunkRadius; chZ++) {
                int x = (int) l.getX(), y = (int) l.getY(), z = (int) l.getZ();
                for (Entity e : new Location(l.getWorld(), x + (chX * 16), y, z + (chZ * 16)).getChunk().getEntities()) {
                    if (e.getLocation().distance(l) <= radius && e.getLocation().getBlock() != l.getBlock())
                        radiusEntities.add(e);
                }
            }
        }
        return radiusEntities.toArray(new Entity[radiusEntities.size()]);
    }
} public class PowerArrow extends Power implements PowerRightClick{

    public long cooldownTime = 20;

    @Override
    public void rightClick(Player player) {
        long cooldown;
       if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
       }else{ 
    	   RPGValue value = RPGValue.get(player, item, "arrow.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "arrow.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            player.playSound(player.getLocation(), Sound.SHOOT_ARROW, 1.0f, 1.0f);
            Arrow arrow = player.launchProjectile(Arrow.class);
            Events.removeArrows.put(arrow.getEntityId(), (byte) 1);
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
       }
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.arrow", locale), (double) cooldownTime / 20d);
    }

    @Override
    public String getName() {
        return "arrow";
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown", 20);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
    }
} public class PowerCommand extends Power implements PowerRightClick, PowerLeftClick {

    public String command = "";
    public String display = "Runs command";
    public String permission = "";
    public boolean isRight = true;
    public long cooldownTime = 20;

    @Override
    public void rightClick(Player player) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{  
    	if (isRight) {
            long cooldown;
            RPGValue value = RPGValue.get(player, item, "command." + command + ".cooldown");
            if (value == null) {
                cooldown = System.currentTimeMillis() / 50;
                value = new RPGValue(player, item, "command." + command + ".cooldown", cooldown);
            } else {
                cooldown = value.asLong();
            }
            if (cooldown <= System.currentTimeMillis() / 50) {
                value.set(System.currentTimeMillis() / 50 + cooldownTime);
                if (permission.length() != 0 && !permission.equals("*")) {
                    PermissionAttachment attachment = player.addAttachment(Plugin.plugin, 1);
                    String[] perms = permission.split("\\.");
                    StringBuilder p = new StringBuilder();
                    for (int i = 0; i < perms.length; i++) {
                        p.append(perms[i]);
                        attachment.setPermission(p.toString(), true);
                        p.append('.');
                    }
                }
                boolean wasOp = player.isOp();
                if (permission.equals("*"))
                    player.setOp(true);
                player.chat("/" + command.replaceAll("\\{player\\}", player.getName()));
                if (permission.equals("*"))
                    player.setOp(wasOp);
            } else {
                player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
            }
        }
        }
    }

    @Override
    public void leftClick(Player player) {
        if (!isRight) {
            long cooldown;
            RPGValue value = RPGValue.get(player, item, "command." + command + ".cooldown");
            if (value == null) {
                cooldown = System.currentTimeMillis() / 50;
                value = new RPGValue(player, item, "command." + command + ".cooldown", cooldown);
            } else {
                cooldown = value.asLong();
            }
            if (cooldown <= System.currentTimeMillis() / 50) {
                value.set(System.currentTimeMillis() / 50 + cooldownTime);
                if (permission.length() != 0 && !permission.equals("*")) {
                    PermissionAttachment attachment = player.addAttachment(Plugin.plugin, 1);
                    String[] perms = permission.split("\\.");
                    StringBuilder p = new StringBuilder();
                    for (int i = 0; i < perms.length; i++) {
                        p.append(perms[i]);
                        attachment.setPermission(p.toString(), true);
                        p.append('.');
                    }
                }
                boolean wasOp = player.isOp();
                if (permission.equals("*"))
                    player.setOp(true);
                player.chat("/" + command.replaceAll("\\{player\\}", player.getName()));
                if (permission.equals("*"))
                    player.setOp(wasOp);
            } else {
                player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
            }
        }
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + display;
    }

    @Override
    public String getName() {
        return "command";
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown", 20);
        command = s.getString("command", "");
        display = s.getString("display", "");
        isRight = s.getBoolean("isRight", true);
        permission = s.getString("permission", "");
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
        s.set("command", command);
        s.set("display", display);
        s.set("isRight", isRight);
        s.set("permission", permission);
    }
} public class PowerConsume extends Power implements PowerRightClick {

    @Override
    public void rightClick(Player player) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{
        ItemStack item = player.getInventory().getItemInHand();
        int count = item.getAmount() - 1;
        if (count == 0) {
            item.setAmount(0);
            item.setType(Material.AIR);
            player.setItemInHand(null);
        } else {
            item.setAmount(count);
        }
        }
    }

    @Override
    public void init(ConfigurationSection s) {

    }

    @Override
    public void save(ConfigurationSection s) {

    }

    @Override
    public String getName() {
        return "consume";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + Locale.get("power.consume", locale);
    }
} public class PowerFireball extends Power implements PowerRightClick {

    public long cooldownTime = 20;

    @Override
    public void rightClick(Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{
        RPGValue value = RPGValue.get(player, item, "tnt.fireball");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "tnt.fireball", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            player.playSound(player.getLocation(), Sound.GHAST_FIREBALL, 1.0f, 1.0f);
            player.launchProjectile(SmallFireball.class);
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
        }
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.fireball", locale), (double) cooldownTime / 20d);
    }

    @Override
    public String getName() {
        return "fireball";
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown", 20);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
    }
} public class PowerFlame extends Power implements PowerHit {

    public int burnTime = 20;

    @Override
    public void hit(Player player, LivingEntity e, double damage) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{  
    	e.setFireTicks(burnTime);
    }
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.flame", locale), (double) burnTime / 20d);
    }

    @Override
    public String getName() {
        return "flame";
    }

    @Override
    public void init(ConfigurationSection s) {
        burnTime = s.getInt("burntime");
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("burntime", burnTime);
    }
} public class PowerFood extends Power implements PowerRightClick {
	public int foodpoints;
	@Override
    public void rightClick(Player player) {
	       if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
	       }else{
          ItemStack item = player.getInventory().getItemInHand();
          int count = item.getAmount() - 1;
          if (count == 0) {
        	player.setFoodLevel(player.getFoodLevel() + foodpoints);
            item.setAmount(0);
            item.setType(Material.AIR);
            player.setItemInHand(item);
          } else {
        	player.setFoodLevel(player.getFoodLevel() + foodpoints);
            item.setAmount(count);
        }
	  }
    }

    @Override
    public void init(ConfigurationSection s) {
      foodpoints = s.getInt("foodpoints");
    }

    @Override
    public void save(ConfigurationSection s) {
      s.set("foodpoints", foodpoints); 
    }

    @Override
    public String getName() {
        return "food";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.food", locale),foodpoints);
    }
} public class PowerIce extends Power implements PowerRightClick {

    public long cooldownTime = 20;

    @Override
    public void rightClick(final Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{  
        RPGValue value = RPGValue.get(player, item, "ice.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "ice.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            player.playSound(player.getLocation(), Sound.FIZZ, 1.0f, 0.1f);
            final FallingBlock block = player.getWorld().spawnFallingBlock(player.getLocation().add(0, 1.8, 0), Material.ICE, (byte) 0);
            block.setVelocity(player.getLocation().getDirection().multiply(2d));
            block.setDropItem(false);
            BukkitRunnable run = new BukkitRunnable() {

                @SuppressWarnings("deprecation")
				public void run() {
                    boolean hit = false;
                    World world = block.getWorld();
                    Location bLoc = block.getLocation();
                    loop: for (int x = -1; x < 2; x++) {
                        for (int y = -1; y < 2; y++) {
                            for (int z = -1; z < 2; z++) {
                                Location loc = block.getLocation().add(x, y, z);
                                if (world.getBlockTypeIdAt(loc) != Material.AIR.getId()) {
                                    Block b = world.getBlockAt(loc);
                                    if (b.getType().isSolid()) {
                                        if (checkBlock(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), 1, 1, 1, bLoc.getX() - 0.5d, bLoc.getY() - 0.5d, bLoc.getZ() - 0.5d, 1, 1, 1)) {
                                            hit = true;
                                            break loop;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (!hit) {
                        List<Entity> entities = block.getNearbyEntities(1, 1, 1);
                        for (Entity e : entities) {
                            if (e != player) {
                                hit = true;
                                break;
                            }
                        }
                    }
                    if (block.isDead() || hit) {
                        block.remove();
                        block.getLocation().getBlock().setType(Material.AIR);
                        cancel();
                        final TObjectLongHashMap<Location> changedBlocks = new gnu.trove.map.hash.TObjectLongHashMap<Location>();
                        for (int x = -1; x < 2; x++) {
                            for (int y = -1; y < 3; y++) {
                                for (int z = -1; z < 2; z++) {
                                    Location loc = block.getLocation().add(x, y, z);
                                    Block b = world.getBlockAt(loc);
                                    if (!b.getType().isSolid()) {
                                        changedBlocks.put(b.getLocation(), b.getTypeId() | (b.getData() << 16));
                                        b.setType(Material.ICE);
                                    }
                                }
                            }
                        }
                        (new BukkitRunnable() {
                            Random random = new Random();

                            @SuppressWarnings("deprecation")
							public void run() {
                                for (int i = 0; i < 4; i++) {
                                    if (changedBlocks.isEmpty()) {
                                        cancel();
                                        return;
                                    }
                                    int index = random.nextInt(changedBlocks.size());
                                    long data = changedBlocks.values()[index];
                                    Location position = (Location) changedBlocks.keys()[index];
                                    changedBlocks.remove(position);
                                    Block c = position.getBlock();
                                    position.getWorld().playEffect(position, Effect.STEP_SOUND, c.getTypeId());
                                    c.setTypeId((int) (data & 0xFFFF));
                                    c.setData((byte) (data >> 16));
                                }

                            }
                        }).runTaskTimer(Plugin.plugin, 4 * 20 + new Random().nextInt(40), 3);
                    }

                }
            };
            run.runTaskTimer(Plugin.plugin, 0, 1);

        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
        }
    }

    private boolean checkBlock(double x1, double y1, double z1, double w1, double h1, double d1, double x2, double y2, double z2, double w2, double h2, double d2) {
        if (x1 + w1 < x2)
            return false;
        if (x2 + w2 < x1)
            return false;
        if (y1 + h1 < y2)
            return false;
        if (y2 + h2 < y1)
            return false;
        if (z1 + d1 < z2)
            return false;
        if (z2 + d2 < z1)
            return false;

        return true;
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.ice", locale), (double) cooldownTime / 20d);
    }

    @Override
    public String getName() {
        return "ice";
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown", 20);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
    }
} public class PowerKnockup extends Power implements PowerHit {

    public int chance = 20;
    public double power = 2;

    private Random rand = new Random();

    @Override
    public void hit(Player player, LivingEntity e, double damage) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else if (rand.nextInt(chance) == 0)
            e.setVelocity(player.getLocation().getDirection().setY(power));
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.knockup", locale), (int) ((1d / (double) chance) * 100d));
    }

    @Override
    public String getName() {
        return "knockup";
    }

    @Override
    public void init(ConfigurationSection s) {
        chance = s.getInt("chance");
        power = s.getDouble("power", 2);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("chance", chance);
        s.set("power", power);
    }

} public class PowerLifeSteal extends Power implements PowerHit {

    public int chance = 20;
    private Random random = new Random();
    @Override
    public void hit(Player player, LivingEntity e, double damage) {
    	if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else if (random.nextInt(chance) == 0){
          if ((player.getHealth() + damage) >= player.getMaxHealth()){
        	  player.setHealth(player.getMaxHealth());
          }else
        	player.setHealth(player.getHealth() + damage);
    }
    }	

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.lifesteal", locale), (double) chance);
    }

    @Override
    public String getName() {
        return "lifesteal";
    }

    @Override
    public void init(ConfigurationSection s) {
        chance = s.getInt("chance");
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("chance", chance);
    }
} public class PowerLightning extends Power implements PowerHit, PowerProjectileHit {

    public int chance = 20;
    private Random random = new Random();

    @Override
    public void hit(Player player, LivingEntity e, double damage) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else if (random.nextInt(chance) == 0)
            e.getWorld().strikeLightning(e.getLocation());
    }

    @Override
    public void projectileHit(Player player, Projectile p) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
     	   player.sendMessage(ChatColor.RED + String.format(Locale.get("message.error.permission", Locale.getPlayerLocale(player))));
        }else if (random.nextInt(chance) == 0)
            p.getWorld().strikeLightning(p.getLocation());
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.lightning", locale), (int) ((1d / (double) chance) * 100d));
    }

    @Override
    public String getName() {
        return "lightning";
    }

    @Override
    public void init(ConfigurationSection s) {
        chance = s.getInt("chance");
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("chance", chance);
    }
} public class PowerPotionHit extends Power implements PowerHit {

    public int chance = 20;
    private Random random = new Random();
    public PotionEffectType type = PotionEffectType.HARM;
    public int duration = 20;
    public int amplifier = 1;

    @Override
    public void hit(Player player, LivingEntity e, double damage) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else if (random.nextInt(chance) == 0)
            e.addPotionEffect(new PotionEffect(type, duration, amplifier));
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.potionhit", locale), (int) ((1d / (double) chance) * 100d), type.getName().toLowerCase().replace('_', ' '));
    }

    @Override
    public String getName() {
        return "potionhit";
    }

    @Override
    public void init(ConfigurationSection s) {
        chance = s.getInt("chance", 20);
        duration = s.getInt("duration", 20);
        amplifier = s.getInt("amplifier", 1);
        type = PotionEffectType.getByName(s.getString("type", PotionEffectType.HARM.getName()));
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("chance", chance);
        s.set("duration", duration);
        s.set("amplifier", amplifier);
        s.set("type", type.getName());
    }
} public class PowerPotionSelf extends Power implements PowerRightClick {

    public long cooldownTime = 20;
    public int amplifier = 3;
    public int time = 20;
    public PotionEffectType type = PotionEffectType.HEAL;

    @Override
    public void rightClick(Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{  
        RPGValue value = RPGValue.get(player, item, "potionself.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "potionself.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            player.addPotionEffect(new PotionEffect(type, time, amplifier));
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
        }
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown");
        amplifier = s.getInt("amp");
        time = s.getInt("time");
        type = PotionEffectType.getByName(s.getString("type", "heal"));
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
        s.set("amp", amplifier);
        s.set("time", time);
        s.set("type", type.getName());
    }

    @Override
    public String getName() {
        return "potionself";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.potionself", locale), type.getName().toLowerCase().replaceAll("_", " "), amplifier + 1, ((double) time) / 20d);
    }

} public class PowerPotionTick extends Power implements PowerTick {

    public int amplifier = 2;
    public PotionEffectType effect = PotionEffectType.SPEED;

    @Override
    public void tick(Player player) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
     	   player.sendMessage(ChatColor.RED + String.format(Locale.get("message.error.permission", Locale.getPlayerLocale(player))));
        }else{  
    	boolean hasEffect = false;
        for (PotionEffect potionEffect : player.getActivePotionEffects()) {
            if (potionEffect.getType().equals(effect) && potionEffect.getDuration() == 25) {
                player.addPotionEffect(new PotionEffect(effect, 30, amplifier, true), true);
                hasEffect = true;
                break;
            }
        }
        if (!hasEffect) {
            player.addPotionEffect(new PotionEffect(effect, 30, amplifier, true), true);
        }
        }

    }

    @Override
    public void init(ConfigurationSection s) {
        amplifier = s.getInt("amplifier");
        effect = PotionEffectType.getByName(s.getString("effect", "heal"));

    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("amplifier", amplifier);
        s.set("effect", effect.getName());

    }

    @Override
    public String getName() {
        return "potiontick";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.potiontick", locale), effect.getName().toLowerCase().replaceAll("_", " "), amplifier + 1);
    }

} public class PowerRainbow extends Power implements PowerRightClick {

    public long cooldownTime = 20;
    public int count = 5;
    private Random random = new Random();

    @Override
    public void rightClick(Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{
        RPGValue value = RPGValue.get(player, item, "arrow.rainbow");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "arrow.rainbow", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            player.playSound(player.getLocation(), Sound.SHOOT_ARROW, 1.0f, 1.0f);
            final ArrayList<FallingBlock> blocks = new ArrayList<FallingBlock>();
            for (int i = 0; i < count; i++) {
                FallingBlock block = player.getWorld().spawnFallingBlock(player.getLocation().add(0, 1.8, 0), Material.WOOL, (byte) random.nextInt(16));
                block.setVelocity(player.getLocation().getDirection().multiply(new Vector(random.nextDouble() * 2d + 0.5, random.nextDouble() * 2d + 0.5, random.nextDouble() * 2d + 0.5)));
                block.setDropItem(false);
                blocks.add(block);
            }
            (new BukkitRunnable() {

                ArrayList<Location> fallLocs = new ArrayList<Location>();
                Random random = new Random();

                public void run() {

                    Iterator<Location> l = fallLocs.iterator();
                    while (l.hasNext()) {
                        Location loc = l.next();
                        if (random.nextBoolean()) {
                            Block b = loc.getBlock();
                            if (b.getType() == Material.WOOL) {
                                loc.getWorld().playEffect(loc, Effect.STEP_SOUND, Material.WOOL.getId(), b.getData());
                                b.setType(Material.AIR);
                            }
                            l.remove();
                        }
                        if (random.nextInt(5) == 0) {
                            break;
                        }
                    }

                    Iterator<FallingBlock> it = blocks.iterator();
                    while (it.hasNext()) {
                        FallingBlock block = it.next();
                        if (block.isDead()) {
                            fallLocs.add(block.getLocation());
                            it.remove();
                        }
                    }

                    if (fallLocs.isEmpty() && blocks.isEmpty()) {
                        cancel();
                    }

                }
            }).runTaskTimer(Plugin.plugin, 0, 5);
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
        }
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.rainbow", locale), count, (double) cooldownTime / 20d);
    }

    @Override
    public String getName() {
        return "rainbow";
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown", 20);
        count = s.getInt("count", 5);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
        s.set("count", count);
    }
} public class PowerRumble extends Power implements PowerRightClick {

    public long cooldownTime = 20;
    public int power = 2;
    public int distance = 15;

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown", 20);
        power = s.getInt("power", 2);
        distance = s.getInt("distance", 15);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
        s.set("power", power);
        s.set("distance", distance);
    }

    @Override
    public void rightClick(final Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{
        RPGValue value = RPGValue.get(player, item, "rumble.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "rumble.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            final Location location = player.getLocation().add(0, -0.2, 0);
            final Vector direction = player.getLocation().getDirection();
            direction.setY(0);
            direction.normalize();
            BukkitRunnable task = new BukkitRunnable() {

                private int count = 0;

                public void run() {
                    Location above = location.clone().add(0, 1, 0);
                    if (above.getBlock().getType().isSolid() || !location.getBlock().getType().isSolid()) {
                        cancel();
                        return;
                    }

                    Location temp = location.clone();
                    for (int x = -2; x <= 2; x++) {
                        for (int z = -2; z <= 2; z++) {
                            temp.setX(x + location.getBlockX());
                            temp.setZ(z + location.getBlockZ());
                            Block block = temp.getBlock();
                            temp.getWorld().playEffect(temp, Effect.STEP_SOUND, block.getTypeId());
                        }
                    }
                    Entity[] near = getNearbyEntities(location, 1.5);
                    boolean hit = false;
                    Random random = new Random();
                    for (Entity e : near) {
                        if (e != player) {
                            hit = true;
                            break;
                        }
                    }
                    if (hit) {
                        location.getWorld().createExplosion(location.getX(), location.getY(), location.getZ(), power, false, false);
                        near = getNearbyEntities(location, 2.5);
                        for (Entity e : near) {
                            if (e != player)
                                e.setVelocity(new Vector(random.nextGaussian() / 4d, 1d + random.nextDouble() * (double) power, random.nextGaussian() / 4d));
                        }
                        cancel();
                        return;
                    }
                    location.add(direction);
                    if (count >= distance) {
                        cancel();
                    }
                    count++;
                }
            };
            task.runTaskTimer(Plugin.plugin, 0, 3);
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
        }
    }

    @Override
    public String getName() {
        return "rumble";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.rumble", locale), (double) cooldownTime / 20d);
    }
} @Deprecated
public class PowerRush extends Power implements PowerRightClick {

    private long cd = 20;
    private int speed = 3;
    private int time = 20;

    @Override
    public void rightClick(Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{
        RPGValue value = RPGValue.get(player, item, "rush.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "rush.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cd);
            player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, time, speed));
        }
        }
    }

    @Override
    public void init(ConfigurationSection s) {
        cd = s.getLong("cooldown");
        speed = s.getInt("speed");
        time = s.getInt("time");
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cd);
        s.set("speed", speed);
        s.set("time", time);
    }

    @Override
    public String getName() {
        return "rush";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + "Gives temporary speed boost";
    }

} public class PowerSkyHook extends Power implements PowerRightClick {
    
    public Material railMaterial = Material.GLASS;
    public int hookDistance = 10;
    
    @Override
    public void rightClick(final Player player) {
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{ 
    	RPGValue isHooking = RPGValue.get(player, item, "skyhook.isHooking");
        if (isHooking == null) {
            isHooking = new RPGValue(player, item, "skyhook.isHooking", false);
        }
        if (isHooking.asBoolean()) {
            player.setVelocity(player.getLocation().getDirection());
            isHooking.set(false);
            return;
        }
        Block block = player.getTargetBlock(null, hookDistance);
        if (block.getType() != railMaterial) {
            player.sendMessage(ChatColor.AQUA + Locale.get("message.skyhook.fail", Locale.getPlayerLocale(player)));
            return;
        }
        isHooking.set(true);
        final Location location = player.getLocation();
        player.setAllowFlight(true);
        player.setVelocity(location.getDirection().multiply(block.getLocation().distance(location) / 2d));
        player.setFlying(true);
        (new BukkitRunnable() {
            
            private int delay = 0;
            
            @Override
            public void run() {
                if (!player.getAllowFlight()) {
                    cancel();
                    RPGValue.get(player, item, "skyhook.isHooking").set(false);
                    return;
                }
                if (!RPGValue.get(player, item, "skyhook.isHooking").asBoolean()) {
                    player.setFlying(false);
                    if (player.getGameMode() != GameMode.CREATIVE) 
                        player.setAllowFlight(false);
                    cancel();
                    return;
                }
                player.setFlying(true);
                player.getLocation(location);
                location.add(0, 2.4, 0);
                if (delay < 20) {
                    delay++;
                    if (location.getBlock().getType() == railMaterial) {
                        delay = 20;
                    }
                    return;
                }
                Vector dir = location.getDirection().setY(0).normalize();
                location.add(dir);
                if (location.getBlock().getType() != railMaterial) {
                    player.setFlying(false);
                    if (player.getGameMode() != GameMode.CREATIVE) 
                        player.setAllowFlight(false);
                    cancel();
                    RPGValue.get(player, item, "skyhook.isHooking").set(false);
                    return;
                }
                player.setVelocity(dir.multiply(0.5));
                
            }
        }).runTaskTimer(Plugin.plugin, 0, 0);
    }
    }
    @Override
    public void init(ConfigurationSection s) {
        railMaterial = Material.valueOf(s.getString("railMaterial", "GLASS"));
        hookDistance = s.getInt("hookDistance", 10);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("railMaterial", railMaterial.toString());
        s.set("hookDistance", hookDistance);
    }

    @Override
    public String getName() {
        return "skyhook";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + Locale.get("power.skyhook", locale);
    }

} public class PowerTNTCannon extends Power implements PowerRightClick {

    public long cooldownTime = 20;

    @Override
    public void rightClick(Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{
        RPGValue value = RPGValue.get(player, item, "tnt.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "tnt.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            player.playSound(player.getLocation(), Sound.SHOOT_ARROW, 1.0f, 1.0f);
            TNTPrimed tnt = player.getWorld().spawn(player.getLocation().add(0, 1.8, 0), TNTPrimed.class);
            tnt.setVelocity(player.getLocation().getDirection().multiply(2d));
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
        }
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.tntcannon", locale), (double) cooldownTime / 20d);
    }

    @Override
    public String getName() {
        return "tntcannon";
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown", 20);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
    }
} public class PowerTeleport extends Power implements PowerRightClick, PowerProjectileHit {

    public int distance = 5;
    public long cooldownTime = 20;

    @Override
    public void rightClick(Player player) {
        long cooldown;
        if (item.getHasPermission() == true && player.hasPermission(item.getPermission()) == false){
        }else{
        RPGValue value = RPGValue.get(player, item, "teleport.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "teleport.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            // float dist = 0;
            World world = player.getWorld();
            Location start = player.getLocation();
            start.setY(start.getY() + 1.6);
            // Location current = new Location(world, 0, 0, 0);
            Block lastSafe = world.getBlockAt(start);
            // Keeping the old method because BlockIterator could get removed (irc)
            // double dir = Math.toRadians(start.getYaw()) + (Math.PI / 2d);
            // double dirY = Math.toRadians(start.getPitch()) + (Math.PI / 2d);
            BlockIterator bi = new BlockIterator(player, distance);
            // while (dist < distance) {
            while (bi.hasNext()) {
                // current.setX(start.getX() + dist * Math.cos(dir) *
                // Math.sin(dirY));
                // current.setY(start.getY() + dist * Math.cos(dirY));
                // current.setZ(start.getZ() + dist * Math.sin(dir) *
                // Math.sin(dirY));
                Block block = bi.next();// world.getBlockAt(current);
                if (!block.getType().isSolid() || (block.getType() == Material.AIR)) {
                    lastSafe = block;
                } else {
                    break;
                }
                // dist+= 0.5;
            }
            Location newLoc = lastSafe.getLocation();
            newLoc.setPitch(start.getPitch());
            newLoc.setYaw(start.getYaw());
            player.teleport(newLoc);
            world.playEffect(newLoc, Effect.ENDER_SIGNAL, 0);
            world.playSound(newLoc, Sound.ENDERMAN_TELEPORT, 1.0f, 0.3f);
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
        }
    }

    @Override
    public void projectileHit(Player player, Projectile p) {
        long cooldown;
        RPGValue value = RPGValue.get(player, item, "teleport.cooldown");
        if (value == null) {
            cooldown = System.currentTimeMillis() / 50;
            value = new RPGValue(player, item, "teleport.cooldown", cooldown);
        } else {
            cooldown = value.asLong();
        }
        if (cooldown <= System.currentTimeMillis() / 50) {
            value.set(System.currentTimeMillis() / 50 + cooldownTime);
            World world = player.getWorld();
            Location start = player.getLocation();
            Location newLoc = p.getLocation();
            if (start.distanceSquared(newLoc) >= distance * distance) {
                player.sendMessage(ChatColor.AQUA + Locale.get("message.too.far", Locale.getPlayerLocale(player)));
                return;
            }
            newLoc.setPitch(start.getPitch());
            ;
            newLoc.setYaw(start.getYaw());
            player.teleport(newLoc);
            world.playEffect(newLoc, Effect.ENDER_SIGNAL, 0);
            world.playSound(newLoc, Sound.ENDERMAN_TELEPORT, 1.0f, 0.3f);
        } else {
            player.sendMessage(ChatColor.AQUA + String.format(Locale.get("message.cooldown", Locale.getPlayerLocale(player)), ((double) (cooldown - System.currentTimeMillis() / 50)) / 20d));
        }
    }

    @Override
    public void init(ConfigurationSection s) {
        cooldownTime = s.getLong("cooldown");
        distance = s.getInt("distance");
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("cooldown", cooldownTime);
        s.set("distance", distance);
    }

    @Override
    public String getName() {
        return "teleport";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + String.format(Locale.get("power.teleport", locale), distance, (double) cooldownTime / 20d);
    }
} public class PowerTicker extends BukkitRunnable {

    @Override
    public void run() {
        Player[] players = Bukkit.getOnlinePlayers();
        for (Player player : players) {
            ItemStack[] armour = player.getInventory().getArmorContents();
            for (ItemStack part : armour) {
                RPGItem item = ItemManager.toRPGItem(part);
                if (item == null)
                    continue;
                item.tick(player);
            }
            ItemStack part = player.getItemInHand();
            RPGItem item = ItemManager.toRPGItem(part);
            if (item == null)
                continue;
            item.tick(player);
        }
    }

} public class PowerUnbreakable extends Power implements PowerHit {

    @SuppressWarnings("deprecation")
    @Override
    public void hit(Player player, LivingEntity e, double damage) {
        player.getItemInHand().setDurability((short) 0);
        player.updateInventory();
    }

    @Override
    public void init(ConfigurationSection s) {

    }

    @Override
    public void save(ConfigurationSection s) {

    }

    @Override
    public String getName() {
        return "unbreakable";
    }

    @Override
    public String displayText(String locale) {
        return ChatColor.GREEN + Locale.get("power.unbreakable", locale);
    }
} public class PowerUnbreaking extends Power implements PowerHit {

    public int level = 1;
    private Random random = new Random();

    @SuppressWarnings("deprecation")
    @Override
    public void hit(Player player, LivingEntity e, double damage) {
        if (random.nextDouble() < ((double) level) / 100d) {
            System.out.println(player.getItemInHand().getDurability());
            player.getItemInHand().setDurability((short) (player.getItemInHand().getDurability() - 1));
            System.out.println(player.getItemInHand().getDurability());
            player.updateInventory();
        }
    }

    @Override
    public void init(ConfigurationSection s) {
        level = s.getInt("level", 1);
    }

    @Override
    public void save(ConfigurationSection s) {
        s.set("level", level);
    }

    @Override
    public String getName() {
        return "unbreaking";
    }

    @Override
    public String displayText(String locale) {
        return String.format(ChatColor.GREEN + Locale.get("power.unbreaking", locale), level);
    }
} public class WorldGuard {

    private static WorldGuardPlugin plugin;
    private static boolean hasSupport = false;
    public static boolean useWorldGuard = true;

    public static void init(think.rpgitems.Plugin plugin2) {
        Plugin plugin = plugin2.getServer().getPluginManager().getPlugin("WorldGuard");
        useWorldGuard = plugin2.getConfig().getBoolean("support.worldguard", false);
        if (plugin == null || !(plugin instanceof WorldGuardPlugin)) {
            return;
        }
        hasSupport = true;
        WorldGuard.plugin = (WorldGuardPlugin) plugin;
        think.rpgitems.Plugin.logger.info("[RPG Items] World Guard found");
    }

    public static boolean isEnabled() {
        return hasSupport;
    }

    public static boolean canBuild(Player player, Location location) {
        if (!hasSupport || !useWorldGuard)
            return true;
        return plugin.canBuild(player, location);
    }

    public static boolean canPvP(Location location) {
        if (!hasSupport || !useWorldGuard)
            return true;
        return plugin.getRegionManager(location.getWorld()).getApplicableRegions(location).allows(DefaultFlag.PVP);
    }
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.logging.Logger;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import think.rpgitems.commands.Commands;
import think.rpgitems.config.ConfigUpdater;
import think.rpgitems.data.Font;
import think.rpgitems.data.Locale;
import think.rpgitems.item.ItemManager;
import think.rpgitems.power.Power;
import think.rpgitems.power.PowerArrow;
import think.rpgitems.power.PowerCommand;
import think.rpgitems.power.PowerConsume;
import think.rpgitems.power.PowerFireball;
import think.rpgitems.power.PowerFlame;
import think.rpgitems.power.PowerFood;
import think.rpgitems.power.PowerIce;
import think.rpgitems.power.PowerKnockup;
import think.rpgitems.power.PowerLifeSteal;
import think.rpgitems.power.PowerLightning;
import think.rpgitems.power.PowerPotionHit;
import think.rpgitems.power.PowerPotionSelf;
import think.rpgitems.power.PowerPotionTick;
import think.rpgitems.power.PowerRainbow;
import think.rpgitems.power.PowerRumble;
import think.rpgitems.power.PowerRush;
import think.rpgitems.power.PowerSkyHook;
import think.rpgitems.power.PowerTNTCannon;
import think.rpgitems.power.PowerTeleport;
import think.rpgitems.power.PowerTicker;
import think.rpgitems.power.PowerUnbreakable;
import think.rpgitems.power.PowerUnbreaking;
import think.rpgitems.support.WorldGuard;
/*
 *  This file is part of RPG Items.
 *
 *  RPG Items is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  RPG Items is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with RPG Items.  If not, see <http://www.gnu.org/licenses/>.
 */
package think.rpgitems;




@SuppressWarnings("deprecation")
public class Plugin extends JavaPlugin {

    public static Logger logger = Logger.getLogger("RPGItems");
	
    public static Plugin plugin;

    @Override
    public void onLoad() {
        plugin = this;
        reloadConfig();
        Font.load();