/*
 * Copyright 2011 Google Inc.
 * Copyright 2014 Andreas Schildbach
 *
 * 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 org.bitcoinj.examples;

import org.bitcoinj.base.BitcoinNetwork;
import org.bitcoinj.base.Network;
import org.bitcoinj.base.Sha256Hash;
import org.bitcoinj.core.*;
import org.bitcoinj.net.discovery.DnsDiscovery;
import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.MemoryBlockStore;
import org.bitcoinj.utils.BriefLogFormatter;
import picocli.CommandLine;

import java.net.InetAddress;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * <p>Downloads the block given a block hash from the remote or localhost node and prints it out.</p>
 * <p>When downloading from localhost, run bitcoind locally: bitcoind -testnet -daemon.
 * After bitcoind is up and running, use command: org.bitcoinj.examples.FetchBlock --localhost &lt;blockHash&gt; </p>
 * <p>Otherwise, use command: org.bitcoinj.examples.FetchBlock &lt;blockHash&gt;, this command will download blocks from a peer generated by DNS seeds.</p>
 */
@CommandLine.Command(usageHelpAutoWidth = true, sortOptions = false)
public class FetchBlock implements Callable<Integer> {
    @CommandLine.Parameters(index = "0", description = "The hash of the block to download.")
    private String blockHashParam;
    @CommandLine.Option(names = "--localhost", description = "Connect to the localhost node. Default: ${DEFAULT-VALUE}")
    private boolean localhost = true;
    @CommandLine.Option(names = "--help", usageHelp = true, description = "Displays program options.")
    private boolean help;

    public static void main(String[] args) throws Exception {
        BriefLogFormatter.init();
        int exitCode = new CommandLine(new FetchBlock()).execute(args);
        System.exit(exitCode);
    }

    @Override
    public Integer call() throws Exception {
        // Connect to testnet and find a peer
        System.out.println("Connecting to node");
        final Network network = BitcoinNetwork.TESTNET;
        final NetworkParameters params = NetworkParameters.of(network);
        BlockStore blockStore = new MemoryBlockStore(params.getGenesisBlock());
        BlockChain chain = new BlockChain(params, blockStore);
        PeerGroup peerGroup = new PeerGroup(network, chain);
        if (localhost) {
            peerGroup.addPeerDiscovery(new DnsDiscovery(params));
        } else {
            PeerAddress addr = PeerAddress.localhost(params);
            peerGroup.addAddress(addr);
        }
        peerGroup.start();
        peerGroup.waitForPeers(1).get();
        Peer peer = peerGroup.getConnectedPeers().get(0);

        // Retrieve a block through a peer
        Sha256Hash blockHash = Sha256Hash.wrap(blockHashParam);
        Future<Block> future = peer.getBlock(blockHash);
        System.out.println("Waiting for node to send us the requested block: " + blockHash);
        Block block = future.get();
        System.out.println(block);
        peerGroup.stopAsync();

        return 0;
    }
}
