public class SparkTrailAPI {

    private LocationAPI locationAPI;
    private MobAPI mobAPI;
    private PlayerAPI playerAPI;

    public SparkTrailAPI() {
        this.locationAPI = new LocationAPI();
        this.mobAPI = new MobAPI();
        this.playerAPI = new PlayerAPI();
    }

    public LocationAPI locationAPI() {
        return this.locationAPI;
    }

    public MobAPI mobAPI() {
        return this.mobAPI;
    }

    public PlayerAPI playerAPI() {
        return this.playerAPI;
    }

    public HashSet<EffectHolder> getAllActiveEffects() {
        return EffectManager.getInstance().getEffectHolders();
    }
} public class MenuChatListener implements Listener {

    @EventHandler
    public void onChat(AsyncPlayerChatEvent event) {
        Player player = event.getPlayer();
        String msg = event.getMessage();

        if (ParticleDemo.ACTIVE.containsKey(player.getName())) {
            if (msg.equalsIgnoreCase("NAME")) {
                Lang.sendTo(player, Lang.DEMO_CURRENT_PARTICLE.toString().replace("%effect%", StringUtil.capitalise(ParticleDemo.ACTIVE.get(player.getName()).getCurrentParticle().toString())));
                event.setCancelled(true);
            } else if (msg.equalsIgnoreCase("STOP")) {
                ParticleDemo pd = ParticleDemo.ACTIVE.get(player.getName());
                pd.cancel();
                Lang.sendTo(player, Lang.DEMO_STOP.toString());
                event.setCancelled(true);

            }
        }
    }
} public class CommandComplete implements TabCompleter {

    @Override
    public List<String> onTabComplete(CommandSender sender, Command cmd, String label, String[] args) {
        List<String> list = new ArrayList<String>();
        String cmdString = SparkTrailPlugin.getInstance().cmdString;
        if (cmd.getName().equalsIgnoreCase(cmdString)) {
            if (args.length > 0) {
                if (args[0].equalsIgnoreCase("sound")) {
                    for (Sound s : Sound.values()) {
                        if (s.toString().toLowerCase().startsWith(args[args.length - 1])) {
                            list.add(s.toString().toLowerCase());
                        }
                    }
                }
            }
        }
        return list;
    }
} public class TrailCommand implements CommandExecutor {

    public String label;
    ChatColor c1 = SparkTrailPlugin.getInstance().primaryColour;
    ChatColor c2 = SparkTrailPlugin.getInstance().secondaryColour;
    private Paginator help;

    public TrailCommand(String name) {
        this.label = name;
        this.help = this.generateHelp();
    }

    private Paginator generateHelp() {
        ArrayList<String> list = new ArrayList<String>();
        for (HelpEntry he : HelpEntry.values()) {
            list.add(he.getLine());
        }
        return new Paginator(list, 5);
    }

    public boolean onCommand(CommandSender sender, Command cmd, String cmdLabel, String[] args) {

        if (args.length == 0) {
            if (Permission.TRAIL.hasPerm(sender, true, false)) {
                Player p = (Player) sender;
                if (!ConfigOptions.instance.getConfig().getBoolean("enableMenu", true)) {
                    Lang.sendTo(sender, Lang.MENU_DISABLED.toString());
                    return true;
                }
                ParticleMenu pm = new ParticleMenu(p, p.getName());
                if (pm.fail) {
                    Lang.sendTo(sender, Lang.MENU_ERROR.toString());
                    return true;
                }
                pm.open(true);
                return true;
            } else return true;
        } else if (args.length == 1 && args[0].equalsIgnoreCase("location")) {
            if (Permission.LOC_TRAIL.hasPerm(sender, true, false)) {
                Player p = (Player) sender;
                InteractListener.INTERACTION.put(p.getName(), new InteractDetails(InteractDetails.InteractType.BLOCK, InteractDetails.ModifyType.ADD));
                Lang.sendTo(sender, Lang.INTERACT_BLOCK.toString());
                return true;
            } else return true;
        } else if (args.length == 1 && args[0].equalsIgnoreCase("mob")) {
            if (Permission.MOB_TRAIL.hasPerm(sender, true, false)) {
                Player p = (Player) sender;
                InteractListener.INTERACTION.put(p.getName(), new InteractDetails(InteractDetails.InteractType.MOB, InteractDetails.ModifyType.ADD));
                Lang.sendTo(sender, Lang.INTERACT_MOB.toString());
                return true;
            } else return true;
        } else if (args.length == 1 || (args.length >= 2 && (args[0].equalsIgnoreCase("blockbreak") || args[0].equalsIgnoreCase("itemspray") || args[0].equalsIgnoreCase("firework")))) {
            if (args[0].equalsIgnoreCase("reload")) {
                if (Permission.RELOAD.hasPerm(sender, true, true)) {
                    SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.MAIN).reloadConfig();
                    SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.LANG).reloadConfig();
                    Lang.sendTo(sender, Lang.CONFIGS_RELOADED.toString());
                    return true;
                } else return true;
            }
            if (args[0].equalsIgnoreCase("help")) {
                if (Permission.TRAIL.hasPerm(sender, true, true)) {
                    sender.sendMessage(c2 + "------------ SparkTrail Help 1/" + help.getIndex() + " ------------");
                    sender.sendMessage(c2 + "Parameters: <> = Required      [] = Optional");
                    for (String s : help.getPage(1)) {
                        sender.sendMessage(s);
                    }
                    return true;
                } else return true;
            } else if (args[0].equalsIgnoreCase("random")) {
                if (!(sender instanceof Player)) {
                    Lang.sendTo(sender, Lang.IN_GAME_ONLY.toString());
                    return true;
                }
                Player p = (Player) sender;

                EffectHolder eh = EffectManager.getInstance().getEffect(p.getName());
                if (eh == null) {
                    eh = EffectCreator.createPlayerHolder(p.getName());
                }

                ArrayList<ParticleType> list = new ArrayList<ParticleType>();
                for (ParticleType pt : ParticleType.values()) {
                    if (!pt.requiresDataMenu()) {
                        if (Permission.hasEffectPerm(p, false, pt, null) && !eh.hasEffect(pt)) {
                            list.add(pt);
                        }
                    }
                }

                if (list.isEmpty()) {
                    Lang.sendTo(p, Lang.RANDOM_SELECT_FAILED.toString());
                    return true;
                }
                ParticleType pt = list.get(new Random().nextInt(list.size()));
                if (Permission.hasEffectPerm(p, true, pt, null)) {
                    if (eh.addEffect(pt, true)) {
                        Lang.sendTo(p, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                    }
                    return true;
                } else {
                    EffectManager.getInstance().clear(eh);
                    return true;
                }
            } else if (args[0].equalsIgnoreCase("demo")) {
                if (Permission.DEMO.hasPerm(sender, true, false)) {
                    Player p = (Player) sender;
                    if (ParticleDemo.ACTIVE.containsKey(p.getName())) {
                        ParticleDemo.ACTIVE.get(p.getName()).cancel();
                        Lang.sendTo(sender, Lang.DEMO_STOP.toString());
                        return true;
                    }
                    Lang.sendTo(sender, Lang.DEMO_BEGIN.toString());
                    new ParticleDemo((Player) sender);
                    return true;
                } else return true;
            } else if (args[0].equalsIgnoreCase("info")) {
                if (Permission.INFO.hasPerm(sender, true, false)) {
                    EffectHolder eh = EffectManager.getInstance().getEffect(((Player) sender).getName());
                    if (eh == null || eh.getEffects().isEmpty()) {
                        Lang.sendTo(sender, Lang.NO_ACTIVE_EFFECTS.toString());
                        return true;
                    }
                    sender.sendMessage(c2 + "------------ Trail Effects ------------");
                    for (Effect e : eh.getEffects()) {
                        if (e.getParticleType().requiresDataMenu()) {
                            sender.sendMessage(c1 + StringUtil.capitalise(e.getParticleType().toString()) + ": " + c2 + e.getParticleData());
                        } else {
                            sender.sendMessage(c1 + StringUtil.capitalise(e.getParticleType().toString()));
                        }
                    }
                    return true;
                } else return true;
            } else if (args[0].equalsIgnoreCase("start")) {
                if (Permission.START.hasPerm(sender, true, false)) {
                    EffectHolder current = EffectManager.getInstance().getEffect(sender.getName());
                    EffectHolder eh = EffectManager.getInstance().createFromFile(sender.getName());
                    if (eh == null || eh.getEffects().isEmpty()) {
                        Lang.sendTo(sender, Lang.NO_EFFECTS_TO_LOAD.toString());
                        return true;
                    }
                    if (current != null) {
                        EffectManager.getInstance().clearFromMemory(current);
                    }
                    Lang.sendTo(sender, Lang.EFFECTS_LOADED.toString());
                    return true;
                }
            } else if (args[0].equalsIgnoreCase("stop")) {
                if (Permission.STOP.hasPerm(sender, true, false)) {
                    EffectHolder eh = EffectManager.getInstance().getEffect(sender.getName());
                    if (eh == null) {
                        Lang.sendTo(sender, Lang.NO_ACTIVE_EFFECTS.toString());
                        return true;
                    }
                    EffectManager.getInstance().remove(eh);
                    Lang.sendTo(sender, Lang.EFFECTS_STOPPED.toString());
                    return true;
                } else return true;
            } else if (args[0].equalsIgnoreCase("clear")) {
                if (Permission.CLEAR.hasPerm(sender, true, false)) {
                    EffectHolder eh = EffectManager.getInstance().getEffect(sender.getName());
                    if (eh == null) {
                        Lang.sendTo(sender, Lang.NO_ACTIVE_EFFECTS.toString());
                        return true;
                    }
                    EffectManager.getInstance().clear(eh);
                    Lang.sendTo(sender, Lang.EFFECTS_CLEARED.toString());
                    return true;
                } else return true;
            } else {
                if (EnumUtil.isEnumType(ParticleType.class, args[0].toUpperCase())) {
                    ParticleType pt = ParticleType.valueOf(args[0].toUpperCase());
                    if (!(sender instanceof Player)) {
                        Lang.sendTo(sender, Lang.IN_GAME_ONLY.toString());
                        return true;
                    }
                    Player p = (Player) sender;
                    if (pt.requiresDataMenu()) {
                        if (pt == ParticleType.BLOCKBREAK || pt == ParticleType.ITEMSPRAY) {
                            if (Permission.hasEffectPerm(p, true, pt, null)) {
                                if (args.length == 1) {
                                    Lang.sendTo(p, Lang.INVALID_EFFECT_ARGS.toString().replace("%effect%", pt == ParticleType.BLOCKBREAK ? "Block Break" : "ItemSpray").replace("%extra_info%", "Structure: " + ChatColor.YELLOW + "<IdValue> <BlockMeta>"));
                                    return true;
                                }

                                BlockData bd = DataFactory.findBlockData(StringUtil.combineSplit(1, args, " "));
                                ParticleDetails pd = new ParticleDetails(pt);
                                pd.blockId = bd.id;
                                pd.blockMeta = bd.data;
                                EffectHolder eh = EffectManager.getInstance().getEffect(p.getName());
                                if (eh == null) {
                                    eh = EffectCreator.createPlayerHolder(p.getName());
                                }
                                if (eh.hasEffect(pd)) {
                                    eh.removeEffect(pd);
                                    Lang.sendTo(p, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
                                } else {
                                    if (eh.addEffect(pd, true)) {
                                        Lang.sendTo(p, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                                    }
                                }
                            }
                            return true;
                        } else if (pt == ParticleType.FIREWORK) {
                            if (Permission.hasEffectPerm(p, true, pt, null)) {
                                if (args.length == 1) {
                                    Lang.sendTo(p, Lang.INVALID_EFFECT_ARGS.toString().replace("%effect%", "Firework").replace("%extra_info%", "Separate each parameter with a space."));
                                    return true;
                                }

                                FireworkEffect fe = DataFactory.generateFireworkEffectFrom(StringUtil.combineSplit(1, args, " "));
                                ParticleDetails pd = new ParticleDetails(pt);
                                pd.fireworkEffect = fe;
                                EffectHolder eh = EffectManager.getInstance().getEffect(p.getName());
                                if (eh == null) {
                                    eh = EffectCreator.createPlayerHolder(p.getName());
                                }
                                if (eh.hasEffect(pd)) {
                                    eh.removeEffect(pd);
                                    Lang.sendTo(p, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
                                } else {
                                    if (eh.addEffect(pd, true)) {
                                        Lang.sendTo(p, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                                    }
                                }
                            }
                            return true;
                        } else if (pt == ParticleType.CRITICAL) {
                            Lang.sendTo(sender, Lang.CRITICAL_HELP.toString());
                            return true;
                        } else if (pt == ParticleType.POTION) {
                            Lang.sendTo(sender, Lang.POTION_HELP.toString());
                            return true;
                        } else if (pt == ParticleType.SMOKE) {
                            Lang.sendTo(sender, Lang.SMOKE_HELP.toString());
                            return true;
                        } else if (pt == ParticleType.SWIRL) {
                            Lang.sendTo(sender, Lang.SWIRL_HELP.toString());
                            return true;
                        }
                    } else if (Permission.hasEffectPerm(p, true, pt, null)) {
                        EffectHolder eh = EffectManager.getInstance().getEffect(p.getName());
                        if (eh == null) {
                            eh = EffectCreator.createPlayerHolder(p.getName());
                        }
                        if (eh.hasEffect(pt)) {
                            eh.removeEffect(pt);
                            Lang.sendTo(p, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
                        } else {
                            if (eh.addEffect(pt, true)) {
                                Lang.sendTo(p, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                            }
                        }
                        return true;
                    } else return true;
                }
            }
        } else if (args.length == 2) {
            if (args[0].equals("help")) {
                if (Permission.TRAIL.hasPerm(sender, true, true)) {
                    if (StringUtil.isInt(args[1])) {
                        String[] str = help.getPage(Integer.parseInt(args[1]));
                        if (str == null) {
                            Lang.sendTo(sender, Lang.HELP_INDEX_TOO_BIG.toString().replace("%index%", args[1]));
                            return true;
                        }
                        sender.sendMessage(c2 + "------------ SparkTrail Help " + args[1] + "/" + help.getIndex() + " ------------");
                        sender.sendMessage(c2 + "Parameters: <> = Required      [] = Optional");
                        for (String s : str) {
                            sender.sendMessage(s);
                        }
                    }
                    return true;
                } else return true;
            } else if (args[0].equalsIgnoreCase("timeout")) {
                if (Permission.TIMEOUT.hasPerm(sender, true, false)) {
                    if (!StringUtil.isInt(args[1])) {
                        Lang.sendTo(sender, Lang.INT_ONLY_WITH_ARGS.toString().replace("%string%", args[1]).replace("%argNum%", "1"));
                        return true;
                    }
                    Player p = (Player) sender;
                    EffectHolder eh = EffectManager.getInstance().getEffect(p.getName());
                    if (eh == null || eh.getEffects().isEmpty()) {
                        Lang.sendTo(sender, Lang.NO_ACTIVE_EFFECTS.toString());
                        return true;
                    }
                    eh.setTimeout(Integer.parseInt(args[1]));
                    Lang.sendTo(sender, Lang.TIMEOUT_SET.toString().replace("%timeout%", args[1]));
                }
            } else if (args[0].equalsIgnoreCase("sound")) {
                if (Permission.SOUND.hasPerm(sender, true, false)) {
                    EffectHolder eh = EffectManager.getInstance().getEffect(sender.getName());
                    if (eh == null || eh.getEffects().isEmpty()) {
                        eh = EffectCreator.createPlayerHolder(sender.getName());
                    }
                    if (!EnumUtil.isEnumType(org.bukkit.Sound.class, args[1].toUpperCase())) {
                        Lang.sendTo(sender, Lang.NO_SOUND_IN_STRING.toString().replace("%string%", args[1]));
                        return true;
                    }

                    org.bukkit.Sound enumSound = org.bukkit.Sound.valueOf(args[1].toUpperCase());
                    ParticleDetails pd = new ParticleDetails(ParticleType.SOUND);
                    pd.sound = enumSound;
                    if (eh.addEffect(pd, true)) {
                        Lang.sendTo(sender, Lang.EFFECT_ADDED.toString().replace("%effect%", "Sound"));
                    }
                    return true;
                } else return true;
            } else if (args[0].equalsIgnoreCase("player")) {
                if (args[1].equalsIgnoreCase("list")) {
                    if (Permission.PLAYER_LIST.hasPerm(sender, true, true)) {
                        ArrayList<EffectHolder> list = new ArrayList<EffectHolder>();
                        for (EffectHolder eh : EffectManager.getInstance().getEffectHolders()) {
                            if (eh.getEffectType().equals(EffectHolder.EffectType.PLAYER)) {
                                list.add(eh);
                            }
                        }
                        if (list.isEmpty()) {
                            Lang.sendTo(sender, Lang.PLAYER_LIST_NO_ACTIVE_EFFECTS.toString());
                            return true;
                        }
                        sender.sendMessage(SparkTrailPlugin.getInstance().secondaryColour + "------------ " + SparkTrailPlugin.getInstance().primaryColour + "Player" + " Trail Effects ------------");
                        for (EffectHolder eh : list) {
                            sender.sendMessage(SparkTrailPlugin.getInstance().primaryColour + eh.getDetails().playerName);
                            sender.sendMessage(SparkTrailPlugin.getInstance().primaryColour + " ---> " + SparkTrailPlugin.getInstance().secondaryColour + DataFactory.serialiseEffects(eh.getEffects(), true, true, false));
                        }
                        return true;
                    } else return true;
                }
                if (Permission.PLAYER_TRAIL.hasPerm(sender, true, false)) {
                    Player target = Bukkit.getPlayer(args[1]);
                    if (target == null) {
                        Lang.sendTo(sender, Lang.NULL_PLAYER.toString().replace("%player%", args[1]));
                        return true;
                    }
                    if (!ConfigOptions.instance.getConfig().getBoolean("enableMenu", true)) {
                        Lang.sendTo(sender, Lang.MENU_DISABLED.toString());
                        return true;
                    }
                    ParticleMenu pm = new ParticleMenu(((Player) sender), target.getName());
                    if (pm.fail) {
                        Lang.sendTo(sender, Lang.MENU_ERROR.toString());
                        return true;
                    }
                    pm.open(false);
                    Lang.sendTo(sender, Lang.ADMIN_OPEN_MENU.toString().replace("%player%", target.getName()));
                    return true;
                } else return true;
            } else if (args[0].equalsIgnoreCase("location")) {
                if (args[1].equalsIgnoreCase("list")) {
                    if (Permission.LOC_LIST.hasPerm(sender, true, true)) {
                        ArrayList<EffectHolder> list = new ArrayList<EffectHolder>();
                        for (EffectHolder eh : EffectManager.getInstance().getEffectHolders()) {
                            if (eh.getEffectType().equals(EffectHolder.EffectType.LOCATION)) {
                                list.add(eh);
                            }
                        }
                        if (list.isEmpty()) {
                            Lang.sendTo(sender, Lang.LOC_LIST_NO_ACTIVE_EFFECTS.toString());
                            return true;
                        }
                        sender.sendMessage(SparkTrailPlugin.getInstance().secondaryColour + "------------ " + SparkTrailPlugin.getInstance().primaryColour + "Location" + " Trail Effects ------------");
                        for (EffectHolder eh : list) {
                            sender.sendMessage(SparkTrailPlugin.getInstance().primaryColour + DataFactory.serialiseLocation(eh.getLocation()));
                            sender.sendMessage(SparkTrailPlugin.getInstance().primaryColour + " ---> " + SparkTrailPlugin.getInstance().secondaryColour + DataFactory.serialiseEffects(eh.getEffects(), true, true, false));
                        }
                        return true;
                    } else return true;
                } else if (args[1].equalsIgnoreCase("stop")) {
                    if (Permission.LOC_STOP.hasPerm(sender, true, false)) {
                        InteractListener.INTERACTION.put(sender.getName(), new InteractDetails(InteractDetails.InteractType.BLOCK, InteractDetails.ModifyType.STOP));
                        Lang.sendTo(sender, Lang.INTERACT_BLOCK.toString());
                        return true;
                    } else return true;
                } else if (args[1].equalsIgnoreCase("start")) {
                    if (Permission.LOC_START.hasPerm(sender, true, false)) {
                        InteractListener.INTERACTION.put(sender.getName(), new InteractDetails(InteractDetails.InteractType.BLOCK, InteractDetails.ModifyType.START));
                        Lang.sendTo(sender, Lang.INTERACT_BLOCK.toString());
                        return true;
                    } else return true;
                } else if (args[1].equalsIgnoreCase("clear")) {
                    if (Permission.LOC_CLEAR.hasPerm(sender, true, false)) {
                        InteractListener.INTERACTION.put(sender.getName(), new InteractDetails(InteractDetails.InteractType.BLOCK, InteractDetails.ModifyType.CLEAR));
                        Lang.sendTo(sender, Lang.INTERACT_BLOCK.toString());
                        return true;
                    } else return true;
                }
            } else if (args[0].equalsIgnoreCase("mob")) {
                if (args[1].equalsIgnoreCase("list")) {
                    if (Permission.MOB_LIST.hasPerm(sender, true, true)) {
                        ArrayList<EffectHolder> list = new ArrayList<EffectHolder>();
                        for (EffectHolder eh : EffectManager.getInstance().getEffectHolders()) {
                            if (eh.getEffectType().equals(EffectHolder.EffectType.MOB)) {
                                list.add(eh);
                            }
                        }
                        if (list.isEmpty()) {
                            Lang.sendTo(sender, Lang.MOB_LIST_NO_ACTIVE_EFFECTS.toString());
                            return true;
                        }
                        sender.sendMessage(SparkTrailPlugin.getInstance().secondaryColour + "------------ " + SparkTrailPlugin.getInstance().primaryColour + "Mob" + " Trail Effects ------------");
                        for (EffectHolder eh : list) {
                            Entity e = DataFactory.getMob(eh.getDetails().mobUuid);
                            if (e != null) {
                                sender.sendMessage(SparkTrailPlugin.getInstance().primaryColour + StringUtil.capitalise(e.getType().toString()));
                                sender.sendMessage(SparkTrailPlugin.getInstance().primaryColour + " ---> " + SparkTrailPlugin.getInstance().secondaryColour + DataFactory.serialiseEffects(eh.getEffects(), true, true, false));
                            }
                        }
                        return true;
                    } else return true;
                } else if (args[1].equalsIgnoreCase("stop")) {
                    if (Permission.MOB_STOP.hasPerm(sender, true, false)) {
                        InteractListener.INTERACTION.put(sender.getName(), new InteractDetails(InteractDetails.InteractType.MOB, InteractDetails.ModifyType.STOP));
                        Lang.sendTo(sender, Lang.INTERACT_MOB.toString());
                        return true;
                    } else return true;
                } else if (args[1].equalsIgnoreCase("start")) {
                    if (Permission.MOB_START.hasPerm(sender, true, false)) {
                        InteractListener.INTERACTION.put(sender.getName(), new InteractDetails(InteractDetails.InteractType.MOB, InteractDetails.ModifyType.START));
                        Lang.sendTo(sender, Lang.INTERACT_MOB.toString());
                        return true;
                    } else return true;
                } else if (args[1].equalsIgnoreCase("clear")) {
                    if (Permission.MOB_CLEAR.hasPerm(sender, true, false)) {
                        InteractListener.INTERACTION.put(sender.getName(), new InteractDetails(InteractDetails.InteractType.MOB, InteractDetails.ModifyType.CLEAR));
                        Lang.sendTo(sender, Lang.INTERACT_MOB.toString());
                        return true;
                    } else return true;
                }
            } else {
                if (EnumUtil.isEnumType(ParticleType.class, args[0].toUpperCase())) {
                    if (!(sender instanceof Player)) {
                        Lang.sendTo(sender, Lang.IN_GAME_ONLY.toString());
                        return true;
                    }
                    ParticleType pt = ParticleType.valueOf(args[0].toUpperCase());
                    Player p = (Player) sender;
                    ParticleDetails pd = null;
                    if (pt == ParticleType.CRITICAL) {
                        if (EnumUtil.isEnumType(Critical.CriticalType.class, args[1].toUpperCase())) {
                            Critical.CriticalType type = Critical.CriticalType.valueOf(args[1].toUpperCase());
                            if (Permission.hasEffectPerm(p, true, pt, type.toString().toLowerCase(), null)) {
                                pd = new ParticleDetails(pt);
                                pd.criticalType = type;
                            } else return true;
                        } else {
                            Lang.sendTo(sender, Lang.CRITICAL_HELP.toString());
                            return true;
                        }
                    } else if (pt == ParticleType.POTION) {
                        if (EnumUtil.isEnumType(Potion.PotionType.class, args[1].toUpperCase())) {
                            Potion.PotionType type = Potion.PotionType.valueOf(args[1].toUpperCase());
                            if (Permission.hasEffectPerm(p, true, pt, type.toString().toLowerCase(), null)) {
                                pd = new ParticleDetails(pt);
                                pd.potionType = type;
                            } else return true;
                        } else {
                            Lang.sendTo(sender, Lang.POTION_HELP.toString());
                            return true;
                        }
                    } else if (pt == ParticleType.SMOKE) {
                        if (EnumUtil.isEnumType(Smoke.SmokeType.class, args[1].toUpperCase())) {
                            Smoke.SmokeType type = Smoke.SmokeType.valueOf(args[1].toUpperCase());
                            if (Permission.hasEffectPerm(p, true, pt, type.toString().toLowerCase(), null)) {
                                pd = new ParticleDetails(pt);
                                pd.smokeType = type;
                            } else return true;
                        } else {
                            Lang.sendTo(sender, Lang.SMOKE_HELP.toString());
                            return true;
                        }
                    } else if (pt == ParticleType.SWIRL) {
                        if (EnumUtil.isEnumType(Swirl.SwirlType.class, args[1].toUpperCase())) {
                            Swirl.SwirlType type = Swirl.SwirlType.valueOf(args[1].toUpperCase());
                            if (Permission.hasEffectPerm(p, true, pt, type.toString().toLowerCase(), null)) {
                                pd = new ParticleDetails(pt);
                                pd.swirlType = type;
                                pd.setPlayer(p.getName(), p.getUniqueId());
                            } else return true;
                        } else {
                            Lang.sendTo(sender, Lang.SWIRL_HELP.toString());
                            return true;
                        }
                    }
                    if (pd != null) {
                        EffectHolder eh = EffectManager.getInstance().getEffect(p.getName());
                        if (eh == null) {
                            eh = EffectCreator.createPlayerHolder(p.getName());
                        }
                        if (eh.hasEffect(pd)) {
                            eh.removeEffect(pd);
                            Lang.sendTo(p, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
                        } else {
                            if (eh.addEffect(pd, true)) {
                                Lang.sendTo(p, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                            }
                        }
                        return true;
                    }
                }
            }
        } else if (args.length == 3) {
            if (args[0].equalsIgnoreCase("player")) {
                if (args[2].equalsIgnoreCase("info")) {
                    if (Permission.PLAYER_INFO.hasPerm(sender, true, true)) {
                        Player target = Bukkit.getPlayer(args[1]);
                        if (target == null) {
                            Lang.sendTo(sender, Lang.NULL_PLAYER.toString().replace("%player%", args[1]));
                            return true;
                        }
                        EffectHolder eh = EffectManager.getInstance().getEffect(target.getName());
                        if (eh == null || eh.getEffects().isEmpty()) {
                            Lang.sendTo(sender, Lang.PLAYER_NO_ACTIVE_EFFECTS.toString().replace("%player%", args[1]));
                            return true;
                        }
                        sender.sendMessage(c2 + "------------ Trail Effects ------------");
                        for (Effect e : eh.getEffects()) {
                            if (e.getParticleType().requiresDataMenu()) {
                                sender.sendMessage(c1 + StringUtil.capitalise(e.getParticleType().toString()) + ": " + c2 + e.getParticleData());
                            } else {
                                sender.sendMessage(c1 + StringUtil.capitalise(e.getParticleType().toString()));
                            }
                        }
                        return true;
                    } else return true;
                } else if (args[2].equalsIgnoreCase("start")) {
                    if (Permission.PLAYER_START.hasPerm(sender, true, true)) {
                        Player target = Bukkit.getPlayer(args[1]);
                        if (target == null) {
                            Lang.sendTo(sender, Lang.NULL_PLAYER.toString().replace("%player%", args[1]));
                            return true;
                        }
                        EffectHolder eh = EffectManager.getInstance().createFromFile(target.getName());
                        if (eh == null || eh.getEffects().isEmpty()) {
                            Lang.sendTo(sender, Lang.PLAYER_NO_EFFECTS_TO_LOAD.toString().replace("%player%", target.getName()));
                            EffectManager.getInstance().clear(eh);
                            return true;
                        }
                        Lang.sendTo(sender, Lang.PLAYER_EFFECTS_LOADED.toString().replace("%player%", target.getName()));
                        return true;
                    } else return true;
                } else if (args[2].equalsIgnoreCase("stop")) {
                    if (Permission.PLAYER_START.hasPerm(sender, true, true)) {
                        Player target = Bukkit.getPlayer(args[1]);
                        if (target == null) {
                            Lang.sendTo(sender, Lang.NULL_PLAYER.toString().replace("%player%", args[1]));
                            return true;
                        }
                        EffectHolder eh = EffectManager.getInstance().getEffect(target.getName());
                        if (eh == null) {
                            Lang.sendTo(sender, Lang.PLAYER_NO_ACTIVE_EFFECTS.toString().replace("%player%", args[1]));
                            return true;
                        }
                        EffectManager.getInstance().remove(eh);
                        Lang.sendTo(sender, Lang.PLAYER_EFFECTS_STOPPED.toString().replace("%player%", target.getName()));
                        return true;
                    } else return true;
                } else if (args[2].equalsIgnoreCase("clear")) {
                    if (Permission.PLAYER_START.hasPerm(sender, true, true)) {
                        Player target = Bukkit.getPlayer(args[1]);
                        if (target == null) {
                            Lang.sendTo(sender, Lang.NULL_PLAYER.toString().replace("%player%", args[1]));
                            return true;
                        }
                        EffectHolder eh = EffectManager.getInstance().getEffect(target.getName());
                        if (eh == null) {
                            Lang.sendTo(sender, Lang.PLAYER_NO_ACTIVE_EFFECTS.toString().replace("%player%", args[1]));
                            return true;
                        }
                        EffectManager.getInstance().clear(eh);
                        Lang.sendTo(sender, Lang.PLAYER_EFFECTS_CLEARED.toString().replace("%player%", target.getName()));
                        return true;
                    } else return true;
                }
            } else if (args[0].equalsIgnoreCase("location")) {
                if (args[1].equalsIgnoreCase("stop")) {
                    if (args[2].equalsIgnoreCase("all")) {
                        if (Permission.LOC_STOP_ALL.hasPerm(sender, true, true)) {
                            for (EffectHolder eh : EffectManager.getInstance().getEffectHolders()) {
                                if (eh.getEffectType().equals(EffectHolder.EffectType.LOCATION)) {
                                    EffectManager.getInstance().remove(eh);
                                }
                            }
                            Lang.sendTo(sender, Lang.LOC_STOP_ALL.toString());
                        } else return true;
                    }
                }
            }
        } else if (args.length == 4 && args[0].equalsIgnoreCase("location")) {
            if (Permission.LOC_STOP.hasPerm(sender, true, false)) {
                Location l = DataFactory.getLocation(sender, args, 1);
                if (l == null) {
                    return true;
                }

                ParticleMenu pm = new ParticleMenu((Player) sender, l);
                pm.open(true);
                Lang.sendTo(sender, Lang.OPEN_MENU.toString());
                return true;
            } else return true;
        } else if (args.length == 5 && args[0].equals("location") && args[1].equalsIgnoreCase("stop")) {
            if (Permission.LOC_STOP.hasPerm(sender, true, true)) {
                Location l = DataFactory.getLocation(sender, args, 2);
                if (l == null) {
                    return true;
                }

                EffectHolder eh = EffectManager.getInstance().getEffect(l);
                if (eh == null) {
                    Lang.sendTo(sender, Lang.LOC_NO_ACTIVE_EFFECTS.toString());
                    return true;
                }

                EffectManager.getInstance().remove(eh);
                Lang.sendTo(sender, Lang.LOC_EFFECTS_STOPPED.toString());
                return true;
            } else return true;
        } else if (args.length == 5 && args[0].equals("location") && args[1].equalsIgnoreCase("start")) {
            if (Permission.LOC_START.hasPerm(sender, true, true)) {
                Location l = DataFactory.getLocation(sender, args, 2);
                if (l == null) {
                    return true;
                }
                EffectHolder eh = EffectManager.getInstance().createFromFile(l);
                if (eh == null || eh.getEffects().isEmpty()) {
                    Lang.sendTo(sender, Lang.LOC_NO_EFFECTS_TO_LOAD.toString());
                    EffectManager.getInstance().clear(eh);
                    return true;
                }
                Lang.sendTo(sender, Lang.LOC_EFFECTS_LOADED.toString());
                return true;
            } else return true;
        } else if (args.length == 5 && args[0].equals("location") && args[1].equalsIgnoreCase("clear")) {
            if (Permission.LOC_CLEAR.hasPerm(sender, true, true)) {
                Location l = DataFactory.getLocation(sender, args, 2);
                if (l == null) {
                    return true;
                }
                EffectHolder eh = EffectManager.getInstance().getEffect(l);
                EffectManager.getInstance().clear(eh);
                Lang.sendTo(sender, Lang.LOC_EFFECTS_CLEARED.toString());
                return true;
            } else return true;
        } else if (args.length == 5 || (args.length >= 6 && (args[4].equalsIgnoreCase("blockbreak") || args[4].equalsIgnoreCase("itemspray") || args[4].equalsIgnoreCase("firework")))) {
            if (args[0].equalsIgnoreCase("location")) {
                Location l = DataFactory.getLocation(sender, args, 1);
                if (l == null) {
                    return true;
                }

                if (EnumUtil.isEnumType(ParticleType.class, args[4].toUpperCase())) {
                    ParticleType pt = ParticleType.valueOf(args[4].toUpperCase());
                    if (pt == ParticleType.BLOCKBREAK || pt == ParticleType.ITEMSPRAY) {
                        if (!(sender instanceof Player) || Permission.hasEffectPerm(((Player) sender), true, pt, "location")) {
                            if (args.length == 5) {
                                Lang.sendTo(sender, Lang.INVALID_EFFECT_ARGS.toString().replace("%effect%", pt == ParticleType.BLOCKBREAK ? "Block Break" : "ItemSpray").replace("%extra_info%", "Separate each parameter with a space."));
                                return true;
                            }

                            BlockData bd = DataFactory.findBlockData(StringUtil.combineSplit(5, args, " "));
                            ParticleDetails pd = new ParticleDetails(pt);
                            pd.blockId = bd.id;
                            pd.blockMeta = bd.data;
                            add(l, pt, sender, pd);
                        }
                        return true;
                    } else if (pt == ParticleType.FIREWORK) {
                        if (!(sender instanceof Player) || Permission.hasEffectPerm(((Player) sender), true, pt, "location")) {
                            if (args.length == 5) {
                                Lang.sendTo(sender, Lang.INVALID_EFFECT_ARGS.toString().replace("%effect%", "Firework").replace("%extra_info%", "Separate each parameter with a space."));
                                return true;
                            }
                            FireworkEffect fe = DataFactory.generateFireworkEffectFrom(StringUtil.combineSplit(5, args, " "));
                            ParticleDetails pd = new ParticleDetails(pt);
                            pd.fireworkEffect = fe;
                            add(l, pt, sender, pd);
                        }
                        return true;
                    } else if (pt == ParticleType.CRITICAL) {
                        Lang.sendTo(sender, Lang.CRITICAL_HELP.toString());
                        return true;
                    } else if (pt == ParticleType.POTION) {
                        Lang.sendTo(sender, Lang.POTION_HELP.toString());
                        return true;
                    } else if (pt == ParticleType.SMOKE) {
                        Lang.sendTo(sender, Lang.SMOKE_HELP.toString());
                        return true;
                    } else if (pt == ParticleType.SWIRL) {
                        Lang.sendTo(sender, Lang.SWIRL_NOT_ALLOWED.toString());
                        return true;
                    } else if (!(sender instanceof Player) || Permission.hasEffectPerm(((Player) sender), true, pt, "location")) {
                        EffectHolder eh = EffectManager.getInstance().getEffect(l);
                        if (eh == null) {
                            eh = EffectCreator.createLocHolder(l);
                        }
                        if (eh.hasEffect(pt)) {
                            eh.removeEffect(pt);
                            Lang.sendTo(sender, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
                        } else {
                            if (eh.addEffect(pt, true)) {
                                Lang.sendTo(sender, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                            }
                        }
                        return true;
                    } else return true;
                }
            }
        } else if (args.length == 6) {
            if (args[0].equalsIgnoreCase("location")) {
                Location l = DataFactory.getLocation(sender, args, 1);
                if (l == null) {
                    return true;
                }

                ParticleDetails pd = null;

                if (EnumUtil.isEnumType(ParticleType.class, args[4].toUpperCase())) {
                    ParticleType pt = ParticleType.valueOf(args[4].toUpperCase());
                    if (pt == ParticleType.CRITICAL) {
                        if (EnumUtil.isEnumType(Critical.CriticalType.class, args[5].toUpperCase())) {
                            Critical.CriticalType type = Critical.CriticalType.valueOf(args[5].toUpperCase());
                            if (!(sender instanceof Player) || Permission.hasEffectPerm(((Player) sender), true, pt, type.toString().toLowerCase(), "location")) {
                                pd = new ParticleDetails(pt);
                                pd.criticalType = type;
                            } else return true;
                        } else {
                            Lang.sendTo(sender, Lang.CRITICAL_HELP.toString());
                            return true;
                        }
                    } else if (pt == ParticleType.POTION) {
                        if (EnumUtil.isEnumType(Potion.PotionType.class, args[5].toUpperCase())) {
                            Potion.PotionType type = Potion.PotionType.valueOf(args[5].toUpperCase());
                            if (!(sender instanceof Player) || Permission.hasEffectPerm(((Player) sender), true, pt, type.toString().toLowerCase(), "location")) {
                                pd = new ParticleDetails(pt);
                                pd.potionType = type;
                            } else return true;
                        } else {
                            Lang.sendTo(sender, Lang.POTION_HELP.toString());
                            return true;
                        }
                    } else if (pt == ParticleType.SMOKE) {
                        if (EnumUtil.isEnumType(Smoke.SmokeType.class, args[5].toUpperCase())) {
                            Smoke.SmokeType type = Smoke.SmokeType.valueOf(args[5].toUpperCase());
                            if (!(sender instanceof Player) || Permission.hasEffectPerm(((Player) sender), true, pt, type.toString().toLowerCase(), "location")) {
                                pd = new ParticleDetails(pt);
                                pd.smokeType = type;
                            } else return true;
                        } else {
                            Lang.sendTo(sender, Lang.SMOKE_HELP.toString());
                            return true;
                        }
                    } else if (pt == ParticleType.SWIRL) {
                        Lang.sendTo(sender, Lang.SWIRL_NOT_ALLOWED.toString());
                        return true;
                    }
                    if (pd != null) {
                        EffectHolder eh = EffectManager.getInstance().getEffect(l);
                        if (eh == null) {
                            eh = EffectCreator.createLocHolder(l);
                        }
                        if (eh.hasEffect(pd)) {
                            eh.removeEffect(pd);
                            Lang.sendTo(sender, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
                        } else {
                            if (eh.addEffect(pd, true)) {
                                Lang.sendTo(sender, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                            }
                        }
                        return true;
                    }
                }
            }
        }

        Lang.sendTo(sender, Lang.COMMAND_ERROR.toString()
                .replace("%cmd%", "/" + cmd.getLabel() + " " + (args.length == 0 ? "" : StringUtil.combineSplit(0, args, " "))));
        return true;
    }

    public void add(Location l, ParticleType pt, CommandSender sender, ParticleDetails pd) {
        EffectHolder eh = EffectManager.getInstance().getEffect(l);
        if (eh == null) {
            eh = EffectCreator.createLocHolder(l);
        }
        if (eh.hasEffect(pd)) {
            eh.removeEffect(pd);
            Lang.sendTo(sender, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
        } else {
            if (eh.addEffect(pd, true)) {
                Lang.sendTo(sender, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
            }
        }
    }
} public class ConfigOptions extends Options {

    public static ConfigOptions instance;

    public ConfigOptions(YAMLConfig config) {
        super(config);
        instance = this;
        this.setDefaults();
        this.setMaxTick();
    }

    public int maxTick = 0;

    public void setMaxTick() {
        for (String key : config.getConfigurationSection("effects").getKeys(false)) {
            int i = config.getInt("effects." + key + ".frequency", 20);
            if (this.maxTick < i) {
                this.maxTick = i;
            }
        }

        for (int i = maxTick; i >= maxTick; i++) {
            if (i % 20 == 0) {
                maxTick = i;
                break;
            }
        }
    }

    public boolean useSql() {
        return this.config.getBoolean("sql.use", false);
    }

    public boolean sqlOverride() {
        if (useSql()) {
            return this.config.getBoolean("sql.overrideFile");
        }
        return false;
    }

    @Override
    public void setDefaults() {
        set("command", "trail");

        set("primaryChatColour", "a");
        set("secondaryChatColour", "e");

        set("autoUpdate", false);
        set("checkForUpdates", true);

        set("sql.overrideFile", true, "If true, data saved to the MySQL Database will override data saved to a file");
        set("sql.use", false);
        set("sql.host", "localhost");
        set("sql.port", 3306);
        set("sql.database", "SparkTrail");
        set("sql.username", "none");
        set("sql.password", "none");

        set("autosave", true, "If true, SparkTrail will autosave all pet data to prevent data", "loss in the event of a server crash.");
        set("autosaveTimer", 180, "AutoSave interval (in seconds)");
        set("enableMenu", true);

        // Just set this to 1 so we can have a description
        set("maxEffectAmount", 1, "Maximum amount of effects a player, location or mob is allowed to have. -1 allows an", "unlimited number.");

        set("maxEffectAmount.player", 1);
        set("maxEffectAmount.location", 1);
        set("maxEffectAmount.mob", 1);

        for (ParticleType pt : ParticleType.values()) {
            String name = pt.toString().toLowerCase();
            set("effects." + name + ".enable", true);
            set("effects." + name + ".frequency", 20);
            set("effects." + name + ".playType", "normal");
        }

        this.config.saveConfig();
    }
} public class AutoSave {

    public AutoSave(int timer) {
        new BukkitRunnable() {
            public void run() {
                SparkTrailPlugin plugin = SparkTrailPlugin.getInstance();
                for (EffectHolder e : plugin.EH.getEffectHolders()) {
                    plugin.EH.save(e);
                    plugin.SQLH.save(e);
                }
            }
        }.runTaskTimer(SparkTrailPlugin.getInstance(), (20 * timer) / 2, 20 * timer);
    }
} public class EffectManager {

    private static EffectManager instance;
    private HashSet<EffectHolder> effects = new HashSet<EffectHolder>();

    public EffectManager() {
        instance = this;
    }

    public static EffectManager getInstance() {
        return instance;
    }

    public void addHolder(EffectHolder effectHolder) {
        this.effects.add(effectHolder);
    }

    public void clearFromMemory(EffectHolder holder) {
        if (holder != null) {
            holder.stop();
            this.effects.remove(holder);
        }
    }

    public void clearEffects() {
        Iterator<EffectHolder> i = effects.iterator();
        while (i.hasNext()) {
            EffectHolder e = i.next();
            save(e);
            SQLEffectManager.instance.save(e);
            e.stop();
            i.remove();
        }
    }

    public HashSet<EffectHolder> getEffectHolders() {
        return this.effects;
    }

    public void save(EffectHolder e) {
        if (e.isPersistent()) {
            clearFromFile(e);
            if (e.getEffects().isEmpty()) {
                return;
            }
            YAMLConfig config = SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.DATA);
            String path = "effects.";
            if (e.getEffectType() == EffectHolder.EffectType.PLAYER) {
                path = path + "player." + e.getDetails().playerName + ".";
            } else if (e.getEffectType() == EffectHolder.EffectType.LOCATION) {
                path = path + "location." + DataFactory.serialiseLocation(e.getLocation()) + ".";
            } else if (e.getEffectType() == EffectHolder.EffectType.MOB) {
                path = path + "mob." + e.getDetails().mobUuid + ".";
            }

            for (Effect effect : e.getEffects()) {
                if (effect == null || effect.getParticleType() == null) {
                    continue;
                }
                if (effect.getParticleType().requiresDataMenu()) {
                    ParticleType pt = effect.getParticleType();
                    String value = null;
                    if (pt == ParticleType.BLOCKBREAK) {
                        value = ((BlockBreak) effect).idValue + "," + ((BlockBreak) effect).metaValue;
                    } else if (pt == ParticleType.ITEMSPRAY) {
                        value = ((ItemSpray) effect).idValue + "," + ((ItemSpray) effect).metaValue;
                    } else if (pt == ParticleType.CRITICAL) {
                        value = ((Critical) effect).criticalType.toString();
                    } else if (pt == ParticleType.FIREWORK) {
                        value = DataFactory.serialiseFireworkEffect(((Firework) effect).fireworkEffect, ",");
                    }
                /*else if (pt == ParticleType.NOTE) {
                    value = ((Note) effect).noteType.toString();
				}*/
                    else if (pt == ParticleType.POTION) {
                        value = ((Potion) effect).potionType.toString();
                    } else if (pt == ParticleType.SMOKE) {
                        value = ((Smoke) effect).smokeType.toString();
                    } else if (pt == ParticleType.SWIRL) {
                        value = ((Swirl) effect).swirlType.toString();
                    }
                    if (value != null) {
                        config.set(path + effect.getParticleType().toString().toLowerCase(), value);
                    }
                } else {
                    config.set(path + effect.getParticleType().toString().toLowerCase(), "none");
                }
            }

            config.saveConfig();
        }
    }

    public void clearFromFile(EffectHolder e) {
        if (e != null) {
            YAMLConfig config = SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.DATA);
            String path = "effects.";
            if (e.getEffectType() == EffectHolder.EffectType.PLAYER) {
                path = path + "player." + e.getDetails().playerName;
            } else if (e.getEffectType() == EffectHolder.EffectType.LOCATION) {
                path = path + "location." + DataFactory.serialiseLocation(e.getLocation());
            } else if (e.getEffectType() == EffectHolder.EffectType.MOB) {
                path = path + "mob." + e.getDetails().mobUuid;
            }
            config.set(path, null);
            config.saveConfig();
        }
    }

    public void clear(EffectHolder e) {
        clearFromFile(e);
        this.clearFromMemory(e);
    }

    public EffectHolder createFromFile(Location location) {
        YAMLConfig config = SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.DATA);
        String path = "effects.location." + DataFactory.serialiseLocation(location);
        if (config.get(path) == null) {
            return null;
        }
        EffectHolder eh = EffectCreator.createLocHolder(location);
        return createFromFile(path, eh);
    }

    public EffectHolder createFromFile(UUID uuid) {
        YAMLConfig config = SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.DATA);
        String path = "effects.mob." + uuid;
        if (config.get(path) == null) {
            return null;
        }
        EffectHolder eh = EffectCreator.createMobHolder(uuid);
        return createFromFile(path, eh);
    }

    public EffectHolder createFromFile(String playerName) {
        //Player p = Bukkit.getPlayerExact(playerName);
        /*if (p == null) {
            return null;
		}*/
        String path = "effects.player." + playerName;
        YAMLConfig config = SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.DATA);
        if (config.get(path) == null) {
            return null;
        }
        EffectHolder eh = EffectCreator.createPlayerHolder(playerName);
        return createFromFile(path, eh);
    }

    private EffectHolder createFromFile(String path, EffectHolder eh) {
        YAMLConfig config = SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.DATA);
        if (config.get(path) == null) {
            return null;
        }
        ConfigurationSection cs = config.getConfigurationSection(path);
        for (String key : cs.getKeys(false)) {
            if (EnumUtil.isEnumType(ParticleType.class, key.toUpperCase())) {
                ParticleType pt = ParticleType.valueOf(key.toUpperCase());
                if (pt.requiresDataMenu()) {
                    ParticleDetails pd = new ParticleDetails(pt);
                    String value = config.getString(path + "." + key);
                    if (pt == ParticleType.BLOCKBREAK || pt == ParticleType.ITEMSPRAY) {
                        try {
                            pd.blockId = Integer.parseInt(value.split(",")[0]);
                            pd.blockMeta = Integer.parseInt(value.split(",")[1]);
                        } catch (Exception e) {
                            Logger.log(Logger.LogLevel.WARNING, "Error creating Integer for Effect (" + key + "). Either SparkTrail didn't save properly or the data file was edited.", true);
                            return null;
                        }
                    } else if (pt == ParticleType.CRITICAL) {
                        try {
                            pd.criticalType = Critical.CriticalType.valueOf(value);
                        } catch (Exception e) {
                            Logger.log(Logger.LogLevel.WARNING, "Error creating Effect (" + key + "). Either SparkTrail didn't save properly or the data file was edited.", true);
                            return null;
                        }
                    } else if (pt == ParticleType.FIREWORK) {
                        pd.fireworkEffect = DataFactory.deserialiseFireworkEffect(value, ",");
                    }
                    /*else if (pt == ParticleType.NOTE) {
                        try {
							pd.noteType = Note.NoteType.valueOf(value);
						} catch (Exception e) {
							Logger.log(Logger.LogLevel.WARNING, "Error creating Effect (" + key + "). Either SparkTrail didn't save properly or the data file was edited.", true);
							return null;
						}
					}*/
                    else if (pt == ParticleType.POTION) {
                        try {
                            pd.potionType = Potion.PotionType.valueOf(value);
                        } catch (Exception e) {
                            Logger.log(Logger.LogLevel.WARNING, "Error creating Effect (" + key + "). Either SparkTrail didn't save properly or the data file was edited.", true);
                            return null;
                        }
                    } else if (pt == ParticleType.SMOKE) {
                        try {
                            pd.smokeType = Smoke.SmokeType.valueOf(value);
                        } catch (Exception e) {
                            Logger.log(Logger.LogLevel.WARNING, "Error creating Effect (" + key + "). Either SparkTrail didn't save properly or the data file was edited.", true);
                            return null;
                        }
                    } else if (pt == ParticleType.SWIRL) {
                        try {
                            UUID uuid = null;
                            if (eh.getEffectType().equals(EffectHolder.EffectType.MOB)) {
                                uuid = UUID.fromString(key);
                            } else if (eh.getEffectType().equals(EffectHolder.EffectType.PLAYER)) {
                                Player p = Bukkit.getPlayerExact(key);
                                if (p == null) {
                                    continue;
                                }
                                uuid = p.getUniqueId();
                            }
                            if (eh.getEffectType().equals(EffectHolder.EffectType.LOCATION) || uuid == null) {
                                continue;
                            }
                            pd.swirlType = Swirl.SwirlType.valueOf(value);
                            pd.setMob(uuid);
                        } catch (Exception e) {
                            Logger.log(Logger.LogLevel.WARNING, "Error creating Effect (" + key + "). Either SparkTrail didn't save properly or the data file was edited.", true);
                            return null;
                        }
                    }
                    eh.addEffect(pd, false);
                } else {
                    eh.addEffect(pt, false);
                }
            } else {
                Logger.log(Logger.LogLevel.WARNING, "Error creating Effect (" + key + "). Either SparkTrail didn't save properly or the data file was edited.", true);
                return null;
            }
        }
        return eh;
    }

    public EffectHolder getEffect(Location l) {
        return this.getEffect(l.getWorld(), (int) l.getX(), (int) l.getY(), (int) l.getZ());
    }

    public EffectHolder getEffect(World world, int x, int y, int z) {
        for (EffectHolder e : effects) {
            if (e.world.equals(world) && e.locX == x && e.locY == y && e.locZ == z) {
                return e;
            }
        }
        return null;
    }

    public EffectHolder getEffect(String playerName) {
        for (EffectHolder e : effects) {
            if (e.getDetails().playerName != null && e.getDetails().playerName.equals(playerName)) {
                return e;
            }
        }
        return null;
    }

    public EffectHolder getEffect(UUID mobUuid) {
        for (EffectHolder e : effects) {
            if (e.getDetails().mobUuid != null && e.getDetails().mobUuid == mobUuid) {
                return e;
            }
        }
        return null;
    }

    public void remove(EffectHolder e) {
        save(e);
        SQLEffectManager.instance.save(e);
        this.clearFromMemory(e);
    }
} public class EntityListener implements Listener {

    @EventHandler
    public void onEntityDeath(EntityDeathEvent event) {
        EffectHolder holder = EffectManager.getInstance().getEffect(event.getEntity().getUniqueId());
        if (holder != null) {
            EffectManager.getInstance().remove(holder);
            //ConsoleLogger.log(Logger.LogLevel.WARNING, "Entity with active Trail effect has despawned: {Type: " + event.getEntity().getType() + ", ID: " + event.getEntity().getUniqueId() + "}");
        }
    }

    @EventHandler
    public void onChunkUnload(ChunkUnloadEvent event) {
        ArrayList<Entity> toRemove = new ArrayList<Entity>();
        for (Entity e : event.getChunk().getEntities()) {
            EffectHolder holder = EffectManager.getInstance().getEffect(e.getUniqueId());
            if (holder != null) {
                EffectManager.getInstance().clear(holder);
                continue;
            }

            if (e instanceof Item && ItemSpray.UUID_LIST.contains(e.getUniqueId())) {
                toRemove.add(e);
            }
        }
        if (!toRemove.isEmpty()) {
            Iterator<Entity> i = toRemove.iterator();
            while (i.hasNext()) {
                i.next().remove();
            }
        }
    }
} public class InteractListener implements Listener {

    public static HashMap<String, InteractDetails> INTERACTION = new HashMap<String, InteractDetails>();

    @EventHandler
    public void onInteractEntity(PlayerInteractEntityEvent event) {
        Player p = event.getPlayer();
        if (INTERACTION.containsKey(p.getName()) && INTERACTION.get(p.getName()).interactType.equals(InteractDetails.InteractType.MOB)) {
            if (event.getRightClicked() instanceof Player) {
                InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.RETRY_MOB_INTERACT.toString()));
                INTERACTION.remove(p.getName());
                return;
            }
            Entity e = event.getRightClicked();
            if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.ADD)) {
                ParticleMenu pm = new ParticleMenu(p, e.getUniqueId());
                pm.open(true);
                INTERACTION.remove(p.getName());
            } else if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.STOP)) {
                EffectHolder eh = EffectManager.getInstance().getEffect(e.getUniqueId());
                if (eh == null) {
                    InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.MOB_NO_ACTIVE_EFFECTS_RETRY_INTERACT.toString()));
                } else {
                    EffectManager.getInstance().remove(eh);
                    Lang.sendTo(p, Lang.MOB_EFFECTS_STOPPED.toString());
                }
                INTERACTION.remove(p.getName());
            } else if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.START)) {
                EffectHolder eh = EffectManager.getInstance().getEffect(e.getUniqueId());
                if (eh == null) {
                    InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.MOB_NO_EFFECTS_RETRY_INTERACT.toString()));
                } else {
                    Lang.sendTo(p, Lang.MOB_EFFECTS_STARTED.toString());
                }
                INTERACTION.remove(p.getName());
            } else if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.CLEAR)) {
                EffectHolder eh = EffectManager.getInstance().createFromFile(e.getUniqueId());
                if (eh == null) {
                    InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.MOB_NO_ACTIVE_EFFECTS_RETRY_INTERACT.toString()));
                } else {
                    EffectManager.getInstance().clear(eh);
                    Lang.sendTo(p, Lang.MOB_EFFECTS_CLEARED.toString());
                }
                INTERACTION.remove(p.getName());
            }
            event.setCancelled(true);
        }
    }

    @EventHandler
    public void onInteract(PlayerInteractEvent event) {
        Player p = event.getPlayer();
        if (INTERACTION.containsKey(p.getName())) {
            if (INTERACTION.get(p.getName()).interactType.equals(InteractDetails.InteractType.BLOCK)) {
                if (!(event.getAction().equals(Action.LEFT_CLICK_BLOCK) || event.getAction().equals(Action.RIGHT_CLICK_BLOCK))) {
                    InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.RETRY_BLOCK_INTERACT.toString()));
                    INTERACTION.remove(p.getName());
                    return;
                }
                Location l = event.getClickedBlock().getLocation();
                if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.ADD)) {
                    ParticleMenu pm = new ParticleMenu(p, l);
                    pm.open(true);
                    INTERACTION.remove(p.getName());
                } else if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.STOP)) {
                    EffectHolder eh = EffectManager.getInstance().getEffect(l);
                    if (eh == null) {
                        InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.LOC_NO_ACTIVE_EFFECTS_RETRY_BLOCK_INTERACT.toString()));
                    } else {
                        EffectManager.getInstance().remove(eh);
                        Lang.sendTo(p, Lang.LOC_EFFECTS_STOPPED.toString());
                    }
                    INTERACTION.remove(p.getName());
                } else if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.START)) {
                    EffectHolder eh = EffectManager.getInstance().createFromFile(l);
                    if (eh == null) {
                        InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.LOC_NO_EFFECTS_RETRY_BLOCK_INTERACT.toString()));
                    } else {
                        Lang.sendTo(p, Lang.LOC_EFFECTS_STARTED.toString());
                    }
                    INTERACTION.remove(p.getName());
                } else if (INTERACTION.get(p.getName()).modifyType.equals(InteractDetails.ModifyType.CLEAR)) {
                    EffectHolder eh = EffectManager.getInstance().getEffect(l);
                    if (eh == null) {
                        InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.LOC_NO_ACTIVE_EFFECTS_RETRY_BLOCK_INTERACT.toString()));
                    } else {
                        EffectManager.getInstance().clear(eh);
                        Lang.sendTo(p, Lang.LOC_EFFECTS_CLEARED.toString());
                    }
                    INTERACTION.remove(p.getName());
                }
                event.setCancelled(true);
            } else if (INTERACTION.get(p.getName()).equals(InteractDetails.InteractType.MOB)) {
                InputFactory.promptInt(p, new YesNoFunction(INTERACTION.get(p.getName()), Lang.RETRY_MOB_INTERACT.toString()));
                INTERACTION.remove(p.getName());
                return;
            }
            event.setCancelled(true);
        }
    }
} public class PlayerListener implements Listener {

    @EventHandler
    public void onQuit(PlayerQuitEvent event) {
        Player p = event.getPlayer();
        EffectHolder eh = EffectManager.getInstance().getEffect(p.getName());
        if (eh != null) {
            EffectManager.getInstance().remove(eh);
        }
    }

    @EventHandler
    public void onLogin(PlayerLoginEvent event) {
        final Player p = event.getPlayer();
        if (event.getResult().equals(PlayerLoginEvent.Result.ALLOWED)) {
            new BukkitRunnable() {
                @Override
                public void run() {
                    if (p != null) {
                        EffectHolder eh = EffectManager.getInstance().createFromFile(p.getName());
                        if (eh != null && !eh.getEffects().isEmpty()) {
                            Lang.sendTo(p, Lang.EFFECTS_LOADED.toString());
                        }
                    }
                }
            }.runTaskLater(SparkTrailPlugin.getInstance(), 20L);
        }
    }

    @EventHandler
    public void onInventoryPickup(InventoryPickupItemEvent event) {
        if (event.getInventory().getType() == InventoryType.HOPPER) {
            if (ItemSpray.UUID_LIST.contains(event.getItem().getUniqueId())) {
                event.setCancelled(true);
            }
        }
    }
} public class MenuListener implements Listener {

    @EventHandler
    public void onInvClose(InventoryCloseEvent event) {
        if (event.getView().getTitle().startsWith("Trail GUI")) {
            try {
                ParticleMenu menu = ParticleMenu.openMenus.get(event.getPlayer().getName());
                if (menu == null) {
                    return;
                }
                ParticleMenu.openMenus.remove(event.getPlayer().getName());
            } catch (Exception e) {
                Logger.log(Logger.LogLevel.SEVERE, "Encountered exception in Trail Menu", e, true);
            }
        }
    }

    // TODO: This menu isn't very well done :\
    // It could really be done a LOOOOOT better than this
    @EventHandler
    public void onInvClick(InventoryClickEvent event) {
        Player player = (Player) event.getWhoClicked();
        Inventory inv = event.getInventory();
        String title = event.getView().getTitle();
        int slot = event.getRawSlot();

        if (title.startsWith("Trail GUI")) {
            if (slot < 0 || slot > inv.getSize()) {
                return;
            }

            if (inv.getItem(slot) == null) {
                return;
            }

            try {
                ParticleMenu menu = ParticleMenu.openMenus.get(player.getName());
                if (menu == null) {
                    return;
                }
                //String s = title.split(" - ")[1];
                for (MenuIcon mi : menu.endItems) {
                    if (inv.getItem(slot).equals(mi.getStack())) {
                        mi.onClick();
                        event.setCancelled(true);
                        player.closeInventory();
                        ParticleMenu.openMenus.remove(player.getName());
                        return;
                    }
                }

                for (ParticleType pt : ParticleType.values()) {
                    if (inv.getItem(slot).equals(pt.getMenuItem()) || inv.getItem(slot).equals(pt.getMenuItem(false)) || inv.getItem(slot).equals(pt.getMenuItem(true))) {
                        if (!pt.requiresDataMenu()) {
                            if (inv.getItem(slot).equals(pt.getMenuItem(false))) {
                                if (Permission.hasEffectPerm(player, true, pt, (menu.playerName != null && menu.playerName.equals(player.getName())) ? null : menu.effectType.toString().toLowerCase())) {
                                    if (removeEffect(player, menu.effectType, pt, menu)) {
                                        Lang.sendTo(player, Lang.EFFECT_REMOVED.toString().replace("%effect%", pt.getName()));
                                        inv.setItem(slot, pt.getMenuItem(true));
                                    }
                                }
                            } else if (inv.getItem(slot).equals(pt.getMenuItem(true))) {
                                if (Permission.hasEffectPerm(player, true, pt, (menu.playerName != null && menu.playerName.equals(player.getName())) ? null : menu.effectType.toString().toLowerCase())) {
                                    if (addEffect(player, menu.effectType, pt, menu)) {
                                        Lang.sendTo(player, Lang.EFFECT_ADDED.toString().replace("%effect%", pt.getName()));
                                        inv.setItem(slot, pt.getMenuItem(false));
                                    }
                                }
                            }
                        } else {
                            if (pt == ParticleType.BLOCKBREAK || pt == ParticleType.ITEMSPRAY || pt == ParticleType.FIREWORK) {
                                if (Permission.hasEffectPerm(player, true, pt, (menu.playerName != null && menu.playerName.equals(player.getName())) ? null : menu.effectType.toString().toLowerCase())) {
                                    if (inv.getItem(slot).equals(pt.getMenuItem(false))) {
                                        removeEffect(player, menu.effectType, pt, menu);
                                        inv.setItem(slot, pt.getMenuItem(true));
                                        event.setCancelled(true);
                                        player.closeInventory();
                                        return;
                                    }
                                    WaitingData wd = new WaitingData(menu.effectType, pt);
                                    wd.location = menu.location;
                                    wd.mobUuid = menu.mobUuid;
                                    wd.playerName = menu.playerName;
                                    InputFactory.prompt(player, pt, wd);
                                /*MenuChatListener.AWAITING_DATA.put(player.getName(), wd);
                                if (pt == ParticleType.BLOCKBREAK || pt == ParticleType.ITEMSPRAY) {
                                    Lang.sendTo(player, Lang.ENTER_BLOCK_OR_ITEM.toString().replace("%effect%", pt == ParticleType.BLOCKBREAK ? "Block Break" : "ItemSpray"));
                                } else if (pt == ParticleType.FIREWORK) {
                                    Lang.sendTo(player, Lang.ENTER_FIREWORK.toString());
                                }*/
                                    event.setCancelled(true);
                                    player.closeInventory();
                                    ParticleMenu.openMenus.remove(player.getName());
                                    event.setCancelled(true);
                                    return;
                                }
                            } else {
                                event.setCancelled(true);
                                player.closeInventory();
                                ParticleMenu.openMenus.remove(player.getName());
                                DataMenu dm = null;
                                if (menu.effectType == EffectHolder.EffectType.PLAYER) {
                                    dm = new DataMenu(player, menu.playerName, pt);
                                } else if (menu.effectType == EffectHolder.EffectType.LOCATION) {
                                    dm = new DataMenu(player, menu.location, pt);
                                } else if (menu.effectType == EffectHolder.EffectType.MOB) {
                                    dm = new DataMenu(player, menu.mobUuid, pt);
                                }
                                if (dm != null) {
                                    if (dm.fail) {
                                        Lang.sendTo(player, Lang.MENU_ERROR.toString());
                                    } else {
                                        dm.open(false);
                                    }
                                }
                                DataMenu.openMenus.remove(player.getName());
                                return;
                            }
                        }
                    }
                }

                event.setCancelled(true);
                player.closeInventory();
                return;
            } catch (Exception e) {
                event.setCancelled(true);
                Logger.log(Logger.LogLevel.SEVERE, "Encountered exception in Trail Menu", e, true);
            }
        } else if (title.contains(" - Trail GUI - ")) {
            if (slot < 0 || slot > inv.getSize()) {
                return;
            }

            if (inv.getItem(slot) == null) {
                return;
            }
            try {
                if (slot <= 26) {
                    DataMenu menu = DataMenu.openMenus.get(player.getName());
                    if (menu == null) {
                        return;
                    }
                    String[] split = title.split(" - ");
                    String particle = split[0];
                    //String data = split[2];

                    if (inv.getItem(slot) != null && inv.getItem(slot).equals(DataMenu.BACK)) {
                        DataMenu.openMenus.remove(player.getName());

                        ParticleMenu pm = null;
                        if (menu.effectType == EffectHolder.EffectType.PLAYER) {
                            pm = new ParticleMenu(player, menu.playerName);
                        } else if (menu.effectType == EffectHolder.EffectType.LOCATION) {
                            pm = new ParticleMenu(player, menu.location);
                        } else if (menu.effectType == EffectHolder.EffectType.MOB) {
                            pm = new ParticleMenu(player, menu.mobUuid);
                        }
                        if (pm != null) {
                            if (pm.fail) {
                                Lang.sendTo(player, Lang.MENU_ERROR.toString());
                            } else {
                                pm.open(false);
                            }
                        }
                        event.setCancelled(true);
                        player.closeInventory();
                        return;
                    }

                    if (EnumUtil.isEnumType(ParticleType.class, particle.toString().toUpperCase())) {
                        ParticleType pt = ParticleType.valueOf(particle.toUpperCase());
                        if (pt != null) {
                            for (ParticleDataItem pdi : ParticleDataItem.values()) {
                                boolean b = inv.getItem(slot).getItemMeta().getDisplayName().contains("OFF");
                                if (inv.getItem(slot).equals(pdi.getMenuItem(false)) || inv.getItem(slot).equals(pdi.getMenuItem(true))) {
                                    if (pt == ParticleType.CRITICAL) {
                                        if (EnumUtil.isEnumType(Critical.CriticalType.class, pdi.toString().toUpperCase())) {
                                            ParticleDetails pd = new ParticleDetails(pt);
                                            Critical.CriticalType criticalType = Critical.CriticalType.valueOf(pdi.toString().toUpperCase());
                                            pd.criticalType = criticalType;
                                            if (Permission.hasEffectPerm(player, true, pt, criticalType.toString().toLowerCase(), (menu.playerName != null && menu.playerName.equals(player.getName())) ? null : menu.effectType.toString().toLowerCase())) {
                                                if (b) {
                                                    if (removeEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_REMOVED.toString().replace("%effect%", "Critical"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                } else {
                                                    if (addEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_ADDED.toString().replace("%effect%", "Critical"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                }
                                            }
                                        }
                                    }
                                /*else if (pt == ParticleType.NOTE) {
                                    if (EnumUtil.isEnumType(Note.NoteType.class, pdi.toString().toUpperCase())) {
										Note.NoteType noteType = Note.NoteType.valueOf(pdi.toString().toUpperCase());
										ParticleDetails pd = new ParticleDetails(pt);
										pd.noteType = noteType;
										if (b) {
											if (removeEffect(player, pd, menu.effectType, menu, data)) {
												inv.setItem(slot, pdi.getMenuItem(b));
											}
										}
										else {
											if (addEffect(player, pd, menu.effectType, menu, data)) {
												inv.setItem(slot, pdi.getMenuItem(b));
											}
										}
									}
								}*/
                                    else if (pt == ParticleType.POTION) {
                                        if (EnumUtil.isEnumType(Potion.PotionType.class, pdi.toString().toUpperCase())) {
                                            Potion.PotionType potionType = Potion.PotionType.valueOf(pdi.toString().toUpperCase());
                                            ParticleDetails pd = new ParticleDetails(pt);
                                            pd.potionType = potionType;
                                            if (Permission.hasEffectPerm(player, true, pt, potionType.toString().toLowerCase(), (menu.playerName != null && menu.playerName.equals(player.getName())) ? null : menu.effectType.toString().toLowerCase())) {
                                                if (b) {
                                                    if (removeEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_REMOVED.toString().replace("%effect%", "Potion"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                } else {
                                                    if (addEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_ADDED.toString().replace("%effect%", "Potion"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                }
                                            }
                                        }
                                    } else if (pt == ParticleType.SMOKE) {
                                        if (EnumUtil.isEnumType(Smoke.SmokeType.class, pdi.toString().toUpperCase())) {
                                            Smoke.SmokeType smokeType = Smoke.SmokeType.valueOf(pdi.toString().toUpperCase());
                                            ParticleDetails pd = new ParticleDetails(pt);
                                            pd.smokeType = smokeType;
                                            if (Permission.hasEffectPerm(player, true, pt, smokeType.toString().toLowerCase(), (menu.playerName != null && menu.playerName.equals(player.getName())) ? null : menu.effectType.toString().toLowerCase())) {
                                                if (b) {
                                                    if (removeEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_REMOVED.toString().replace("%effect%", "Smoke"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                } else {
                                                    if (addEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_ADDED.toString().replace("%effect%", "Smoke"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                }
                                            }
                                        }
                                    } else if (pt == ParticleType.SWIRL) {
                                        if (EnumUtil.isEnumType(Swirl.SwirlType.class, pdi.toString().toUpperCase())) {
                                            Swirl.SwirlType swirlType = Swirl.SwirlType.valueOf(pdi.toString().toUpperCase());
                                            ParticleDetails pd = new ParticleDetails(pt);
                                            pd.swirlType = swirlType;
                                            pd.setPlayer(player.getName(), player.getUniqueId());
                                            if (Permission.hasEffectPerm(player, true, pt, swirlType.toString().toLowerCase(), (menu.playerName != null && menu.playerName.equals(player.getName())) ? null : menu.effectType.toString().toLowerCase())) {
                                                if (b) {
                                                    if (removeEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_REMOVED.toString().replace("%effect%", "Swirl"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                } else {
                                                    if (addEffect(player, pd, menu.effectType, menu)) {
                                                        Lang.sendTo(player, Lang.EFFECT_ADDED.toString().replace("%effect%", "Swirl"));
                                                        inv.setItem(slot, pdi.getMenuItem(b));
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    event.setCancelled(true);
                    player.closeInventory();
                }
            } catch (Exception e) {
                event.setCancelled(true);
                player.closeInventory();
                Logger.log(Logger.LogLevel.SEVERE, "Encountered exception in Trail Menu", e, true);
            }
        }
    }

    private boolean addEffect(Player player, ParticleDetails pd, EffectHolder.EffectType effectType, Menu menu) {
        EffectHolder eh = getHolder(player, effectType, pd.getParticleType(), menu);

        if (eh == null) {
            Logger.log(Logger.LogLevel.SEVERE, "Effect creation failed while adding Particle Type (" + pd.getParticleType().toString() + ") [Reported from MenuListener].", true);
            return false;
        }

        return eh.addEffect(pd, true);
    }

    private boolean removeEffect(Player player, ParticleDetails pd, EffectHolder.EffectType effectType, Menu menu) {
        EffectHolder eh = getHolder(player, effectType, pd.getParticleType(), menu);

        if (eh == null) {
            Logger.log(Logger.LogLevel.SEVERE, "Effect creation failed while adding Particle Type (" + pd.getParticleType().toString() + ") [Reported from MenuListener].", true);
            return false;
        }

        eh.removeEffect(pd);

        return true;
    }

    private boolean addEffect(Player player, EffectHolder.EffectType effectType, ParticleType particleType, Menu menu) {
        EffectHolder eh = getHolder(player, effectType, particleType, menu);

        if (eh == null) {
            Logger.log(Logger.LogLevel.SEVERE, "Effect creation failed while adding Particle Type (" + particleType.toString() + ") [Reported from MenuListener].", true);
            return false;
        }

        HashSet<ParticleDetails> hashSet = new HashSet<ParticleDetails>();
        if (effectType == EffectHolder.EffectType.PLAYER) {
            ParticleDetails pd = new ParticleDetails(particleType);
            Player p = Bukkit.getPlayerExact(menu.playerName);
            if (p == null) {
                Logger.log(Logger.LogLevel.SEVERE, "Effect creation failed (" + menu.playerName + ") while adding Particle Type (" + particleType.toString() + ") [Reported from MenuListener].", true);
                return false;
            }
            pd.setPlayer(menu.playerName, p.getUniqueId());
            hashSet.add(pd);
        } else if (effectType == EffectHolder.EffectType.LOCATION) {
            ParticleDetails pd = new ParticleDetails(particleType);
            hashSet.add(pd);
        } else if (effectType == EffectHolder.EffectType.MOB) {
            ParticleDetails pd = new ParticleDetails(particleType);
            pd.setMob(menu.mobUuid);
            hashSet.add(pd);

        }

        return eh.addEffect(particleType, true);
    }

    private boolean removeEffect(Player player, EffectHolder.EffectType effectType, ParticleType particleType, Menu menu) {
        EffectHolder eh = getHolder(player, effectType, particleType, menu);
        if (eh == null) {
            Logger.log(Logger.LogLevel.SEVERE, "Effect modification failed while removing Particle Type (" + particleType.toString() + ") [Reported from MenuListener].", true);
            return false;
        }

        eh.removeEffect(particleType);

        return true;
    }

    private EffectHolder getHolder(Player player, EffectHolder.EffectType effectType, ParticleType particleType, Menu menu) {
        EffectHolder eh = null;
        if (effectType == EffectHolder.EffectType.LOCATION) {
            try {
                eh = EffectManager.getInstance().getEffect(menu.location);
            } catch (Exception e) {
                Logger.log(Logger.LogLevel.SEVERE, "Failed to create Location (" + DataFactory.serialiseLocation(menu.location) + ") whilst finding EffectHolder (" + particleType.toString() + ")", e, true);
                return null;
            }
        } else if (effectType == EffectHolder.EffectType.PLAYER) {
            eh = EffectManager.getInstance().getEffect(menu.playerName);
        } else if (effectType == EffectHolder.EffectType.MOB) {
            eh = EffectManager.getInstance().getEffect(menu.mobUuid);
        }

        if (eh == null) {
            if (effectType == EffectHolder.EffectType.PLAYER) {
                Player p = Bukkit.getPlayerExact(menu.playerName);
                if (p == null) {
                    Logger.log(Logger.LogLevel.SEVERE, "Failed to create Player Effect (" + menu.playerName + ") while finding Effect Holder (" + particleType.toString() + ") [Reported from MenuListener].", true);
                    return null;
                }
                eh = EffectCreator.createPlayerHolder(menu.playerName);
            } else if (effectType == EffectHolder.EffectType.LOCATION) {
                Location l;
                try {
                    l = menu.location;
                    /*String[] s = data.split(", ");
                    l = new Location(Bukkit.getWorld(s[0]), Integer.parseInt(s[1]), Integer.parseInt(s[2]), Integer.parseInt(s[3]));*/
                } catch (Exception e) {
                    l = null;
                }
                if (l == null) {
                    Logger.log(Logger.LogLevel.SEVERE, "Failed to create Location (" + DataFactory.serialiseLocation(menu.location) + ") whilst finding EffectHolder (" + particleType.toString() + ") [Reported from MenuListener].", true);
                    return null;
                }
                eh = EffectCreator.createLocHolder(l);
            } else if (effectType == EffectHolder.EffectType.MOB) {
                eh = EffectCreator.createMobHolder(menu.mobUuid);
            }
        }

        return eh;
    }
} public class SQLEffectManager {

    public static SQLEffectManager instance;

    public SQLEffectManager() {
        instance = this;
    }

    public void save(EffectHolder eh) {
        if (eh.isPersistent()) {
            if (ConfigOptions.instance.useSql()) {
                Connection con = null;
                PreparedStatement statement = null;

                if (SparkTrailPlugin.getInstance().dbPool != null) {
                    try {
                        con = SparkTrailPlugin.getInstance().dbPool.getConnection();
                        String data = DataFactory.serialiseEffects(eh.getEffects(), false, false, true);

                        if (eh.getEffectType().equals(EffectHolder.EffectType.PLAYER)) {
                            statement = con.prepareStatement("INSERT INTO PlayerEffects (?, Effects) VALUES (?, ?);");
                            statement.setString(1, "PlayerName");
                            statement.setString(2, eh.getDetails().playerName);
                        } else if (eh.getEffectType().equals(EffectHolder.EffectType.LOCATION)) {
                            statement = con.prepareStatement("INSERT INTO PlayerEffects (?, Effects) VALUES (?, ?);");
                            statement.setString(1, "Location");
                            statement.setString(2, DataFactory.serialiseLocation(eh.getLocation()));
                        } else if (eh.getEffectType().equals(EffectHolder.EffectType.MOB)) {
                            statement = con.prepareStatement("INSERT INTO MobEffects (?, Effects) VALUES (?, ?);");
                            statement.setString(1, "MobUUID");
                            statement.setString(2, eh.getDetails().mobUuid.toString());
                        }

                        if (statement != null) {
                            statement.setString(3, data);
                            statement.executeUpdate();
                        }

                    } catch (SQLException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            if (statement != null)
                                statement.close();
                            if (con != null)
                                con.close();
                        } catch (SQLException ignored) {
                        }
                    }
                }
            }
        }
    }

    public void clear(EffectHolder eh) {
        if (ConfigOptions.instance.useSql()) {
            Connection con = null;
            PreparedStatement statement = null;

            if (SparkTrailPlugin.getInstance().dbPool != null) {
                try {
                    con = SparkTrailPlugin.getInstance().dbPool.getConnection();

                    if (eh.getEffectType().equals(EffectHolder.EffectType.PLAYER)) {
                        statement = con.prepareStatement("DELETE FROM PlayerEffects WHERE PlayerName = ?;");
                        statement.setString(1, eh.getDetails().playerName);
                    } else if (eh.getEffectType().equals(EffectHolder.EffectType.LOCATION)) {
                        statement = con.prepareStatement("DELETE FROM LocationEffects WHERE Location = ?;");
                        statement.setString(1, DataFactory.serialiseLocation(eh.getLocation()));
                    } else if (eh.getEffectType().equals(EffectHolder.EffectType.MOB)) {
                        statement = con.prepareStatement("DELETE FROM MobEffects WHERE MobUUID = ?;");
                        statement.setString(1, eh.getDetails().mobUuid.toString());
                    }

                    if (statement != null) {
                        statement.executeUpdate();
                    }

                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (statement != null)
                            statement.close();
                        if (con != null)
                            con.close();
                    } catch (SQLException ignored) {
                    }
                }
            }
        }
    }

    public void update(EffectHolder eh) {
        if (ConfigOptions.instance.useSql()) {
            Connection con = null;
            PreparedStatement statement = null;

            if (SparkTrailPlugin.getInstance().dbPool != null) {
                try {
                    con = SparkTrailPlugin.getInstance().dbPool.getConnection();
                    String data = DataFactory.serialiseEffects(eh.getEffects(), false, false, true);

                    if (eh.getEffectType().equals(EffectHolder.EffectType.PLAYER)) {
                        statement = con.prepareStatement("UPDATE PlayerEffects SET Effects = ? WHERE ? = ?");
                        statement.setString(2, "PlayerName");
                        statement.setString(3, eh.getDetails().playerName);
                    } else if (eh.getEffectType().equals(EffectHolder.EffectType.LOCATION)) {
                        statement = con.prepareStatement("UPDATE LocationEffects SET Effects = ? WHERE ? = ?");
                        statement.setString(2, "Location");
                        statement.setString(3, DataFactory.serialiseLocation(eh.getLocation()));
                    } else if (eh.getEffectType().equals(EffectHolder.EffectType.MOB)) {
                        statement = con.prepareStatement("UPDATE MobEffects SET Effects = ? WHERE ? = ?");
                        statement.setString(2, "MobUUID");
                        statement.setString(3, eh.getDetails().mobUuid.toString());
                    }

                    if (statement != null) {
                        statement.setString(1, data);
                        statement.executeUpdate();
                    }

                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (statement != null)
                            statement.close();
                        if (con != null)
                            con.close();
                    } catch (SQLException ignored) {
                    }
                }
            }
        }
    }

    public EffectHolder create(String playerName) {
        if (ConfigOptions.instance.useSql()) {
            Connection con = null;
            PreparedStatement statement = null;

            if (SparkTrailPlugin.getInstance().dbPool != null) {
                try {
                    con = SparkTrailPlugin.getInstance().dbPool.getConnection();
                    statement = con.prepareStatement("SELECT * FROM PlayerEffects WHERE PlayerName = ?;");
                    statement.setString(1, playerName);
                    ResultSet rs = statement.executeQuery();
                    while (rs.next()) {
                        EffectManager.getInstance().clearFromMemory(EffectManager.getInstance().getEffect(playerName));
                        EffectHolder eh = EffectCreator.createPlayerHolder(playerName);
                        String effects = rs.getString("Effects");
                        DataFactory.addEffectsFrom(effects, eh);
                    }

                } catch (SQLException e) {
                    //Log the issue
                } finally {
                    try {
                        if (statement != null)
                            statement.close();
                        if (con != null)
                            con.close();
                    } catch (SQLException ignored) {
                    }
                }
            }
        }
        return null;
    }

    public EffectHolder create(Location location) {
        if (ConfigOptions.instance.useSql()) {
            Connection con = null;
            PreparedStatement statement = null;

            if (SparkTrailPlugin.getInstance().dbPool != null) {
                try {
                    con = SparkTrailPlugin.getInstance().dbPool.getConnection();
                    statement = con.prepareStatement("SELECT * FROM LocationEffects WHERE Location = ?;");
                    statement.setString(1, DataFactory.serialiseLocation(location));
                    ResultSet rs = statement.executeQuery();
                    while (rs.next()) {
                        EffectManager.getInstance().clearFromMemory(EffectManager.getInstance().getEffect(location));
                        EffectHolder eh = EffectCreator.createLocHolder(location);
                        String effects = rs.getString("Effects");
                        DataFactory.addEffectsFrom(effects, eh);
                    }
                } catch (SQLException e) {
                    //Log the issue
                } finally {
                    try {
                        if (statement != null)
                            statement.close();
                        if (con != null)
                            con.close();
                    } catch (SQLException ignored) {
                    }
                }
            }
        }
        return null;
    }
} public class ItemSpray extends Effect {

    public static ArrayList<ItemSprayRemoveTask> TASKS = new ArrayList<ItemSprayRemoveTask>();
    public static ArrayList<UUID> UUID_LIST = new ArrayList<UUID>();

    public int idValue;
    public int metaValue;

    public ItemSpray(EffectHolder effectHolder, int idValue, int metaValue) {
        super(effectHolder, ParticleType.ITEMSPRAY);
        this.idValue = idValue;
        this.metaValue = metaValue;
    }

    @Override
    public boolean play() {
        boolean shouldPlay = super.play();
        if (shouldPlay) {
            for (Location l : this.displayType.getLocations(this.getHolder().getEffectPlayLocation())) {
                for (int i = 1; i <= 5; i++) {
                    Item item = this.getWorld().dropItemNaturally(l, new ItemStack(this.idValue, 1, (short) this.metaValue));
                    item.setVelocity(item.getVelocity().normalize().multiply(0.4F));
                    item.setPickupDelay(Integer.MAX_VALUE);
                    new ItemSprayRemoveTask(item);
                }
            }
        }
        return shouldPlay;
    }

    @Override
    public void playDemo(Player p) {
        for (int i = 1; i <= 5; i++) {
            Item item = this.getWorld().dropItemNaturally(new Location(p.getWorld(), p.getLocation().getX() + 0.5D, p.getLocation().getY(), p.getLocation().getZ() + 0.5D), new ItemStack(this.idValue, 1, (short) this.metaValue));
            item.setPickupDelay(Integer.MAX_VALUE);
            new ItemSprayRemoveTask(item);
        }
    }

    public class ItemSprayRemoveTask extends BukkitRunnable {

        private Item item;
        private UUID uuid;

        ItemSprayRemoveTask(Item item) {
            this.item = item;
            this.uuid = item.getUniqueId();
            TASKS.add(this);
            UUID_LIST.add(this.uuid);
            this.runTaskLater(SparkTrailPlugin.getInstance(), 50L);
        }

        @Override
        public void run() {
            this.executeFinish(true);
        }

        public void executeFinish(boolean removeFromLists) {
            if (this.item != null && !this.item.isDead()) {
                this.item.remove();
            }
            if (removeFromLists) {
                TASKS.remove(this);
                UUID_LIST.remove(this.uuid);
            }
        }

        @Override
        public synchronized void cancel() throws IllegalStateException {
            super.cancel();
        }
    }
} public enum Lang {

    PREFIX("prefix", "&2ST&a » &r"),

    NO_PERMISSION("no_permission", "&aYou are not permitted to do that."),
    COMMAND_ERROR("cmd_error", "&aError for input string: &e%cmd%&a. Use &e/" + SparkTrailPlugin.getInstance().cmdString + " help &afor help."),
    HELP_INDEX_TOO_BIG("help_index_too_big", "&aPage &e%index% &adoes not exist."),
    IN_GAME_ONLY("in_game_only", "&ePlease log in to do that."),
    STRING_ERROR("string_error", "&aError parsing String: [&e%string%&a]. Please revise command arguments."),
    NULL_PLAYER("null_player", "&e%player% &ais not online. Please try a different Player."),
    INT_ONLY("int_only", "&e%string% &aneeds to be an integer."),
    INT_ONLY_WITH_ARGS("int_only_with_args", "&e%string% &a[Arg &e%argNum%&a] needs to be an integer."),
    NO_SOUND_IN_STRING("no_sound_in_string", "&aError parsing String: [&e%string%&a]. Sound Trail could not be created."),
    WHUPS("whups", "&aWhups. Something bad happened. Please report this, along with information on what you did."),
    CONFIGS_RELOADED("configs_reloaded", "&aConfiguration files reloaded."),
    MENU_DISABLED("menu_disabled", "&aTrail menu has been globally disabled."),

    PLAYER_LIST_NO_ACTIVE_EFFECTS("player_list_no_active_effects", "&aThere are no Player Trail effects active."),
    PLAYER_NO_ACTIVE_EFFECTS("player_no_active_effects", "&aThere are no Player Trail effects active for &e%player%&a."),
    PLAYER_NO_EFFECTS_TO_LOAD("player_no_effects_to_load", "&aThere are no Trail effects to load for &e%player%&a."),
    PLAYER_EFFECTS_LOADED("player_effects_loaded", "&aTrail effects have been loaded for &e%player%&a."),
    PLAYER_EFFECTS_STOPPED("player_effects_stopped", "&aTrail effects stopped for &e%player%&a."),
    PLAYER_EFFECTS_CLEARED("player_effects_cleared", "&aTrail effects cleared for &e%player%&a."),

    NO_ACTIVE_EFFECTS("no_active_effects", "&aYou do not have any Trail effects active."),
    TIMEOUT_SET("timeout_set", "&aTimeout has been set to &e%timeout%&a."),
    MAX_EFFECTS_ALLOWED("max_effects_allowed", "&aMaximum number of effects reached."),
    EFFECT_CREATION_FAILED("effect_creation_failed", "&aEffect creation has failed. SparkTrail may have encountered a severe error."),
    CANCEL_EFFECT_CREATION("cancel_effect_creation", "&aEffect creation cancelled."),
    EFFECT_ADDED("effect_added", "&e%effect% &aeffect added."),
    EFFECT_REMOVED("effect_removed", "&e%effect% &aeffect removed."),
    EFFECTS_LOADED("effects_loaded", "&aYour Trail effects have been loaded."),
    EFFECTS_CLEARED("effects_cleared", "&aYour Trail effects have been cleared."),
    NO_EFFECTS_TO_LOAD("no_effects_to_load", "&aYou have no Trail effects to load."),
    EFFECTS_STOPPED("effects_stopped", "&aYour Trail effects have been stopped."),
    RANDOM_SELECT_FAILED("random_select_failed", "&aRandom Trail selection has failed."),
    SWIRL_NOT_ALLOWED("swirl_not_allowed", "&eSwirl &aTrail effect cannot be added to blocks."),

    LOC_NO_EFFECTS_RETRY_BLOCK_INTERACT("loc_no_effects_retry_block_interact", "&aLocation Trail effects do no exist for that block. Would you like to retry? [&eYES &aor &eNO&a]"),
    LOC_EFFECTS_STARTED("loc_effects_started", "&aLocation Trail effect started."),
    LOC_EFFECTS_STOPPED("loc_effects_stopped", "&aLocation Trail effect stopped."),
    LOC_EFFECTS_CLEARED("loc_effects_cleared", "&aLocation Trail effect cleared."),
    LOC_EFFECTS_LOADED("loc_effects_loaded", "&Location Trail effects loaded."),
    LOC_NO_EFFECTS_TO_LOAD("loc_no_effects_to_load", "&aThere are no Trail effects to load for that location."),
    LOC_LIST_NO_ACTIVE_EFFECTS("loc_list_no_active_effects", "&aThere are no Location Trail effects active."),
    LOC_NO_ACTIVE_EFFECTS("loc_no_active_effects", "&aThere are no Trail effects active at that location."),
    LOC_NO_ACTIVE_EFFECTS_RETRY_BLOCK_INTERACT("loc_no_active_effects_retry_block_interact", "&aThere are no Location Trail effects active. Would you like to retry? [&eYES &aor &eNO&a]"),
    LOC_STOP_ALL("loc_stop_all", "&aAll Location Trail effects have been stopped."),

    MOB_NO_EFFECTS_RETRY_INTERACT("mob_no_effects_retry_interact", "&aMob Trail effects do no exist for that block. Would you like to retry? [&eYES &aor &eNO&a]"),
    MOB_EFFECTS_STOPPED("mob_effects_stopped", "&aMob Trail effect stopped."),
    MOB_EFFECTS_STARTED("mob_effects_started", "&aMob Trail effect started."),
    MOB_EFFECTS_CLEARED("mob_effects_cleared", "&aMob Trail effect cleared."),
    MOB_NO_EFFECTS_TO_LOAD("mob_no_effects_to_load", "&aThere are no Trail effects to load for that Mob."),
    MOB_LIST_NO_ACTIVE_EFFECTS("mob_list_no_active_effects", "&aThere are no Mob Trail effects active."),
    MOB_NO_ACTIVE_EFFECTS_RETRY_INTERACT("mob_no_active_effects_retry_interact", "&aThere are no Mob Trail effects active. Would you like to retry? [&eYES &aor &eNO&a]"),

    INVALID_EFFECT_ARGS("invalid_effect_args", "&aInvalid &e%effect% &aeffect arguments entered. %extra_info%"),
    CRITICAL_HELP("critical_help", "&eCritical &aeffects: &eNormal&a, &eMagic&a."),
    POTION_HELP("potion_help", "&ePotion &aeffects: &eAqua&a, &eBlack&a, &eBlue&a, &eCrimson&a, &eDarkBlue&a, &eDarkGreen&a, &eDarkRed&a, &eGold&a, &eGray&a, &eGreen&a, &ePink&a, &eRed&a."),
    SMOKE_HELP("smoke_help", "&eSmoke &aeffects: &eRed&a, &eBlack&a, &eRainbow&a."),
    SWIRL_HELP("swirl_help", "&eSwirl &aeffects: &eLightBlue&a, &eBlue&a, &eDarkBlue&a, &eRed&a, &eDarkRed&a, &eGreen&a, &eDarkGreen&a, &eYellow&a, &eOrange&a, &eGray&a, &eBlack&a, &eWhite&a, &ePurple&a, &ePink&a."),

    INPUT_FIRST_IDVALUE("input_first_idvalue", "&aWhat ID value would you like this effect to have?"),
    INPUT_SECOND_METAVALUE("input_second_idvalue", "&aWhat Block Meta value would you like this effect to have?"),
    INVALID_INPUT("invalid_input", "&aInvalid. Retry or enter &eexit &ato cancel."),
    INPUT_FIREWORK("input_firework", "&aWhat firework effects would you like this effect to have? Separate each parameter with a space."),
    INPUT_TIMEOUT("input_timeout", "&aHow long until this set of effects times out?"),

    MENU_ERROR("menu_error", "&aThere has been a problem with the Trail GUI Menu. Please see the console for details."),
    OPEN_MENU("open_menu", "&aOpening Trail Effect GUI"),
    ENTER_BLOCK_OR_ITEM("enter_block_break", "&aPlease enter effect parameters [&e%effect%&a]. Structure: &e<IdValue> <Meta>"),
    ENTER_FIREWORK("enter_firework", "&aPlease enter effect parameters [&eFirework&a]. Separate each parameter with a space."),
    ENTER_TIMEOUT("enter_timeout", "&aPlease enter an integer."),
    INCORRECT_EFFECT_ARGS("incorrect_blockbreak_args", "&aCould not create &e%effect% &aeffect from String [&e%string%&a]. Would you like to retry? [&eYES &aor &eNO&a]"),
    YES_OR_NO("yes_or_no", "&aPlease enter &eYES &aor &eNO&a."),
    INTERACT_BLOCK("interact_block", "&aPlease interact with a target block to modify its Trail effects."),
    INTERACT_MOB("interact_mob", "&aPlease interact with a target entity to modify its Trail effects."),
    RETRY_BLOCK_INTERACT("retry_block_interact", "&aUse the Trail command to create Air Trail effects. Would you like to retry creating a block effect? &e[YES or NO]"),
    RETRY_MOB_INTERACT("retry_mob_interact", "&aInteract with an Entity (other than a Player) to modify its Trail effects. Would you like to retry? [&eYES &aor &eNO&a]"),
    EXECUTE_LOC_LIST("execute_loc_list", "&aExecute &e/" + SparkTrailPlugin.getInstance().cmdString + " list &ato view the list of Location Trail effects. Use the IDs to run &e/" + SparkTrailPlugin.getInstance().cmdString + " stop <id>&a."),

    DEMO_BEGIN("demo_begin", "&aStarting Trail Demo. You may enter the following commands during the presentation: &eNAME&a, &eSTOP&a."),
    DEMO_STOP("demo_stop", "&aTrail Demo has been stopped."),
    DEMO_CURRENT_PARTICLE("demo_current_particle", "&aCurrent Trail effect: &e%effect%&a."),

    ADMIN_OPEN_MENU("open_player_menu", "&aOpening Trail Effect GUI for &e%player%&a."),;

    private String path;
    private String def;
    private String[] desc;

    Lang(String path, String def, String... desc) {
        this.path = path;
        this.def = def;
        this.desc = desc;
    }

    public String[] getDescription() {
        return this.desc;
    }

    public String getPath() {
        return this.path;
    }

    public static void sendTo(CommandSender sender, String msg) {
        if (msg != null || !msg.equalsIgnoreCase("") && !msg.equalsIgnoreCase(" ") && !msg.equalsIgnoreCase("none")) {
            sender.sendMessage(SparkTrailPlugin.getInstance().prefix + msg);
        }
    }

    public static void sendTo(Player p, String msg) {
        if (msg != null && !msg.equalsIgnoreCase("") && !msg.equalsIgnoreCase(" ") && !(msg.equalsIgnoreCase("none"))) {
            p.sendMessage(SparkTrailPlugin.getInstance().prefix + msg);
        }
    }

    @Override
    public String toString() {
        String result = SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.LANG).getString(this.path, this.def);
        if (result != null && result != "" && result != "none") {
            return ChatColor.translateAlternateColorCodes('&', SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.LANG).getString(this.path, this.def));
        } else {
            return "";
        }
    }

    public String getRaw() {
        return SparkTrailPlugin.getInstance().getConfig(SparkTrailPlugin.ConfigType.LANG).getString(this.path, this.def);
    }
} public enum Permission {

    UPDATE("sparktrail.update"),
    TRAIL("sparktrail.trail"),
    RELOAD("sparktrail.trail.reload"),

    PLAYER_TRAIL("sparktrail.player.trail"),
    PLAYER_INFO("sparktrail.trail.player.info"),
    PLAYER_START("sparktrail.trail.player.start"),
    PLAYER_STOP("sparktrail.trail.player.stop"),
    PLAYER_CLEAR("sparktrail.trail.player.clear"),
    PLAYER_LIST("sparktrail.trail.player.list"),

    LOC_TRAIL("sparktrail.trail.location"),
    LOC_START("sparktrail.trail.location.start"),
    LOC_STOP("sparktrail.trail.location.stop"),
    LOC_STOP_ALL("sparktrail.trail.location.stop.all"),
    LOC_CLEAR("sparktrail.trail.location.clear"),
    LOC_LIST("sparktrail.trail.location.list"),

    MOB_TRAIL("sparktrail.trail.mob"),
    MOB_START("sparktrail.trail.mob.start"),
    MOB_STOP("sparktrail.trail.mob.stop"),
    MOB_CLEAR("sparktrail.trail.mob.clear"),
    MOB_LIST("sparktrail.trail.mob.list"),

    SOUND("sparktrail.trail.sound"),
    TIMEOUT("sparktrail.trail.timeout"),
    CLEAR("sparktrail.trail.clear"),
    STOP("sparktrail.trail.stop"),
    START("sparktrail.trail.start"),
    DEMO("sparktrail.trail.demo"),
    INFO("sparktrail.trail.info"),;

    String perm;

    Permission(String perm) {
        this.perm = perm;
    }

    public boolean hasPerm(CommandSender sender, boolean sendMessage, boolean allowConsole) {
        if (sender instanceof Player) {
            return hasPerm(((Player) sender), sendMessage);
        } else {
            if (!allowConsole && sendMessage) {
                Lang.sendTo(sender, Lang.IN_GAME_ONLY.toString());
            }
            return allowConsole;
        }
    }

    public boolean hasPerm(Player player, boolean sendMessage) {
        if (player.hasPermission(this.perm)) {
            return true;
        }
        if (sendMessage) {
            Lang.sendTo(player, Lang.NO_PERMISSION.toString().replace("%perm%", this.perm));
        }
        return false;
    }

    public static boolean hasEffectPerm(Player player, boolean sendMessage, String perm) {
        if (player.hasPermission(perm)) {
            return true;
        }
        if (sendMessage) {
            Lang.sendTo(player, Lang.NO_PERMISSION.toString().replace("%perm%", perm));
        }
        return false;
    }

    public static boolean hasEffectPerm(Player player, boolean sendMessage, ParticleType particleType, String effectType) {
        String perm = "sparktrail.trail" + (effectType == null ? "" : ("." + effectType.toLowerCase())) + ".type." + particleType.toString().toLowerCase();
        return hasEffectPerm(player, sendMessage, perm);
    }

    public static boolean hasEffectPerm(Player player, boolean sendMessage, ParticleType particleType, String data, String effectType) {
        String perm = "sparktrail.trail" + (effectType == null ? "" : ("." + effectType.toString().toLowerCase())) + ".type." + particleType.toString().toLowerCase();
        return hasEffectPerm(player, sendMessage, perm + "." + data);
    }
}
import com.dsh105.dshutils.DSHPlugin;
import com.dsh105.dshutils.Metrics;
import com.dsh105.dshutils.Updater;
import com.dsh105.dshutils.command.CustomCommand;
import com.dsh105.dshutils.config.YAMLConfig;
import com.dsh105.dshutils.logger.ConsoleLogger;
import com.dsh105.dshutils.logger.Logger;
import com.dsh105.dshutils.util.VersionUtil;
import com.dsh105.sparktrail.api.SparkTrailAPI;
import com.dsh105.sparktrail.chat.MenuChatListener;
import com.dsh105.sparktrail.command.CommandComplete;
import com.dsh105.sparktrail.command.TrailCommand;
import com.dsh105.sparktrail.config.ConfigOptions;
import com.dsh105.sparktrail.data.AutoSave;
import com.dsh105.sparktrail.data.EffectManager;
import com.dsh105.sparktrail.listeners.EntityListener;
import com.dsh105.sparktrail.listeners.InteractListener;
import com.dsh105.sparktrail.listeners.PlayerListener;
import com.dsh105.sparktrail.menu.MenuListener;
import com.dsh105.sparktrail.mysql.SQLEffectManager;
import com.dsh105.sparktrail.trail.type.ItemSpray;
import com.dsh105.sparktrail.util.Lang;
import com.dsh105.sparktrail.util.Permission;
import com.jolbox.bonecp.BoneCP;
import com.jolbox.bonecp.BoneCPConfig;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
        } catch (Exception e) {
            Logger.log(Logger.LogLevel.SEVERE, "Failed to generate Configuration File (config.yml).", e, true);
        }

        config.reloadConfig();

        ChatColor colour1 = ChatColor.getByChar(this.getConfig(ConfigType.MAIN).getString("primaryChatColour", "a"));
        if (colour1 != null) {
            this.primaryColour = colour1;
        }
        ChatColor colour2 = ChatColor.getByChar(this.getConfig(ConfigType.MAIN).getString("secondaryChatColour", "e"));
        if (colour2 != null) {
            this.secondaryColour = colour2;
        }

        try {
            dataConfig = this.getConfigManager().getNewConfig("data.yml");
        } catch (Exception e) {
            Logger.log(Logger.LogLevel.SEVERE, "Failed to generate Configuration File (data.yml).", e, true);
        }
        dataConfig.reloadConfig();

        String[] langHeader = {"SparkTrail By DSH105", "---------------------",
                "Language Configuration File"};
        try {
            langConfig = this.getConfigManager().getNewConfig("language.yml", langHeader);
            try {
                for (Lang l : Lang.values()) {
                    String[] desc = l.getDescription();
                    langConfig.set(l.getPath(), langConfig.getString(l.getPath(), l.getRaw()
                            .replace("&a", "&" + this.primaryColour.getChar())
                            .replace("&e", "&" + this.secondaryColour.getChar())),
                            desc);
                }
                langConfig.saveConfig();
            } catch (Exception e) {
                Logger.log(Logger.LogLevel.SEVERE, "Failed to generate Configuration File (language.yml).", e, true);
            }

        } catch (Exception e) {
        }
        langConfig.reloadConfig();

        this.prefix = Lang.PREFIX.toString();

        this.EH = new EffectManager();
        this.SQLH = new SQLEffectManager();

        if (this.config.getBoolean("useSql", false)) {
            String host = config.getString("sql.host", "localhost");
            int port = config.getInt("sql.port", 3306);
            String db = config.getString("sql.database", "SparkTrail");
            String user = config.getString("sql.username", "none");
            String pass = config.getString("sql.password", "none");
            BoneCPConfig bcc = new BoneCPConfig();
            bcc.setJdbcUrl("jdbc:mysql://" + host + ":" + port + "/" + db);
            bcc.setUsername(user);
            bcc.setPassword(pass);
            bcc.setPartitionCount(2);
            bcc.setMinConnectionsPerPartition(3);
            bcc.setMaxConnectionsPerPartition(7);
            bcc.setConnectionTestStatement("SELECT 1");
            try {
                dbPool = new BoneCP(bcc);
            } catch (SQLException e) {
                Logger.log(Logger.LogLevel.SEVERE, "Failed to connect to MySQL! [MySQL DataBase: " + db + "].", e, true);
            }
            if (dbPool != null) {
                Connection connection = null;
                Statement statement = null;
                try {
                    connection = dbPool.getConnection();
                    statement = connection.createStatement();
                    statement.executeUpdate("CREATE TABLE IF NOT EXISTS PlayerEffects (" +
                            "PlayerName varchar(255)," +
                            "Effects varchar(255)," +
                            "PRIMARY KEY (PlayerName)" +
                            ");");

                    statement.executeUpdate("CREATE TABLE IF NOT EXISTS LocationEffects (" +
                            "Location varchar(255)," +
                            "Effects varchar(255)," +
                            "PRIMARY KEY (Location)" +
                            ");");

                    statement.executeUpdate("CREATE TABLE IF NOT EXISTS MobEffects (" +
                            "MobUUID varchar(255)," +
                            "Effects varchar(255)," +
                            "PRIMARY KEY (MobUUID)" +
                            ");");
                } catch (SQLException e) {
                    Logger.log(Logger.LogLevel.SEVERE, "MySQL DataBase Table initiation has failed.", e, true);
                }
            }
        }

        if (this.config.getBoolean("autosave", true)) {
            this.AS = new AutoSave(this.config.getInt("autosaveTimer", 180));
        }

        // Register custom commands
        // Command string based off the string defined in config.yml
        try {
            Class craftServer = Class.forName("org.bukkit.craftbukkit." + VersionUtil.getServerVersion() + ".CraftServer");
            if (craftServer.isInstance(Bukkit.getServer())) {
                final Field f = craftServer.getDeclaredField("commandMap");
                f.setAccessible(true);
                CM = (CommandMap) f.get(Bukkit.getServer());
            }
        } catch (Exception e) {
            Logger.log(Logger.LogLevel.WARNING, "Registration of commands failed.", e, true);
        }

        String cmdString = this.config.getString("command", "trail");
        if (CM.getCommand(cmdString) != null) {
            Logger.log(Logger.LogLevel.WARNING, "A command under the name " + ChatColor.RED + "/" + cmdString + ChatColor.YELLOW + " already exists. Trail Command temporarily registered under " + ChatColor.RED + "/st:" + cmdString, true);
        }

        CustomCommand cmd = new CustomCommand(cmdString);
        CM.register("st", cmd);
        cmd.setExecutor(new TrailCommand(cmdString));