// Path: cachedfield/src/main/java/com/byoutline/cachedfield/FieldState.java
// public enum FieldState {
// 
//     NOT_LOADED, CURRENTLY_LOADING, LOADED
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/CallResult.java
// @AutoValue
// public abstract class CallResult<RETURN_TYPE> {
// 
//     public static <RETURN_TYPE> CallResult<RETURN_TYPE> create(@Nullable RETURN_TYPE successResult,
//                                                                @Nullable Exception failureResult) {
//         return new AutoValue_CallResult<RETURN_TYPE>(successResult, failureResult);
//     }
// 
//     @Nullable
//     public abstract RETURN_TYPE getSuccessResult();
// 
//     @Nullable
//     public abstract Exception getFailureResult();
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/EndpointState.java
// public enum EndpointState {
//     BEFORE_CALL, DURING_CALL, CALL_SUCCESS, CALL_FAILED;
// 
//     public static FieldState toFieldState(EndpointState state) {
//         switch (state) {
//             case BEFORE_CALL:
//                 return FieldState.NOT_LOADED;
//             case DURING_CALL:
//                 return FieldState.CURRENTLY_LOADING;
//             case CALL_SUCCESS:
//                 return FieldState.LOADED;
//             case CALL_FAILED:
//                 return FieldState.NOT_LOADED;
//             default:
//                 throw new IllegalArgumentException("Unknown state: " + state);
//         }
//     }
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/EndpointStateListener.java
// public interface EndpointStateListener<RETURN_TYPE, ARG_TYPE> {
// 
//     void endpointStateChanged(StateAndValue<RETURN_TYPE, ARG_TYPE> currentStateAndValue);
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/StateAndValue.java
// @AutoValue
// public abstract class StateAndValue<VALUE_TYPE, ARG_TYPE> {
// 
//     public static <VALUE_TYPE, ARG_TYPE> StateAndValue<VALUE_TYPE, ARG_TYPE> create(@Nonnull EndpointState state,
//                                                                                     @Nonnull CallResult<VALUE_TYPE> value,
//                                                                                     @Nullable ARG_TYPE arg) {
//         return new AutoValue_StateAndValue<VALUE_TYPE, ARG_TYPE>(state, value, arg);
//     }
// 
//     @Nonnull
//     public abstract EndpointState getState();
// 
//     @Nonnull
//     public abstract CallResult<VALUE_TYPE> getValue();
// 
//     @Nullable
//     public abstract ARG_TYPE getArg();
// }


import com.byoutline.cachedfield.FieldState;
import com.byoutline.cachedfield.cachedendpoint.CallResult;
import com.byoutline.cachedfield.cachedendpoint.EndpointState;
import com.byoutline.cachedfield.cachedendpoint.EndpointStateListener;
import com.byoutline.cachedfield.cachedendpoint.StateAndValue;
import com.byoutline.eventcallback.internal.SessionChecker;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

    /**
     * Register listener that will be informed each time {@link FieldState}
     * changes.
     *
     * @param listener
     * @throws IllegalArgumentException if listener is null
     */
    public synchronized void addStateListener(@Nonnull EndpointStateListener<VALUE_TYPE, ARG_TYPE> listener) throws IllegalArgumentException {
        checkListenerNonNull(listener);
        fieldStateListeners.add(listener);
        if (informStateListenerOnAdd) {
            informStateListener(getStateAndValue(), listener);
        }
    }

    /**
     * Remove field state listener
     *
     * @param listener
     * @return true if listeners collection was modified by this operation,
     * false otherwise
     * @throws IllegalArgumentException if listener is null
     */
    public synchronized boolean removeStateListener(@Nonnull EndpointStateListener<VALUE_TYPE, ARG_TYPE> listener) throws IllegalArgumentException {
        checkListenerNonNull(listener);
        return fieldStateListeners.remove(listener);
    }

    private void checkListenerNonNull(EndpointStateListener listener) throws IllegalArgumentException {
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/FieldState.java
// public enum FieldState {
// 
//     NOT_LOADED, CURRENTLY_LOADING, LOADED
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/CallResult.java
// @AutoValue
// public abstract class CallResult<RETURN_TYPE> {
// 
//     public static <RETURN_TYPE> CallResult<RETURN_TYPE> create(@Nullable RETURN_TYPE successResult,
//                                                                @Nullable Exception failureResult) {
//         return new AutoValue_CallResult<RETURN_TYPE>(successResult, failureResult);
//     }
// 
//     @Nullable
//     public abstract RETURN_TYPE getSuccessResult();
// 
//     @Nullable
//     public abstract Exception getFailureResult();
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/EndpointState.java
// public enum EndpointState {
//     BEFORE_CALL, DURING_CALL, CALL_SUCCESS, CALL_FAILED;
// 
//     public static FieldState toFieldState(EndpointState state) {
//         switch (state) {
//             case BEFORE_CALL:
//                 return FieldState.NOT_LOADED;
//             case DURING_CALL:
//                 return FieldState.CURRENTLY_LOADING;
//             case CALL_SUCCESS:
//                 return FieldState.LOADED;
//             case CALL_FAILED:
//                 return FieldState.NOT_LOADED;
//             default:
//                 throw new IllegalArgumentException("Unknown state: " + state);
//         }
//     }
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/EndpointStateListener.java
// public interface EndpointStateListener<RETURN_TYPE, ARG_TYPE> {
// 
//     void endpointStateChanged(StateAndValue<RETURN_TYPE, ARG_TYPE> currentStateAndValue);
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/cachedendpoint/StateAndValue.java
// @AutoValue
// public abstract class StateAndValue<VALUE_TYPE, ARG_TYPE> {
// 
//     public static <VALUE_TYPE, ARG_TYPE> StateAndValue<VALUE_TYPE, ARG_TYPE> create(@Nonnull EndpointState state,
//                                                                                     @Nonnull CallResult<VALUE_TYPE> value,
//                                                                                     @Nullable ARG_TYPE arg) {
//         return new AutoValue_StateAndValue<VALUE_TYPE, ARG_TYPE>(state, value, arg);
//     }
// 
//     @Nonnull
//     public abstract EndpointState getState();
// 
//     @Nonnull
//     public abstract CallResult<VALUE_TYPE> getValue();
// 
//     @Nullable
//     public abstract ARG_TYPE getArg();
// }


// Path: cachedfield/src/main/java/com/byoutline/cachedfield/internal/CachedValue.java
import com.byoutline.cachedfield.FieldState;
import com.byoutline.cachedfield.cachedendpoint.CallResult;
import com.byoutline.cachedfield.cachedendpoint.EndpointState;
import com.byoutline.cachedfield.cachedendpoint.EndpointStateListener;
import com.byoutline.cachedfield.cachedendpoint.StateAndValue;
import com.byoutline.eventcallback.internal.SessionChecker;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;


    /**
     * Register listener that will be informed each time {@link FieldState}
     * changes.
     *
     * @param listener
     * @throws IllegalArgumentException if listener is null
     */
    public synchronized void addStateListener(@Nonnull EndpointStateListener<VALUE_TYPE, ARG_TYPE> listener) throws IllegalArgumentException {
        checkListenerNonNull(listener);
        fieldStateListeners.add(listener);
        if (informStateListenerOnAdd) {
            informStateListener(getStateAndValue(), listener);
        }
    }

    /**
     * Remove field state listener
     *
     * @param listener
     * @return true if listeners collection was modified by this operation,
     * false otherwise
     * @throws IllegalArgumentException if listener is null
     */
    public synchronized boolean removeStateListener(@Nonnull EndpointStateListener<VALUE_TYPE, ARG_TYPE> listener) throws IllegalArgumentException {
        checkListenerNonNull(listener);
        return fieldStateListeners.remove(listener);
    }

    private void checkListenerNonNull(EndpointStateListener listener) throws IllegalArgumentException {
        if (listener == null) {