/*
 * Copyright (c) [2016] [ <ether.camp> ]
 * This file is part of the ethereumJ library.
 *
 * The ethereumJ library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * The ethereumJ library 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
 */
package org.ethereum.net.dht;

import java.util.ArrayList;
import java.util.List;

public class Bucket {

    public static int MAX_KADEMLIA_K = 5;

    // if bit = 1 go left
    Bucket left;

    // if bit = 0 go right
    Bucket right;

    String name;

    List<Peer> peers = new ArrayList<>();


    public Bucket(String name) {
        this.name = name;
    }


    public void add(Peer peer) {

        if (peer == null) throw new Error("Not a leaf");

        if ( peers == null){

            if (peer.nextBit(name) == 1)
                left.add(peer);
            else
                right.add(peer);

            return;
        }

        peers.add(peer);

        if (peers.size() > MAX_KADEMLIA_K)
            splitBucket();
    }

    public void splitBucket() {
        left = new Bucket(name + "1");
        right = new Bucket(name + "0");

        for (Peer id : peers) {
            if (id.nextBit(name) == 1)
                left.add(id);
            else
                right.add(id);
        }

        this.peers = null;
    }


    public Bucket left() {
        return left;
    }

    public Bucket right() {
        return right;
    }


    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();

        sb.append(name).append("\n");

        if (peers == null) return sb.toString();

        for (Peer id : peers)
            sb.append(id.toBinaryString()).append("\n");

        return sb.toString();
    }


    public void traverseTree(DoOnTree doOnTree) {

        if (left  != null) left.traverseTree(doOnTree);
        if (right != null) right.traverseTree(doOnTree);

        doOnTree.call(this);
    }


    /********************/
     // tree operations //
    /********************/

    public interface DoOnTree {

        void call(Bucket bucket);
    }


    public static class SaveLeaf implements DoOnTree {

        List<Bucket> leafs = new ArrayList<>();

        @Override
        public void call(Bucket bucket) {
            if (bucket.peers != null) leafs.add(bucket);
        }

        public List<Bucket> getLeafs() {
            return leafs;
        }

        public void setLeafs(List<Bucket> leafs) {
            this.leafs = leafs;
        }
    }

    public String getName(){
        return name;
    }

    public List<Peer> getPeers() {
        return peers;
    }
}
