package com.btk5h.skriptmirror.skript;

import com.btk5h.skriptmirror.SkriptMirror;

import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import ch.njol.skript.Skript;
import ch.njol.skript.SkriptConfig;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptParser;

public class EvtByReflection extends SkriptEvent {
  static {
    Skript.registerEvent("Bukkit Event", EvtByReflection.class, BukkitEvent.class,
        "%strings% [(at|on|with) priority %-number%]");
  }

  private static class PriorityListener implements Listener {
    private EventPriority priority;
    private Set<Class<? extends Event>> events = new HashSet<>();

    public PriorityListener(int priority) {
      this.priority = EventPriority.values()[priority];
    }

    public EventPriority getPriority() {
      return priority;
    }

    public Set<Class<? extends Event>> getEvents() {
      return events;
    }
  }

  private static EventExecutor executor = new EventExecutor() {

    @Override
    public void execute(Listener listener, Event event) throws EventException {
      Bukkit.getPluginManager()
          .callEvent(new BukkitEvent(event, ((PriorityListener) listener).getPriority()));
    }
  };

  private static PriorityListener[] listeners = new PriorityListener[]{
      new PriorityListener(0),
      new PriorityListener(1),
      new PriorityListener(2),
      new PriorityListener(3),
      new PriorityListener(4),
      new PriorityListener(5)
  };

  static class BukkitEvent extends Event {
    private final static HandlerList handlers = new HandlerList();

    private final Event event;
    private final EventPriority priority;

    public BukkitEvent(Event event, EventPriority priority) {
      this.event = event;
      this.priority = priority;
    }

    public Event getEvent() {
      return event;
    }

    public EventPriority getPriority() {
      return priority;
    }

    public static HandlerList getHandlerList() {
      return handlers;
    }

    @Override
    public HandlerList getHandlers() {
      return handlers;
    }

  }

  private static Set<Class<? extends Event>> events = new HashSet<>();

  private static void registerEvent(Class<? extends Event> event, EventPriority priority) {
    PriorityListener listener = listeners[priority.ordinal()];
    Set<Class<? extends Event>> events = listener.getEvents();

    if (!events.contains(event)) {
      events.add(event);
      Bukkit.getPluginManager()
          .registerEvent(event, listener, priority, executor, SkriptMirror.getInstance());
    }
  }

  private Class<? extends Event>[] classes;
  private EventPriority priority;

  @SuppressWarnings("unchecked")
  @Override
  public boolean init(Literal<?>[] args, int matchedPattern, SkriptParser.ParseResult parseResult) {
    String[] events = ((Literal<String>) args[0]).getArray();

    classes = (Class<? extends Event>[]) Array.newInstance(Class.class, events.length);

    for (int i = 0; i < events.length; i++) {
      String event = events[i];

      try {
        Class<?> eventClass = Class.forName(event);

        if (!Event.class.isAssignableFrom(eventClass)) {
          Skript.error(event + " is not an event.");
          return false;
        }

        classes[i] = (Class<? extends Event>) eventClass;
      } catch (ClassNotFoundException e) {
        Skript.error(event + " refers to a non-existent class.");
        return false;
      }
    }

    if (args[1] == null) {
      priority = SkriptConfig.defaultEventPriority.value();
    } else {
      int priorityIndex = ((Literal<Number>) args[1]).getSingle().intValue();

      priorityIndex = Math.max(0, Math.min(priorityIndex, listeners.length - 1));

      priority = listeners[priorityIndex].getPriority();
    }

    for (Class<? extends Event> cls : classes) {
      registerEvent(cls, priority);
    }

    return true;
  }

  @Override
  public boolean check(Event e) {
    Class<? extends Event> eventClass = ((BukkitEvent) e).getEvent().getClass();
    if (priority == ((BukkitEvent) e).getPriority()) {
      for (Class<? extends Event> cls : classes) {
        if (cls == eventClass) {
          return true;
        }
      }
    }
    return false;
  }

  @Override
  public String toString(Event e, boolean debug) {
    return Arrays.toString(classes) + " priority " + priority;
  }
}

@@ -139,48 +139,8 @@
 nt;%0A
-import org.bukkit.event.EventException;%0A
 impo
@@ -1255,79 +1255,16 @@
 or =
- new EventExecutor() %7B%0A%0A    @Override%0A    public void execute(Listener 
+%0A      (
 list
@@ -1272,22 +1272,16 @@
 ner,
- Event
  event) 
 thro
@@ -1280,37 +1280,10 @@
 nt) 
-throws EventException %7B%0A     
+-%3E
  Buk
@@ -1399,19 +1399,8 @@
 )));
-%0A    %7D%0A  %7D;
 %0A%0A  

Replace unnecessary anonymous class