/*
 * This file is part of Bitsquare.
 *
 * Bitsquare is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 *
 * Bitsquare is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
 */

package io.bitsquare.gui.main.market.spread;

import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.MarketPrice;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.gui.common.model.ActivatableViewModel;
import io.bitsquare.gui.main.offer.offerbook.OfferBook;
import io.bitsquare.gui.main.offer.offerbook.OfferBookListItem;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.trade.offer.Offer;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

class SpreadViewModel extends ActivatableViewModel {

    private final OfferBook offerBook;
    private PriceFeedService priceFeedService;
    private BSFormatter formatter;
    private final ObservableList<OfferBookListItem> offerBookListItems;
    private final ListChangeListener<OfferBookListItem> listChangeListener;
    final ObservableList<SpreadItem> spreadItems = FXCollections.observableArrayList();


    ///////////////////////////////////////////////////////////////////////////////////////////
    // Constructor, lifecycle
    ///////////////////////////////////////////////////////////////////////////////////////////

    @Inject
    public SpreadViewModel(OfferBook offerBook, PriceFeedService priceFeedService, BSFormatter formatter) {
        this.offerBook = offerBook;
        this.priceFeedService = priceFeedService;
        this.formatter = formatter;

        offerBookListItems = offerBook.getOfferBookListItems();
        listChangeListener = c -> update(offerBookListItems);
    }

    @Override
    protected void activate() {
        offerBookListItems.addListener(listChangeListener);
        offerBook.fillOfferBookListItems();
        update(offerBookListItems);
    }

    @Override
    protected void deactivate() {
        offerBookListItems.removeListener(listChangeListener);
    }

    private void update(ObservableList<OfferBookListItem> offerBookListItems) {
        Map<String, List<Offer>> offersByCurrencyMap = new HashMap<>();
        for (OfferBookListItem offerBookListItem : offerBookListItems) {
            Offer offer = offerBookListItem.getOffer();
            String currencyCode = offer.getCurrencyCode();
            if (!offersByCurrencyMap.containsKey(currencyCode))
                offersByCurrencyMap.put(currencyCode, new ArrayList<>());
            offersByCurrencyMap.get(currencyCode).add(offer);
        }
        spreadItems.clear();
        for (String currencyCode : offersByCurrencyMap.keySet()) {
            List<Offer> offers = offersByCurrencyMap.get(currencyCode);
            List<Offer> buyOffers = offers
                    .stream()
                    .filter(e -> e.getDirection().equals(Offer.Direction.BUY))
                    .sorted((o1, o2) -> {
                        long a = o1.getPrice() != null ? o1.getPrice().value : 0;
                        long b = o2.getPrice() != null ? o2.getPrice().value : 0;
                        if (a != b)
                            return a < b ? 1 : -1;
                        return 0;
                    })
                    .collect(Collectors.toList());

            List<Offer> sellOffers = offers
                    .stream()
                    .filter(e -> e.getDirection().equals(Offer.Direction.SELL))
                    .sorted((o1, o2) -> {
                        long a = o1.getPrice() != null ? o1.getPrice().value : 0;
                        long b = o2.getPrice() != null ? o2.getPrice().value : 0;
                        if (a != b)
                            return a > b ? 1 : -1;
                        return 0;
                    })
                    .collect(Collectors.toList());

            Fiat spread = null;
            Fiat bestSellOfferPrice = sellOffers.isEmpty() ? null : sellOffers.get(0).getPrice();
            Fiat bestBuyOfferPrice = buyOffers.isEmpty() ? null : buyOffers.get(0).getPrice();
            if (bestBuyOfferPrice != null && bestSellOfferPrice != null)
                spread = bestSellOfferPrice.subtract(bestBuyOfferPrice);

            String percentage = "";
            MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);
            if (spread != null && marketPrice != null) {
                double marketPriceAsDouble = marketPrice.getPrice(PriceFeedService.Type.LAST);
                double result = ((double) spread.value / 10000) / marketPriceAsDouble;
                percentage = " (" + formatter.formatPercentagePrice(result) + ")";
            }

            Coin totalAmount = Coin.valueOf(offers.stream().mapToLong(offer -> offer.getAmount().getValue()).sum());
            spreadItems.add(new SpreadItem(currencyCode, buyOffers.size(), sellOffers.size(), offers.size(), spread, percentage, totalAmount));
        }
    }
}

@@ -1090,24 +1090,65 @@
 SFormatter;%0A
+import io.bitsquare.locale.CurrencyUtil;%0A
 import io.bi
@@ -4686,16 +4686,52 @@
 = null;%0A
+            String percentage = %22%22;%0A
         
@@ -4991,119 +4991,15 @@
 ull)
+ %7B
 %0A    
-            spread = bestSellOfferPrice.subtract(bestBuyOfferPrice);%0A%0A            String percentage = %22%22;%0A
     
@@ -5071,32 +5071,109 @@
 (currencyCode);%0A
+                spread = bestSellOfferPrice.subtract(bestBuyOfferPrice);%0A    
             if (
@@ -5205,32 +5205,36 @@
 rice != null) %7B%0A
+    
                 
@@ -5312,16 +5312,93 @@
 .LAST);%0A
+                    if (CurrencyUtil.isFiatCurrency(currencyCode)) %7B%0A        
         
@@ -5451,16 +5451,17 @@
  / 10000
+D
 ) / mark
@@ -5493,16 +5493,24 @@
         
+   
+     
 percenta
@@ -5568,16 +5568,355 @@
  + %22)%22;%0A
+                    %7D else %7B%0A                        final double spreadAsDouble = spread.value != 0 ? 10000D / spread.value : 0;%0A                        double result = marketPriceAsDouble / spreadAsDouble;%0A                        percentage = %22 (%22 + formatter.formatPercentagePrice(result) + %22)%22;%0A                    %7D%0A                %7D%0A
         

Fix wrong spread calculation for altcoins