package com.lucilu.rxdynamicsearch.ui.adapter;

import com.lucilu.rxdynamicsearch.dagger.Scopes.FragmentScope;
import com.lucilu.rxdynamicsearch.ui.adapter.base.IListItemComparator;
import com.lucilu.rxdynamicsearch.ui.adapter.base.IViewHolderBinder;
import com.lucilu.rxdynamicsearch.ui.adapter.base.IViewHolderFactory;
import com.lucilu.rxdynamicsearch.utils.Preconditions;
import com.lucilu.rxdynamicsearch.viewmodel.pojo.DisplayableItem;

import android.support.annotation.NonNull;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.ViewGroup;

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

import javax.inject.Inject;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Implementation of {@link android.support.v7.widget.RecyclerView.Adapter} for {@link
 * DisplayableItem}.
 */
@FragmentScope
public final class RecyclerViewAdapter extends Adapter {

    @NonNull
    private final List<DisplayableItem> mItems = new ArrayList<>();

    @NonNull
    private final IListItemComparator mComparator;

    @NonNull
    private final IViewHolderFactory mInstantiator;

    @NonNull
    private final IViewHolderBinder<DisplayableItem> mBinder;

    @Inject
    RecyclerViewAdapter(@NonNull final IListItemComparator comparator,
                        @NonNull final IViewHolderFactory instantiator,
                        @NonNull final IViewHolderBinder<DisplayableItem> binder) {
        mComparator = comparator;
        mInstantiator = instantiator;
        mBinder = binder;
    }

    @Override
    public ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
        return mInstantiator.createViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        mBinder.bind(holder, mItems.get(position));
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    @Override
    public int getItemViewType(final int position) {
        return mItems.get(position).type();
    }

    /**
     * Updates mItems currently stored in adapter with the new mItems.
     *
     * @param items collection to update the previous values
     */
    public void update(@NonNull final List<DisplayableItem> items) {
        Observable.fromCallable(() -> calculateDiff(items))
                  .subscribeOn(Schedulers.computation())
                  .observeOn(AndroidSchedulers.mainThread())
                  .doOnCompleted(() -> updateItems(items))
                  .subscribe(this::updateAdapterWithDiffResult);
    }

    private void updateItems(@NonNull final List<DisplayableItem> items) {
        Preconditions.assertUiThread();

        mItems.clear();
        mItems.addAll(items);
    }

    private void updateAdapterWithDiffResult(@NonNull final DiffUtil.DiffResult result) {
        Preconditions.assertUiThread();

        result.dispatchUpdatesTo(this);
    }

    private DiffUtil.DiffResult calculateDiff(@NonNull final List<DisplayableItem> newItems) {
        Preconditions.assertWorkerThread();

        return DiffUtil.calculateDiff(new DiffUtilCallback(mItems, newItems, mComparator));
    }
}

@@ -715,16 +715,93 @@
 il.List;
+%0Aimport java.util.concurrent.Executor;%0Aimport java.util.concurrent.Executors;
 %0A%0Aimport
@@ -1401,24 +1401,95 @@
 %3E mBinder;%0A%0A
+    private Executor mExecutor = Executors.newSingleThreadExecutor();%0A%0A
     @Inject%0A
@@ -2623,32 +2623,86 @@
 ateDiff(items))%0A
+                  .doOnNext(__ -%3E updateItems(items))%0A
                 
@@ -2731,20 +2731,22 @@
 ers.
-computation(
+from(mExecutor
 ))%0A 
@@ -2809,67 +2809,8 @@
 ())%0A
-                  .doOnCompleted(() -%3E updateItems(items))%0A
     
@@ -2869,32 +2869,271 @@
 Result);%0A    %7D%0A%0A
+    private DiffUtil.DiffResult calculateDiff(@NonNull final List%3CDisplayableItem%3E newItems) %7B%0A        Preconditions.assertWorkerThread();%0A%0A        return DiffUtil.calculateDiff(new DiffUtilCallback(mItems, newItems, mComparator));%0A    %7D%0A%0A
     private void
@@ -3211,34 +3211,38 @@
 onditions.assert
-Ui
+Worker
 Thread();%0A%0A     
@@ -3420,32 +3420,32 @@
 ertUiThread();%0A%0A
+
         result.d
@@ -3477,246 +3477,7 @@
    %7D
-%0A%0A    private DiffUtil.DiffResult calculateDiff(@NonNull final List%3CDisplayableItem%3E newItems) %7B%0A        Preconditions.assertWorkerThread();%0A%0A        return DiffUtil.calculateDiff(new DiffUtilCallback(mItems, newItems, mComparator));%0A    %7D
 %0A%7D%0A

Use single thread