package net.md_5.bungee.api.event;

import com.google.common.base.Preconditions;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.plugin.Event;
import net.md_5.bungee.api.plugin.Plugin;

/**
 * Represents an event which depends on the result of asynchronous operations.
 *
 * @param <T> Type of this event
 */
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class AsyncEvent<T> extends Event
{

    private final Callback<T> done;
    private final Set<Plugin> intents = Collections.newSetFromMap( new ConcurrentHashMap<Plugin, Boolean>() );
    private final AtomicBoolean fired = new AtomicBoolean();
    private final AtomicInteger latch = new AtomicInteger();

    @Override
    @SuppressWarnings("unchecked")
    public void postCall()
    {
        fired.set( true );
        if ( latch.get() == 0 )
        {
            done.done( (T) this, null );
        }
    }

    /**
     * Register an intent that this plugin will continue to perform work on a
     * background task, and wishes to let the event proceed once the registered
     * background task has completed.
     *
     * @param plugin the plugin registering this intent
     */
    public void registerIntent(Plugin plugin)
    {
        Preconditions.checkState( !fired.get(), "Event %s has already been fired", this );
        Preconditions.checkState( !intents.contains( plugin ), "Plugin %s already registered intent for event %s", plugin, this );

        intents.add( plugin );
        latch.incrementAndGet();
    }

    /**
     * Notifies this event that this plugin has done all its required processing
     * and wishes to let the event proceed.
     *
     * @param plugin a plugin which has an intent registered for this event
     */
    @SuppressWarnings("unchecked")
    public void completeIntent(Plugin plugin)
    {
        Preconditions.checkState( intents.contains( plugin ), "Plugin %s has not registered intent for event %s", plugin, this );
        intents.remove( plugin );
        if ( latch.decrementAndGet() == 0 && fired.get() )
        {
            done.done( (T) this, null );
        }
    }
}

@@ -1065,35 +1065,8 @@
   %7B%0A
-        fired.set( true );%0A
     
@@ -1150,24 +1150,51 @@
 ;%0A        %7D%0A
+        fired.set( true );%0A
     %7D%0A%0A    /
@@ -2292,24 +2292,65 @@
         if (
+ fired.get() )%0A        %7B%0A            if (
  latch.decre
@@ -2371,25 +2371,14 @@
 = 0 
-&& fired.get() )%0A
+)%0A    
     
@@ -2375,32 +2375,36 @@
 )%0A            %7B%0A
+    
             done
@@ -2420,32 +2420,100 @@
 ) this, null );%0A
+            %7D%0A        %7D else %7B%0A            latch.decrementAndGet();%0A
         %7D%0A    %7D%0A

Fix AsyncEvent callback triggering.