/*
 * 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.app.bootstrap;

import io.bitsquare.network.Node;

import net.tomp2p.connection.ChannelClientConfiguration;
import net.tomp2p.connection.ChannelServerConfiguration;
import net.tomp2p.dht.PeerBuilderDHT;
import net.tomp2p.nat.PeerBuilderNAT;
import net.tomp2p.p2p.Peer;
import net.tomp2p.p2p.PeerBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMapChangeListener;
import net.tomp2p.peers.PeerStatistic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.util.concurrent.DefaultEventExecutorGroup;
import org.springframework.core.env.Environment;

public class BootstrapNode {
    private static final Logger log = LoggerFactory.getLogger(BootstrapNode.class);

    private static Peer peer = null;
    private static boolean running = true;

    private final Environment env;

    public BootstrapNode(Environment env) {
        this.env = env;
    }

    public void start() {
        String name = env.getRequiredProperty(Node.NAME_KEY);
        int port = env.getProperty(Node.PORT_KEY, Integer.class, Node.DEFAULT_PORT);

        try {
            Number160 peerId = Number160.createHash(name);

            DefaultEventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(250);
            ChannelClientConfiguration clientConf = PeerBuilder.createDefaultChannelClientConfiguration();
            clientConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup));

            ChannelServerConfiguration serverConf = PeerBuilder.createDefaultChannelServerConfiguration();
            serverConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup));
            serverConf.connectionTimeoutTCPMillis(5000);

            peer = new PeerBuilder(peerId)
                    .ports(port)
                    .channelClientConfiguration(clientConf)
                    .channelServerConfiguration(serverConf)
                    .start();
            
            /*peer.objectDataReply((sender, request) -> {
                log.trace("received request: " + request.toString());
                return "pong";
            });*/

            new PeerBuilderDHT(peer).start();
            new PeerBuilderNAT(peer).start();

            peer.peerBean().peerMap().addPeerMapChangeListener(new PeerMapChangeListener() {
                @Override
                public void peerInserted(PeerAddress peerAddress, boolean verified) {
                    log.debug("Peer inserted: peerAddress=" + peerAddress + ", verified=" + verified);
                }

                @Override
                public void peerRemoved(PeerAddress peerAddress, PeerStatistic peerStatistics) {
                    log.debug("Peer removed: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics);
                }

                @Override
                public void peerUpdated(PeerAddress peerAddress, PeerStatistic peerStatistics) {
                    // log.debug("Peer updated: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics);
                }
            });

            log.info("Bootstrap node started with name " + name + " and port " + port);
            new Thread(() -> {
                while (running) {
                    log.info("List of all peers online ----------------------------");
                    for (PeerAddress peerAddress : peer.peerBean().peerMap().all()) {
                        log.info(peerAddress.toString());
                    }
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        return;
                    }
                }
            }).start();

        } catch (Exception e) {
            if (peer != null)
                peer.shutdown().awaitUninterruptibly();
        }
    }
}

@@ -1575,16 +1575,56 @@
 ent env;
+%0A    private boolean noPeersInfoPrinted;
 %0A%0A    pu
@@ -4055,75 +4055,218 @@
     
-log.info(%22List of all peers online ----------------------------%22);%0A
+if (peer.peerBean().peerMap().all().size() %3E 0) %7B%0A                        noPeersInfoPrinted = false;%0A                        log.info(%22Number of peers online = %22 + peer.peerBean().peerMap().all().size());%0A    
     
@@ -4363,32 +4363,36 @@
                 
+    
 log.info(peerAdd
@@ -4384,16 +4384,27 @@
 og.info(
+%22Peer: %22 + 
 peerAddr
@@ -4432,34 +4432,42 @@
                 
-%7D%0A
+    %7D%0A    
                 
@@ -4468,32 +4468,36 @@
           try %7B%0A
+    
                 
@@ -4537,32 +4537,36 @@
                 
+    
 %7D catch (Interru
@@ -4612,16 +4612,20 @@
     
+    
 return;%0A
     
@@ -4620,16 +4620,219 @@
 return;%0A
+                        %7D%0A                    %7D%0A                    else if (noPeersInfoPrinted) %7B%0A                        log.info(%22No peers online%22);%0A                        noPeersInfoPrinted = true;%0A
         

Improve logging