package hsr.dsa.network;

import java.io.IOException;
import java.net.InetAddress;
import java.util.Random;

import net.tomp2p.dht.PeerBuilderDHT;
import net.tomp2p.dht.PeerDHT;
import net.tomp2p.futures.FutureBootstrap;
import net.tomp2p.futures.FutureDiscover;
import net.tomp2p.p2p.PeerBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMap;
import net.tomp2p.peers.PeerMapConfiguration;
import net.tomp2p.replication.IndirectReplication;

public class NetworkClient extends Node {
	private final InetAddress rootNode;
	private final short rootPort;
	

	/**
	 * Constructor intended for non root nodes without direct Internet access (Firewall / NAT).
	 * @param port
	 * @param rootNode
	 * @param rootPort
	 * @throws IOException
	 */
	public NetworkClient(short port, InetAddress rootNode, short rootPort) throws IOException {
		super(port);
		this.rootNode = rootNode;
		this.rootPort = rootPort;

		this.initPeer();
	}

	

	private void initPeer() throws IOException {
		Number160 peerId = new Number160(new Random());
		PeerMapConfiguration pmc = new PeerMapConfiguration(peerId);
		pmc.peerNoVerification();
		PeerMap pm = new PeerMap(pmc);
		PeerDHT peer = new PeerBuilderDHT(new PeerBuilder(peerId).ports(this.getPort()).peerMap(pm).start()).start();
		this.setPeer(peer);

		PeerAddress bootStrapServer = new PeerAddress(Number160.ZERO, rootNode, rootPort, rootPort);
		FutureDiscover fd = peer.peer().discover().peerAddress(bootStrapServer).start();

		fd.awaitUninterruptibly();
		if (fd.isSuccess()) {
			System.out.println("*** FOUND THAT MY OUTSIDE ADDRESS IS " + fd.peerAddress());
		} else {
			System.out.println("*** FAILED " + fd.failedReason());  // TODO throw exception
		}

		bootStrapServer = fd.reporter();
		FutureBootstrap bootstrap = peer.peer().bootstrap().peerAddress(bootStrapServer).start();
		bootstrap.awaitUninterruptibly();
		if (!bootstrap.isSuccess()) {
			System.out.println("*** COULD NOT BOOTSTRAP!"); // TODO throw exception
		}
		
		new IndirectReplication(this.getPeer()).start();
	}

	protected void reset() throws IOException {
		System.out.println("going to reset");
		this.getPeer().peer().announceShutdown().start().awaitListenersUninterruptibly();
		this.getPeer().peer().shutdown().awaitListenersUninterruptibly();
		
		this.initPeer();
	}
}
