// Path: sample-android/src/main/java/com/example/sample_android/Datastore.java
// public class Datastore {
// 
//     // poor-man's persistence
//     private SharedPreferences prefs;
// 
//     public Datastore(Context context) {
//         prefs = context.getSharedPreferences("datastore", Context.MODE_PRIVATE);
//     }
// 
//     public void store(List<TodoItem> items) {
//         StringBuilder data = new StringBuilder();
//         for (Iterator<TodoItem> iterator = items.iterator(); iterator.hasNext(); ) {
//             TodoItem item = iterator.next();
//             data.append(item.id()).append(":").append(item.text()).append(":").append(item.done());
//             if (iterator.hasNext()) {
//                 data.append(",");
//             }
//         }
//         prefs.edit()
//                 .putString("data", data.toString())
//                 .apply();
//     }
// 
//     public void get(final Callback callback) {
//         // Yeah you can get them pretty fast, but let's pretend it's slow.
//         new AsyncTask<Void, Void, List<TodoItem>>() {
//             @Override
//             protected List<TodoItem> doInBackground(Void... params) {
//                 try {
//                     Thread.sleep(1000);
//                 } catch (InterruptedException e) {
//                     return null;
//                 }
//                 String[] data = prefs.getString("data", "").split(",");
//                 List<TodoItem> items = new ArrayList<>(data.length);
//                 for (String s : data) {
//                     String[] fields = s.split(":");
//                     if (fields.length == 3) {
//                         int id = Integer.parseInt(fields[0]);
//                         String text = fields[1];
//                         boolean done = Boolean.parseBoolean(fields[2]);
//                         items.add(TodoItem.create(id, text, done));
//                     }
//                 }
//                 return items;
//             }
// 
//             @Override
//             protected void onPostExecute(List<TodoItem> todoItems) {
//                 callback.onList(todoItems);
//             }
//         }.execute();
//     }
// 
//     public interface Callback {
//         void onList(List<TodoItem> items);
//     }
// }
// 
// Path: sample-android/src/main/java/com/example/sample_android/state/TodoList.java
// @AutoValue
// public abstract class TodoList {
// 
//     public static TodoList initial() {
//         return new AutoValue_TodoList(true, Collections.<TodoItem>emptyList());
//     }
// 
//     public static TodoList create(boolean loading, List<TodoItem> items) {
//         return new AutoValue_TodoList(loading, Collections.unmodifiableList(items));
//     }
//     
//     public abstract boolean loading();
// 
//     public abstract List<TodoItem> items();
// }
// 
// Path: redux-core/src/main/java/me/tatarka/redux/Store.java
// public interface Store<S> {
// 
//     /**
//      * Returns the current state of the store.
//      */
//     S getState();
// 
//     /**
//      * Sets the state of the store. Warning! You should not call this in normal application code,
//      * instead preferring to update it through dispatching an action. It is however, useful for
//      * tests.
//      */
//     void setState(S state);
// }
// 
// Path: redux-core/src/main/java/me/tatarka/redux/middleware/Middleware.java
// public interface Middleware<A, R> {
// 
//     /**
//      * Called when an action is dispatched.
//      *
//      * @param next   Dispatch to the next middleware or actually update the state if there is none.
//      *               You can chose to call this anywhere to see the state before and after it has
//      *               changed or not at all to drop the action.
//      * @param action This action that was dispatched.
//      */
//     R dispatch(Next<A, R> next, A action);
// 
//     interface Next<A, R> {
//         R next(A action);
//     }
// }


import com.example.sample_android.Datastore;
import com.example.sample_android.state.TodoList;
import me.tatarka.redux.Store;
import me.tatarka.redux.middleware.Middleware;
package com.example.sample_android.middleware;



public class PersistenceMiddleware<A, R> implements Middleware<A, R> {

    private final Store<TodoList> store;
    private final Datastore datastore;

    public PersistenceMiddleware(Store<TodoList> store, Datastore datastore) {
        this.store = store;
        this.datastore = datastore;
    }

    @Override
    public R dispatch(Next<A, R> next, A action) {
// Path: sample-android/src/main/java/com/example/sample_android/Datastore.java
// public class Datastore {
// 
//     // poor-man's persistence
//     private SharedPreferences prefs;
// 
//     public Datastore(Context context) {
//         prefs = context.getSharedPreferences("datastore", Context.MODE_PRIVATE);
//     }
// 
//     public void store(List<TodoItem> items) {
//         StringBuilder data = new StringBuilder();
//         for (Iterator<TodoItem> iterator = items.iterator(); iterator.hasNext(); ) {
//             TodoItem item = iterator.next();
//             data.append(item.id()).append(":").append(item.text()).append(":").append(item.done());
//             if (iterator.hasNext()) {
//                 data.append(",");
//             }
//         }
//         prefs.edit()
//                 .putString("data", data.toString())
//                 .apply();
//     }
// 
//     public void get(final Callback callback) {
//         // Yeah you can get them pretty fast, but let's pretend it's slow.
//         new AsyncTask<Void, Void, List<TodoItem>>() {
//             @Override
//             protected List<TodoItem> doInBackground(Void... params) {
//                 try {
//                     Thread.sleep(1000);
//                 } catch (InterruptedException e) {
//                     return null;
//                 }
//                 String[] data = prefs.getString("data", "").split(",");
//                 List<TodoItem> items = new ArrayList<>(data.length);
//                 for (String s : data) {
//                     String[] fields = s.split(":");
//                     if (fields.length == 3) {
//                         int id = Integer.parseInt(fields[0]);
//                         String text = fields[1];
//                         boolean done = Boolean.parseBoolean(fields[2]);
//                         items.add(TodoItem.create(id, text, done));
//                     }
//                 }
//                 return items;
//             }
// 
//             @Override
//             protected void onPostExecute(List<TodoItem> todoItems) {
//                 callback.onList(todoItems);
//             }
//         }.execute();
//     }
// 
//     public interface Callback {
//         void onList(List<TodoItem> items);
//     }
// }
// 
// Path: sample-android/src/main/java/com/example/sample_android/state/TodoList.java
// @AutoValue
// public abstract class TodoList {
// 
//     public static TodoList initial() {
//         return new AutoValue_TodoList(true, Collections.<TodoItem>emptyList());
//     }
// 
//     public static TodoList create(boolean loading, List<TodoItem> items) {
//         return new AutoValue_TodoList(loading, Collections.unmodifiableList(items));
//     }
//     
//     public abstract boolean loading();
// 
//     public abstract List<TodoItem> items();
// }
// 
// Path: redux-core/src/main/java/me/tatarka/redux/Store.java
// public interface Store<S> {
// 
//     /**
//      * Returns the current state of the store.
//      */
//     S getState();
// 
//     /**
//      * Sets the state of the store. Warning! You should not call this in normal application code,
//      * instead preferring to update it through dispatching an action. It is however, useful for
//      * tests.
//      */
//     void setState(S state);
// }
// 
// Path: redux-core/src/main/java/me/tatarka/redux/middleware/Middleware.java
// public interface Middleware<A, R> {
// 
//     /**
//      * Called when an action is dispatched.
//      *
//      * @param next   Dispatch to the next middleware or actually update the state if there is none.
//      *               You can chose to call this anywhere to see the state before and after it has
//      *               changed or not at all to drop the action.
//      * @param action This action that was dispatched.
//      */
//     R dispatch(Next<A, R> next, A action);
// 
//     interface Next<A, R> {
//         R next(A action);
//     }
// }


// Path: sample-android/src/main/java/com/example/sample_android/middleware/PersistenceMiddleware.java
import com.example.sample_android.Datastore;
import com.example.sample_android.state.TodoList;
import me.tatarka.redux.Store;
import me.tatarka.redux.middleware.Middleware;

package com.example.sample_android.middleware;



public class PersistenceMiddleware<A, R> implements Middleware<A, R> {

    private final Store<TodoList> store;
    private final Datastore datastore;

    public PersistenceMiddleware(Store<TodoList> store, Datastore datastore) {
        this.store = store;
        this.datastore = datastore;
    }

    @Override
    public R dispatch(Next<A, R> next, A action) {
        R result = next.next(action);