package com.mindata.blockchain.socket.pbft.queue;

import cn.hutool.core.collection.CollectionUtil;
import com.mindata.blockchain.socket.pbft.msg.VoteMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wuweifeng wrote on 2018/4/26.
 */
public abstract class AbstractVoteMsgQueue extends BaseMsgQueue {
    /**
     * 存储所有的hash的投票集合
     */
    protected ConcurrentHashMap<String, List<VoteMsg>> voteMsgConcurrentHashMap = new ConcurrentHashMap<>();
    /**
     * 存储本节点已确认状态的hash的集合,即本节点已对外广播过允许commit或拒绝commit的消息了
     */
    protected ConcurrentHashMap<String, Boolean> voteStateConcurrentHashMap = new ConcurrentHashMap<>();

    private Logger logger = LoggerFactory.getLogger(getClass());

    abstract void deal(VoteMsg voteMsg, List<VoteMsg> voteMsgs);

    @Override
    protected void push(VoteMsg voteMsg) {
        String hash = voteMsg.getHash();
        List<VoteMsg> voteMsgs = voteMsgConcurrentHashMap.get(hash);
        if (CollectionUtil.isEmpty(voteMsgs)) {
            voteMsgs = new ArrayList<>();
            voteMsgs.add(voteMsg);
            voteMsgConcurrentHashMap.put(hash, voteMsgs);
        }
        //判断本地集合是否已经存在完全相同的voteMsg了
        for (VoteMsg temp : voteMsgs) {
            if (temp.getNumber() == voteMsg.getNumber() && temp.getAppId().equals(voteMsg.getAppId())) {
                return;
            }
        }
        //添加进去
        voteMsgs.add(voteMsg);
        //如果我已经对该hash的commit投过票了,就不再继续
        if (voteStateConcurrentHashMap.get(hash) != null) {
            return;
        }

        deal(voteMsg, voteMsgs);
    }

    /**
     * 校验队列中是否存在number相同,hash不同,且被同意数量已经超过过2f+1的记录
     *
     * @param hash
     *         hash
     * @return 是否超过
     */
    public boolean hasOtherConfirm(String hash, int number) {
        for (String key : voteMsgConcurrentHashMap.keySet()) {
            if (hash.equals(key)) {
                continue;
            }
            if (voteMsgConcurrentHashMap.get(key).get(0).getNumber() < number) {
                continue;
            }
            //如果有别的>=number的Block已经达成共识了,则返回true
            if (voteStateConcurrentHashMap.get(key) != null && voteStateConcurrentHashMap.get(key)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 清理旧的block的hash
     */
    protected void clearOldBlockHash(int number) {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for (String key : voteMsgConcurrentHashMap.keySet()) {
                if (voteMsgConcurrentHashMap.get(key).get(0).getNumber() <= number) {
                    voteMsgConcurrentHashMap.remove(key);
                    voteStateConcurrentHashMap.remove(key);
                }
            }
            return null;
        });
    }
}