/*
 * The MIT License
 *
 * Copyright 2017 7u83 <7u83@mail.ru>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package btcsim;

import java.util.ArrayList;

import btcsim.Block.BlockType;

/**
 * Node class
 *
 * @author 7u83 <7u83@mail.ru>
 */
public class Node {

    BlockChain chain;
    Block distrib;
    protected int id;
    protected Net net;
    String name = null;

    int rejected = 0;

    public Node() {
        chain = new BlockChain();
        distrib = null;
    }

    public Node(String name) {
        this();
        setName(name);
    }

    public final void setNetAndId(Net net, int id) {
        this.net = net;
        this.id = id;
    }

    /**
     * Set the name of the node
     *
     * @param name name to set
     */
    public final void setName(String name) {
        this.name = name;
    }

 
    /**
     * Verfiy a block Override this method to implement own verfifying such as
     * UASF
     *
     * @param block
     * @return true: accept the block, false: reject block
     */
    boolean checkBlock(Block block) {
        return true;
    }

    /**
     * Receive a (mined) block, frowarded from another node
     *
     * @param block the block sent to this node
     */
    public void receiveBlock(Block block) {

        if (!checkBlock(block)) {
            rejected++;
            return;
        }

        if (chain.getBlock(block.hash) != null) {
            return;
        }

        if (chain.addBlock(block)) {
            distrib = block;
        }

    }
    
    /**
     * Check if a block is in nodes data base
     * @param hash Hash of block
     * @return true if block is in database, false if not.
     */
    public boolean hasBlock(int hash){
        Block b = chain.getBlock(hash);
        return b!=null;
    }

    /**
     * Distribute a block to other nodes, to which this node is connected to.
     *
     * The block to distribute is taken from {@link this.distrib} If
     * this.distrib
     *
     * @return
     */
    boolean distributeBlock() {
        if (distrib == null) {
            return false;
        }
        for (Node node : connections) {
            node.receiveBlock(distrib);
        }
        distrib = null;
        return true;
    }

    Block mineBlock() {
        Block b = net.mineBlock(BlockType.Std, chain.front_block);
//        receiveBlock(b);
        return b;
    }

    // We store "connections" to other nodes here
    private ArrayList<Node> connections;

    /**
     * Connect this node to other nodes
     *
     * @param n Number of connectoins to create
     */
    public void connect(int n) {
        connections = new ArrayList();
        for (int i = 0; i < n; i++) {
            int cid = net.random.nextInt(net.nodes.size());
            if (cid == id) {
                continue;
            }
            connections.add(net.nodes.get(cid));
        }
    }
}

@@ -1857,18 +1857,16 @@
 %0A    %7D%0A%0A
- %0A
     /**%0A
@@ -2108,32 +2108,789 @@
 rn true;%0A    %7D%0A%0A
+    boolean addBlock(Block block) %7B%0A        if (chain.addBlock(block)) %7B%0A            return true;%0A        %7D%0A%0A        // Block couldn't be added, means there was no previous %0A        // block in chain%0A        // try to get the previous block from our connected nodes%0A        Block prevblock = null;%0A%0A        for (Node n : connections) %7B%0A            prevblock = n.getBlock(block.prevhash);%0A            if (prevblock == null)%0A                continue;%0A            if (!checkBlock(prevblock))%0A                return false;%0A            else %0A                break;%0A        %7D%0A        if (prevblock ==null)%0A            return false;%0A        %0A        if (!addBlock(prevblock))%7B%0A            return false;%0A        %7D%0A  %0A        return chain.addBlock(block);%0A  %0A    %7D%0A%0A
     /**%0A     * R
@@ -3223,38 +3223,32 @@
  %7D%0A%0A        if (
-chain.
 addBlock(block))
@@ -3293,19 +3293,101 @@
   %7D%0A
+    %0A    %7D%0A%0A    public Block getBlock(int hash) %7B%0A        return chain.getBlock(hash);
 %0A    %7D%0A
-    
 %0A   
@@ -3437,16 +3437,23 @@
 ta base%0A
+     *%0A
      * @
@@ -3581,16 +3581,17 @@
 nt hash)
+ 
 %7B%0A      
@@ -3602,22 +3602,16 @@
 ock b = 
-chain.
 getBlock
@@ -3634,18 +3634,20 @@
 return b
+ 
 !=
+ 
 null;%0A  

Deal with missing blocks - load them from neighbours