<commit_before>/*
 * This file is part of Bisq.
 *
 * Bisq 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.
 *
 * Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
 */

package bisq.core.trade.txproof.xmr;

import bisq.core.btc.setup.WalletsSetup;
import bisq.core.filter.FilterManager;
import bisq.core.locale.Res;
import bisq.core.support.dispute.mediation.MediationManager;
import bisq.core.support.dispute.refund.RefundManager;
import bisq.core.trade.SellerTrade;
import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager;
import bisq.core.trade.closed.ClosedTradableManager;
import bisq.core.trade.failed.FailedTradesManager;
import bisq.core.trade.txproof.AssetTxProofHttpClient;
import bisq.core.trade.txproof.AssetTxProofResult;
import bisq.core.trade.txproof.AssetTxProofService;
import bisq.core.user.AutoConfirmSettings;
import bisq.core.user.Preferences;

import bisq.network.p2p.BootstrapListener;
import bisq.network.p2p.P2PService;

import bisq.common.app.DevEnv;

import javax.inject.Inject;
import javax.inject.Singleton;

import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.monadic.MonadicBinding;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;

import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import lombok.extern.slf4j.Slf4j;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Entry point for clients to request tx proof and trigger auto-confirm if all conditions
 * are met.
 */
@Slf4j
@Singleton
public class XmrTxProofService implements AssetTxProofService {
    private final FilterManager filterManager;
    private final Preferences preferences;
    private final TradeManager tradeManager;
    private final ClosedTradableManager closedTradableManager;
    private final FailedTradesManager failedTradesManager;
    private final MediationManager mediationManager;
    private final RefundManager refundManager;
    private final P2PService p2PService;
    private final WalletsSetup walletsSetup;
    private final AssetTxProofHttpClient httpClient;
    private final Map<String, XmrTxProofRequestsPerTrade> servicesByTradeId = new HashMap<>();
    private AutoConfirmSettings autoConfirmSettings;
    private Map<String, ChangeListener<Trade.State>> tradeStateListenerMap = new HashMap<>();
    private ChangeListener<Number> btcPeersListener, btcBlockListener;
    private BootstrapListener bootstrapListener;


    ///////////////////////////////////////////////////////////////////////////////////////////
    // Constructor
    ///////////////////////////////////////////////////////////////////////////////////////////

    @SuppressWarnings("WeakerAccess")
    @Inject
    public XmrTxProofService(FilterManager filterManager,
                             Preferences preferences,
                             TradeManager tradeManager,
                             ClosedTradableManager closedTradableManager,
                             FailedTradesManager failedTradesManager,
                             MediationManager mediationManager,
                             RefundManager refundManager,
                             P2PService p2PService,
                             WalletsSetup walletsSetup,
                             AssetTxProofHttpClient httpClient) {
        this.filterManager = filterManager;
        this.preferences = preferences;
        this.tradeManager = tradeManager;
        this.closedTradableManager = closedTradableManager;
        this.failedTradesManager = failedTradesManager;
        this.mediationManager = mediationManager;
        this.refundManager = refundManager;
        this.p2PService = p2PService;
        this.walletsSetup = walletsSetup;
        this.httpClient = httpClient;
    }


    ///////////////////////////////////////////////////////////////////////////////////////////
    // API
    ///////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public void onAllServicesInitialized() {
        // As we might trigger the payout tx we want to be sure that we are well connected to the Bitcoin network.
        // onAllServicesInitialized is called once we have received the initial data but we want to have our
        // hidden service published and upDatedDataResponse received before we start.
        MonadicBinding<Boolean> p2pNetworkAndWalletReady = EasyBind.combine(isP2pBootstrapped(), hasSufficientBtcPeers(), isBtcBlockDownloadComplete(),
                (isP2pBootstrapped, hasSufficientBtcPeers, isBtcBlockDownloadComplete) -> {
                    log.info("isP2pBootstrapped={}, hasSufficientBtcPeers={} isBtcBlockDownloadComplete={}",
                            isP2pBootstrapped, hasSufficientBtcPeers, isBtcBlockDownloadComplete);
                    return isP2pBootstrapped && hasSufficientBtcPeers && isBtcBlockDownloadComplete;
                });

        p2pNetworkAndWalletReady.subscribe((observable, oldValue, newValue) -> {
            if (newValue) {
                onP2pNetworkAndWalletReady();
            }
        });
    }

    @Override
    public void shutDown() {
        servicesByTradeId.values().forEach(XmrTxProofRequestsPerTrade::terminate);
        servicesByTradeId.clear();
    }


    ///////////////////////////////////////////////////////////////////////////////////////////
    // Private<commit_msg>Improve handling of p2pNetworkAndWalletReady<commit_after>/*
 * This file is part of Bisq.
 *
 * Bisq 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.
 *
 * Bisq 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 Bisq. If not, see <http://www.gnu.org/licenses/>.
 */

package bisq.core.trade.txproof.xmr;

import bisq.core.btc.setup.WalletsSetup;
import bisq.core.filter.FilterManager;
import bisq.core.locale.Res;
import bisq.core.support.dispute.mediation.MediationManager;
import bisq.core.support.dispute.refund.RefundManager;
import bisq.core.trade.SellerTrade;
import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager;
import bisq.core.trade.closed.ClosedTradableManager;
import bisq.core.trade.failed.FailedTradesManager;
import bisq.core.trade.txproof.AssetTxProofHttpClient;
import bisq.core.trade.txproof.AssetTxProofResult;
import bisq.core.trade.txproof.AssetTxProofService;
import bisq.core.user.AutoConfirmSettings;
import bisq.core.user.Preferences;

import bisq.network.p2p.BootstrapListener;
import bisq.network.p2p.P2PService;

import bisq.common.app.DevEnv;

import javax.inject.Inject;
import javax.inject.Singleton;

import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.monadic.MonadicBinding;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;

import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import lombok.extern.slf4j.Slf4j;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Entry point for clients to request tx proof and trigger auto-confirm if all conditions
 * are met.
 */
@Slf4j
@Singleton
public class XmrTxProofService implements AssetTxProofService {
    private final FilterManager filterManager;
    private final Preferences preferences;
    private final TradeManager tradeManager;
    private final ClosedTradableManager closedTradableManager;
    private final FailedTradesManager failedTradesManager;
    private final MediationManager mediationManager;
    private final RefundManager refundManager;
    private final P2PService p2PService;
    private final WalletsSetup walletsSetup;
    private final AssetTxProofHttpClient httpClient;
    private final Map<String, XmrTxProofRequestsPerTrade> servicesByTradeId = new HashMap<>();
    private AutoConfirmSettings autoConfirmSettings;
    private Map<String, ChangeListener<Trade.State>> tradeStateListenerMap = new HashMap<>();
    private ChangeListener<Number> btcPeersListener, btcBlockListener;
    private BootstrapListener bootstrapListener;
    private MonadicBinding<Boolean> p2pNetworkAndWalletReady;
    private ChangeListener<Boolean> p2pNetworkAndWalletReadyListener;


    ///////////////////////////////////////////////////////////////////////////////////////////
    // Constructor
    ///////////////////////////////////////////////////////////////////////////////////////////

    @SuppressWarnings("WeakerAccess")
    @Inject
    public XmrTxProofService(FilterManager filterManager,
                             Preferences preferences,
                             TradeManager tradeManager,
                             ClosedTradableManager closedTradableManager,
                             FailedTradesManager failedTradesManager,
                             MediationManager mediationManager,
                             RefundManager refundManager,
                             P2PService p2PService,
                             WalletsSetup walletsSetup,
                             AssetTxProofHttpClient httpClient) {
        this.filterManager = filterManager;
        this.preferences = preferences;
        this.tradeManager = tradeManager;
        this.closedTradableManager = closedTradableManager;
        this.failedTradesManager = failedTradesManager;
        this.mediationManager = mediationManager;
        this.refundManager = refundManager;
        this.p2PService = p2PService;
        this.walletsSetup = walletsSetup;
        this.httpClient = httpClient;
    }


    ///////////////////////////////////////////////////////////////////////////////////////////
    // API
    ///////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public void onAllServicesInitialized() {
        // As we might trigger the payout tx we want to be sure that we are well connected to the Bitcoin network.
        // onAllServicesInitialized is called once we have received the initial data but we want to have our
        // hidden service published and upDatedDataResponse received before we start.
        BooleanProperty isP2pBootstrapped = isP2pBootstrapped();
        BooleanProperty hasSufficientBtcPeers = hasSufficientBtcPeers();
        BooleanProperty isBtcBlockDownloadComplete = isBtcBlockDownloadComplete();
        if (isP2pBootstrapped.get() && hasSufficientBtcPeers.get() && isBtcBlockDownloadComplete.get()) {
            onP2pNetworkAndWalletReady();
        } else {
            p2pNetworkAndWalletReady = EasyBind.combine(isP2pBootstrapped, hasSufficientBtcPeers, isBtcBlockDownloadComplete,
                    (bootstrapped, sufficientPeers, downloadComplete) -> {
                        log.info("isP2pBootstrapped={}, hasSufficientBtcPeers={} isBtcBlockDownloadComplete={}",
                                bootstrapped, sufficientPeers, downloadComplete);
                        return bootstrapped && sufficientPeers && downloadComplete;
                    });

            p2pNetworkAndWalletReadyListener = (observable, oldValue, newValue) -> {
                if (newValue) {
                    onP2pNetworkAndWalletReady();
                }
            };
            p2pNetworkAndWalletReady.subscribe(p2pNetworkAndWalletReadyListener);
        }
    }

    @Override
    public void shutDown() {
        if (p2pNetworkAndWalletReady != null) {
            p2pNetworkAndWalletReady.removeListener(p2pNetworkAndWalletReadyListener);
        }

        servicesByTradeId.values().forEach(XmrTxProofRequestsPerTrade::terminate);
        servicesByTradeId.clear();
    }


    ///////////////////////////////////////////////////////////////////////////////////////////
    // Private
{'fraction_non_alphanumeric': 0.13382727483213708, 'fraction_numerical': 0.003936096318592266, 'mean_word_length': 2.448110697179351, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 13, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '259174', 'n_tokens_mistral': 3286, 'n_tokens_neox': 3217, 'n_words': 802}