// Path: EventBus/src/org/greenrobot/eventbus/ThreadMode.java
// public enum ThreadMode {
//     /**
//      * This is the default. Subscriber will be called directly in the same thread, which is posting the event. Event delivery
//      * implies the least overhead because it avoids thread switching completely. Thus, this is the recommended mode for
//      * simple tasks that are known to complete in a very short time without requiring the main thread. Event handlers
//      * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread.
//      */
//     POSTING,
// 
//     /**
//      * On Android, subscriber will be called in Android's main thread (UI thread). If the posting thread is
//      * the main thread, subscriber methods will be called directly, blocking the posting thread. Otherwise the event
//      * is queued for delivery (non-blocking). Subscribers using this mode must return quickly to avoid blocking the main thread.
//      * <p>
//      * If not on Android, behaves the same as {@link #POSTING}.
//      */
//     MAIN,
// 
//     /**
//      * On Android, subscriber will be called in Android's main thread (UI thread). Different from {@link #MAIN},
//      * the event will always be queued for delivery. This ensures that the post call is non-blocking.
//      * <p>
//      * If not on Android, behaves the same as {@link #POSTING}.
//      */
//     MAIN_ORDERED,
// 
//     /**
//      * On Android, subscriber will be called in a background thread. If posting thread is not the main thread, subscriber methods
//      * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single
//      * background thread, that will deliver all its events sequentially. Subscribers using this mode should try to
//      * return quickly to avoid blocking the background thread.
//      * <p>
//      * If not on Android, always uses a background thread.
//      */
//     BACKGROUND,
// 
//     /**
//      * Subscriber will be called in a separate thread. This is always independent of the posting thread and the
//      * main thread. Posting events never wait for subscriber methods using this mode. Subscriber methods should
//      * use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number
//      * of long-running asynchronous subscriber methods at the same time to limit the number of concurrent threads. EventBus
//      * uses a thread pool to efficiently reuse threads from completed asynchronous subscriber notifications.
//      */
//     ASYNC
// }


import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import de.greenrobot.common.ListMap;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.AGGREGATING;
            // Don't use TypeElement.getSimpleName, it doesn't work for us with inner classes
            return className.substring(paket.length() + 1);
        } else {
            // Paranoia
            throw new IllegalStateException("Mismatching " + paket + " vs. " + className);
        }
    }

    private PackageElement getPackageElement(TypeElement subscriberClass) {
        Element candidate = subscriberClass.getEnclosingElement();
        while (!(candidate instanceof PackageElement)) {
            candidate = candidate.getEnclosingElement();
        }
        return (PackageElement) candidate;
    }

    private void writeCreateSubscriberMethods(BufferedWriter writer, List<ExecutableElement> methods,
                                              String callPrefix, String myPackage) throws IOException {
        for (ExecutableElement method : methods) {
            List<? extends VariableElement> parameters = method.getParameters();
            TypeMirror paramType = getParamTypeMirror(parameters.get(0), null);
            TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType);
            String methodName = method.getSimpleName().toString();
            String eventClass = getClassString(paramElement, myPackage) + ".class";

            Subscribe subscribe = method.getAnnotation(Subscribe.class);
            List<String> parts = new ArrayList<>();
            parts.add(callPrefix + "(\"" + methodName + "\",");
            String lineEnd = "),";
            if (subscribe.priority() == 0 && !subscribe.sticky()) {
// Path: EventBus/src/org/greenrobot/eventbus/ThreadMode.java
// public enum ThreadMode {
//     /**
//      * This is the default. Subscriber will be called directly in the same thread, which is posting the event. Event delivery
//      * implies the least overhead because it avoids thread switching completely. Thus, this is the recommended mode for
//      * simple tasks that are known to complete in a very short time without requiring the main thread. Event handlers
//      * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread.
//      */
//     POSTING,
// 
//     /**
//      * On Android, subscriber will be called in Android's main thread (UI thread). If the posting thread is
//      * the main thread, subscriber methods will be called directly, blocking the posting thread. Otherwise the event
//      * is queued for delivery (non-blocking). Subscribers using this mode must return quickly to avoid blocking the main thread.
//      * <p>
//      * If not on Android, behaves the same as {@link #POSTING}.
//      */
//     MAIN,
// 
//     /**
//      * On Android, subscriber will be called in Android's main thread (UI thread). Different from {@link #MAIN},
//      * the event will always be queued for delivery. This ensures that the post call is non-blocking.
//      * <p>
//      * If not on Android, behaves the same as {@link #POSTING}.
//      */
//     MAIN_ORDERED,
// 
//     /**
//      * On Android, subscriber will be called in a background thread. If posting thread is not the main thread, subscriber methods
//      * will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single
//      * background thread, that will deliver all its events sequentially. Subscribers using this mode should try to
//      * return quickly to avoid blocking the background thread.
//      * <p>
//      * If not on Android, always uses a background thread.
//      */
//     BACKGROUND,
// 
//     /**
//      * Subscriber will be called in a separate thread. This is always independent of the posting thread and the
//      * main thread. Posting events never wait for subscriber methods using this mode. Subscriber methods should
//      * use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number
//      * of long-running asynchronous subscriber methods at the same time to limit the number of concurrent threads. EventBus
//      * uses a thread pool to efficiently reuse threads from completed asynchronous subscriber notifications.
//      */
//     ASYNC
// }


// Path: EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import de.greenrobot.common.ListMap;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.AGGREGATING;

            // Don't use TypeElement.getSimpleName, it doesn't work for us with inner classes
            return className.substring(paket.length() + 1);
        } else {
            // Paranoia
            throw new IllegalStateException("Mismatching " + paket + " vs. " + className);
        }
    }

    private PackageElement getPackageElement(TypeElement subscriberClass) {
        Element candidate = subscriberClass.getEnclosingElement();
        while (!(candidate instanceof PackageElement)) {
            candidate = candidate.getEnclosingElement();
        }
        return (PackageElement) candidate;
    }

    private void writeCreateSubscriberMethods(BufferedWriter writer, List<ExecutableElement> methods,
                                              String callPrefix, String myPackage) throws IOException {
        for (ExecutableElement method : methods) {
            List<? extends VariableElement> parameters = method.getParameters();
            TypeMirror paramType = getParamTypeMirror(parameters.get(0), null);
            TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType);
            String methodName = method.getSimpleName().toString();
            String eventClass = getClassString(paramElement, myPackage) + ".class";

            Subscribe subscribe = method.getAnnotation(Subscribe.class);
            List<String> parts = new ArrayList<>();
            parts.add(callPrefix + "(\"" + methodName + "\",");
            String lineEnd = "),";
            if (subscribe.priority() == 0 && !subscribe.sticky()) {
                if (subscribe.threadMode() == ThreadMode.POSTING) {