package org.jenkinsci.plugins.github.extension;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.AbstractProject;
import jenkins.model.Jenkins;
import org.kohsuke.github.GHEvent;

import java.util.Set;

/**
 * Extension point to contribute events from GH, which plugin interested in.
 * This point should return true in {@link #isApplicable(AbstractProject)}
 * only if it can parse hooks with events contributed in {@link #events()}
 *
 * Each time this plugin wants to get events list from contributors it asks for applicable status
 *
 * @author lanwen (Merkushev Kirill)
 * @since TODO
 */
public abstract class GHEventsSubscriber implements ExtensionPoint {

    /**
     * Should return true only if this subscriber interested in {@link #events()} set for this project
     *
     * @param project to check
     *
     * @return true to provide events to register and subscribe for this project
     */
    public abstract boolean isApplicable(AbstractProject<?, ?> project);

    /**
     * @return immutable set of events this subscriber wants to register and then subscribe to
     */
    public abstract Set<GHEvent> events();

    /**
     * @return All subscriber extensions
     */
    public static ExtensionList<GHEventsSubscriber> all() {
        return Jenkins.getInstance().getExtensionList(GHEventsSubscriber.class);
    }

    /**
     * Converts each subscriber to set of GHEvents
     *
     * @return converter to use in iterable manipulations
     */
    public static Function<GHEventsSubscriber, Set<GHEvent>> extractEvents() {
        return new Function<GHEventsSubscriber, Set<GHEvent>>() {
            @Override
            public Set<GHEvent> apply(GHEventsSubscriber provider) {
                return provider.events();
            }
        };
    }

    /**
     * Helps to filter only GHEventsSubscribers that can return TRUE on given project
     *
     * @param project to check every GHEventsSubscriber for being applicable
     *
     * @return predicate to use in iterable filtering
     */
    public static Predicate<GHEventsSubscriber> isApplicableFor(final AbstractProject<?, ?> project) {
        return new Predicate<GHEventsSubscriber>() {
            @Override
            public boolean apply(GHEventsSubscriber provider) {
                return provider.isApplicable(project);
            }
        };
    }
}

@@ -334,25 +334,24 @@
 oint to 
-cont
+subsc
 rib
-ut
 e events
@@ -600,18 +600,17 @@
 rom 
-contributo
+subscribe
 rs i
@@ -1086,32 +1086,160 @@
 ject);%0A%0A    /**%0A
+     * Should be not null. Should return only events which this extension can parse in %7B@link #onEvent(GHEvent, String)%7D%0A     *%0A
      * @return i
@@ -1316,16 +1316,17 @@
 cribe to
+.
 %0A     */
@@ -1366,24 +1366,606 @@
  events();%0A%0A
+    /**%0A     * This method called when root action receives webhook from GH and this extension is interested in such%0A     * events (provided by %7B@link #events()%7D method). By default do nothing and can be overrided to implement any%0A     * parse logic%0A     *%0A     * @param event   gh-event (as of PUSH, ISSUE...). One of returned by %7B@link #events()%7D method. Never null.%0A     * @param payload payload of gh-event. Never blank. Can be parsed with help of GitHub#parseEventPayload%0A     */%0A    public void onEvent(GHEvent event, String payload) %7B%0A        // do nothing by default%0A    %7D%0A%0A
     /**%0A    
@@ -3173,11 +3173,1330 @@
 %7D;%0A    %7D
+%0A%0A    /**%0A     * Predicate which returns true on apply if current subscriber is interested in event%0A     *%0A     * @param event should be one of %7B@link #events()%7D set to return true on apply%0A     *%0A     * @return predicate to match against %7B@link GHEventsSubscriber%7D%0A     */%0A    public static Predicate%3CGHEventsSubscriber%3E isInterestedIn(final GHEvent event) %7B%0A        return new Predicate%3CGHEventsSubscriber%3E() %7B%0A            @Override%0A            public boolean apply(GHEventsSubscriber subscriber) %7B%0A                return subscriber.events().contains(event);%0A            %7D%0A        %7D;%0A    %7D%0A%0A    /**%0A     * Function which calls %7B@link #onEvent(GHEvent, String)%7D for every subscriber on apply%0A     *%0A     * @param event from hook. Applied only with event from %7B@link #events()%7D set%0A     * @param payload string content of hook from GH. Never blank%0A     *%0A     * @return function to process %7B@link GHEventsSubscriber%7D list. Returns null on apply.%0A     */%0A    public static Function%3CGHEventsSubscriber, Void%3E processEvent(final GHEvent event, final String payload) %7B%0A        return new Function%3CGHEventsSubscriber, Void%3E() %7B%0A            @Override%0A            public Void apply(GHEventsSubscriber subscriber) %7B%0A                subscriber.onEvent(event, payload);%0A                return null;%0A            %7D%0A        %7D;%0A    %7D
 %0A%7D%0A

add method to extension point for parse payload of any GHEvent