package com.bnorm.infinite.async;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.bnorm.infinite.Action;
import com.bnorm.infinite.Transition;

/**
 * A factory interface for asynchronous actions.
 *
 * @param <S> the class type of the states.
 * @param <E> the class type of the events.
 * @param <C> the class type of the context.
 * @author Brian Norman
 * @version 1.1.0
 * @since 1.1.0
 */
public interface AsyncActionFactory<S, E, C> {

    /**
     * Returns the default async action factory.  This async action factory has the default cached thread pool as a
     * backing with an action thread factory set to name all threads as {@code AsyncAction}.
     *
     * @param <S> the class type of the states.
     * @param <E> the class type of the events.
     * @param <C> the class type of the context.
     * @return default async action factory.
     */
    static <S, E, C> AsyncActionFactory<S, E, C> getDefault() {
        return new AsyncActionFactory<S, E, C>() {
            /** The backing executor. */
            private final ExecutorService executor = Executors.newCachedThreadPool(
                    new NamedThreadFactory("AsyncAction"));

            @Override
            public ExecutorService getExecutor() {
                return executor;
            }
        };
    }


    /**
     * Creates a new action that is an asynchronous version of the specified action.  The new asynchronous action uses
     * the factory executor to execute the specified action.
     *
     * @param action the action to perform asynchronously.
     * @return a new asynchronous action.
     */
    default Action<S, E, C> create(Action<S, E, C> action) {
        return new Action<S, E, C>() {
            @Override
            public void perform(S state, E event, Transition<? extends S, ? extends C> transition, C context) {
                getExecutor().submit(() -> action.perform(state, event, transition, context));
            }
        };
    }

    /**
     * Returns the executor service that backs this async action factory.  This is the executor used to perform all
     * asynchronous actions.
     *
     * @return the asynchronous action executor.
     */
    ExecutorService getExecutor();
}

@@ -517,32 +517,39 @@
 he default async
+hronous
  action factory.
@@ -552,32 +552,39 @@
 ory.  This async
+hronous
  action factory 
@@ -612,16 +612,23 @@
 d thread
+%0A     *
  pool as
@@ -629,23 +629,16 @@
 ool as a
-%0A     *
  backing
@@ -648,16 +648,14 @@
 th a
-n action
+ named
  thr
@@ -711,16 +711,23 @@
 ncAction
+%5Bindex%5D
 %7D.%0A     
@@ -897,24 +897,31 @@
 efault async
+hronous
  action fact
@@ -1105,16 +1105,8 @@
     
-private 
 fina
@@ -1168,29 +1168,8 @@
 ool(
-%0A                    
 new 
@@ -1250,71 +1250,391 @@
 lic 
-ExecutorService getExecutor() %7B%0A                return executor
+Action%3CS, E, C%3E create(Action%3CS, E, C%3E action) %7B%0A                return new Action%3CS, E, C%3E() %7B%0A                    @Override%0A                    public void perform(S state, E event, Transition%3C? extends S, ? extends C%3E transition, C context) %7B%0A                        executor.submit(() -%3E action.perform(state, event, transition, context));%0A                    %7D%0A                %7D
 ;%0A  
@@ -1810,16 +1810,27 @@
 factory 
+completion 
 executor
@@ -1983,24 +1983,16 @@
  */%0A    
-default 
 Action%3CS
@@ -2033,561 +2033,8 @@
 ion)
- %7B%0A        return new Action%3CS, E, C%3E() %7B%0A            @Override%0A            public void perform(S state, E event, Transition%3C? extends S, ? extends C%3E transition, C context) %7B%0A                getExecutor().submit(() -%3E action.perform(state, event, transition, context));%0A            %7D%0A        %7D;%0A    %7D%0A%0A    /**%0A     * Returns the executor service that backs this async action factory.  This is the executor used to perform all%0A     * asynchronous actions.%0A     *%0A     * @return the asynchronous action executor.%0A     */%0A    ExecutorService getExecutor()
 ;%0A%7D%0A

Access to the async action executor should be limited