package com.nikita.recipiesapp.common;


import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.MutableLiveData;
import android.support.annotation.NonNull;

import com.nikita.recipiesapp.BuildConfig;
import com.nikita.recipiesapp.common.utils.Check;

public final class Store<State> {
  private final MutableLiveData<State> liveData = new MutableLiveData<>();
  private final Reducer<State> reducer;

  public Store(@NonNull Reducer<State> reducer, @NonNull State initialState) {
    this.reducer = reducer;
    liveData.setValue(initialState);
  }

  @NonNull
  public State getState() {
    State state = liveData.getValue();
    Check.notNull(state);
    return state;
  }

  public <Subscriber extends LifecycleOwner & Renderer<State>> void subscribe(final Subscriber subscriber) {
    if (BuildConfig.IS_UI_TESTING) return;

    liveData.observe(subscriber, state -> {
      Check.notNull(state);
      subscriber.render(state);
    });
  }

  public void dispatch(Action action) {
    if (BuildConfig.IS_UI_TESTING) return;

    State state = liveData.getValue();
    Check.notNull(state);

    liveData.setValue(reducer.reduce(state, action));
  }

  public static class ReducerCombiner<State> implements Reducer<State> {
    private final Reducer<State>[] reducers;

    public ReducerCombiner(Reducer<State>[] reducers) {
      this.reducers = reducers;
    }

    @NonNull
    @Override
    public State reduce(@NonNull State previousState, @NonNull Action action) {

      State state = previousState;
      for (Reducer<State> reducer : reducers) {
        state = reducer.reduce(state, action);
      }

      return state;
    }
  }
}

@@ -413,16 +413,65 @@
 reducer;
+%0A  private final Consumer%3CAction%3E actionConsumer;
 %0A%0A  publ
@@ -608,16 +608,323 @@
 State);%0A
+    this.actionConsumer = this.getStoreConsumer();%0A  %7D%0A%0A  public Store(@NonNull Reducer%3CState%3E reducer, @NonNull Middleware%3CState%3E%5B%5D middlewares, @NonNull State initialState) %7B%0A    this.reducer = reducer;%0A    liveData.setValue(initialState);%0A    this.actionConsumer = combineMiddlewares(this, middlewares);%0A
   %7D%0A%0A  @
@@ -1409,73 +1409,113 @@
     
-State state = liveData.getValue();%0A    Check.notNull(state);%0A%0A   
+actionConsumer.consume(action);%0A  %7D%0A%0A  private Consumer%3CAction%3E getStoreConsumer() %7B%0A    return action -%3E
  liv
@@ -1536,37 +1536,42 @@
 (reducer.reduce(
-s
+getS
 tate
+()
 , action));%0A  %7D%0A
@@ -2061,11 +2061,369 @@
    %7D%0A  %7D
+%0A%0A  private static %3CState%3E Consumer%3CAction%3E combineMiddlewares(Store%3CState%3E store, Middleware%3CState%3E%5B%5D middlewares) %7B%0A    Consumer%3CAction%3E currentConsumer = store.getStoreConsumer();%0A    for (Middleware%3CState%3E middleware : middlewares) %7B%0A      middleware.init(store, currentConsumer);%0A      currentConsumer = middleware;%0A    %7D%0A    return currentConsumer;%0A  %7D
 %0A%7D%0A

Implement middleware applying in store