package info.izumin.android.droidux;

import android.databinding.BaseObservable;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import rx.Observable;
import rx.subjects.BehaviorSubject;

/**
 * Created by izumin on 11/2/15.
 */
public abstract class Store<T> extends BaseObservable {
    public static final String TAG = Store.class.getSimpleName();

    private final BehaviorSubject<T> subject;
    private final List<Middleware> middlewares;
    private T state;

    private Store(Builder builder) {
        subject = BehaviorSubject.create();
        middlewares = builder.middlewares;
        for (Middleware middleware : builder.middlewares) { middleware.onAttach(this); }
    }

    public Observable<T> observe() {
        return subject;
    }

    public T getState() {
        return state;
    }

    public Observable<Action> dispatch(Action action) {
        Observable<Action> o = Observable.just(action);
        ListIterator<Middleware> iterator = getMiddlewares().listIterator();
        while (iterator.hasNext()) {
            Middleware mw = iterator.next();
            o = o.map(mw::beforeDispatch);
        }

        o = o.flatMap(a -> a.call(this));
        o = o.doOnNext(this::dispatchToReducers);

        while (iterator.hasPrevious()) {
            Middleware mw = iterator.previous();
            o = o.map(mw::afterDispatch);
        }
        return o;
    }

    protected void setState(T state) {
        this.state = state;
        notifyChange();
        subject.onNext(state);
    }

    protected List<Middleware> getMiddlewares() {
        return middlewares;
    }

    protected abstract void dispatchToReducers(Action action);

    public static abstract class Builder {
        private final List<Middleware> middlewares;

        public Builder() {
            middlewares = new ArrayList<>();
        }

        public Builder apply(Middleware middleware) {
            middlewares.add(middleware);
            return this;
        }

        public abstract Store build();
    }
}

@@ -73,16 +73,53 @@
 ervable;
+%0Aimport android.databinding.Bindable;
 %0A%0Aimport
@@ -508,24 +508,57 @@
 iddlewares;%0A
+    private final List reducers;%0A
     private 
@@ -573,21 +573,23 @@
 %0A%0A    pr
-ivate
+otected
  Store(B
@@ -689,24 +689,101 @@
 iddlewares;%0A
+        reducers = new ArrayList%3C%3E();%0A        reducers.add(builder.reducer);%0A
         for 
@@ -926,32 +926,46 @@
 subject;%0A    %7D%0A%0A
+    @Bindable%0A
     public T get
@@ -1123,16 +1123,22 @@
         
+final 
 ListIter
@@ -1239,32 +1239,38 @@
 ) %7B%0A            
+final 
 Middleware mw = 
@@ -1485,16 +1485,21 @@
         
+final
  Middlew
@@ -1726,32 +1726,99 @@
 (state);%0A    %7D%0A%0A
+    protected List getReducers() %7B%0A        return reducers;%0A    %7D%0A%0A
     protected Li
@@ -1993,16 +1993,54 @@
 ilder %7B%0A
+        private final Object reducer;%0A
         
@@ -2107,16 +2107,30 @@
 Builder(
+Object reducer
 ) %7B%0A    
@@ -2129,32 +2129,73 @@
 ) %7B%0A            
+this.reducer = reducer;%0A            this.
 middlewares = ne
@@ -2280,32 +2280,37 @@
 ) %7B%0A            
+this.
 middlewares.add(

Add Store#getReducer() and minor refactorings