package org.andork.redux;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Redux {
/**
* Wraps a store to pass {@linkplain Store#dispatch(Action) dispatched}
* {@link Action}s through a chain of {@link Middleware}s that can perform
* side effects like logging, debugging, and even dispatching other actions,
* before the state is updated via the {@link Reducer}.
*
* @param middleware
* a {@link List} of {@link Middleware} to apply.
* @param store
* the {@link Store} to wrap.
* @return a {@link Store} whose {@link Store#dispatch(Action) dispatch}
* method calls the applied middleware.
*/
public static <S> Store<S> applyMiddleware(List<Middleware> middleware, Store<S> store) {
Dispatcher dispatcher = store;
for (ListIterator<Middleware> i = middleware.listIterator(middleware.size()); i.hasPrevious();) {
dispatcher = i.previous().store(store).next(dispatcher);
}
final Dispatcher finalDispatcher = dispatcher;
return new Store<S>() {
@Override
public Object dispatch(Action action) {
try {
return finalDispatcher.dispatch(action);
} catch (Exception e) {
e.printStackTrace();
return store.getState();
}
}
@Override
public S getState() {
return store.getState();
}
@Override
public Runnable subscribe(Runnable callback) {
return store.subscribe(callback);
}
};
}
/**
* Creates a {@link Store}.
*
* @param reducer
* the {@link Reducer} to compute state updates for dispatched
* {@link Action}s.
* @param initialState
* the initial state for the store.
* @return a {@link Store} implementation.
*/
public static <S> Store<S> createStore(Reducer<S> reducer, S initialState) {
return new Store<S>() {
S state = initialState;
final List<Runnable> listeners = new ArrayList<>();
@Override
public Object dispatch(Action action) {
try {
S nextState = reducer.apply(state, action);
if (nextState != state) {
state = nextState;
for (Runnable r : listeners) {
r.run();
}
}
return nextState;
} catch (Exception e) {
e.printStackTrace();
return getState();
}
}
@Override
public S getState() {
return state;
}
@Override
public Runnable subscribe(Runnable callback) {
listeners.add(callback);
return () -> listeners.remove(callback);
}
};
}
}