/*
 * Copyright 2017 Hannes Dorfmann.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.hannesdorfmann.mosby3.sample.mvi.view.shoppingcartoverview;

import com.hannesdorfmann.mosby3.mvi.MviBasePresenter;
import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.ShoppingCart;
import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.model.Product;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import timber.log.Timber;

/**
 * @author Hannes Dorfmann
 */
public class ShoppingCartOverviewPresenter
    extends MviBasePresenter<ShoppingCartOverviewView, List<ShoppingCartOverviewItem>> {

  private final ShoppingCart shoppingCart;
  private final Observable<Boolean> deleteSelectedItemsIntent;
  private final Observable<Boolean> clearSelectionIntent;
  private Disposable deleteDisposable;
  private Disposable deleteSelectedDisposable;

  public ShoppingCartOverviewPresenter(ShoppingCart shoppingCart,
      Observable<Boolean> deleteSelectedItemsIntent, Observable<Boolean> clearSelectionIntent) {
    this.shoppingCart = shoppingCart;
    this.deleteSelectedItemsIntent = deleteSelectedItemsIntent;
    this.clearSelectionIntent = clearSelectionIntent;
  }

  @Override protected void bindIntents() {

    //
    // Observable that emits a list of selected products over time (or empty list if the selection has been cleared)
    //
    Observable<List<Product>> selectedItemsIntent =
        intent(ShoppingCartOverviewView::selectItemsIntent)
            .mergeWith(clearSelectionIntent.map(ignore -> Collections.emptyList()))
            .doOnNext(items -> Timber.d("intent: selected items %d", items.size()))
            .startWith(new ArrayList<Product>(0));

    //
    // Delete multiple selected Items
    //

    deleteSelectedDisposable = selectedItemsIntent
        .switchMap(selectedItems -> deleteSelectedItemsIntent.filter(ignored -> !selectedItems.isEmpty())
            .doOnNext(ignored -> Timber.d("intent: remove %d selected items from shopping cart", selectedItems.size()))
            .flatMap(ignore -> shoppingCart.removeProducts(selectedItems).toObservable()))
        .subscribe();

    //
    // Delete a single item
    //
    deleteDisposable = intent(ShoppingCartOverviewView::removeItemIntent)
        .doOnNext(item -> Timber.d("intent: remove item from shopping cart: %s", item))
        .flatMap(productToDelete -> shoppingCart.removeProduct(productToDelete).toObservable())
        .subscribe();
    //
    // Display a list of items in the shopping cart
    //
    Observable<List<Product>> shoppingCartContentObservable =
        intent(ShoppingCartOverviewView::loadItemsIntent)
            .doOnNext(ignored -> Timber.d("load ShoppingCart intent"))
            .flatMap(ignored -> shoppingCart.itemsInShoppingCart());


    //
    // Display list of items / view state
    //
    List<Observable<?>> combiningObservables =
        Arrays.asList(shoppingCartContentObservable, selectedItemsIntent);

    Observable<List<ShoppingCartOverviewItem>> shoppingCartContentWithSelectedItems =
        Observable.combineLatest(combiningObservables, results -> {
          List<Product> itemsInShoppingCart = (List<Product>) results[0];
          List<Product> selectedProducts = (List<Product>) results[1];

          List<ShoppingCartOverviewItem> items = new ArrayList<>(itemsInShoppingCart.size());
          for (int i = 0; i < itemsInShoppingCart.size(); i++) {
            Product p = itemsInShoppingCart.get(i);
            items.add(new ShoppingCartOverviewItem(p, selectedProducts.contains(p)));
          }
          return items;
        })
        .observeOn(AndroidSchedulers.mainThread());

    subscribeViewState(shoppingCartContentWithSelectedItems, ShoppingCartOverviewView::render);
  }

  @Override protected void unbindIntents() {
    deleteDisposable.dispose();
    deleteSelectedDisposable.dispose();
  }


  @Override public Observable<List<ShoppingCartOverviewItem>> getViewStateObservable() {
    return super.getViewStateObservable();
  }
}

@@ -2380,16 +2380,63 @@
 uct%3E(0))
+%0A            .publish()%0A            .refCount()
 ;%0A%0A    /

fix mvi-sample crash (#324)