contract DepositKAI {
    using SafeMath for uint256;
    using EnumerableSet for EnumerableSet.AddressSet;

    constructor(address[] memory _valAddr) public {
        owner = msg.sender;
        for(uint i=0; i<_valAddr.length; i++) {
            valAddr.push(_valAddr[i]);
        }

        isRefundAble = false;
    }
    
    address constant KAI_ADDRESS = 0xD9Ec3ff1f8be459Bb9369b4E79e9Ebcf7141C093;
    uint256 constant public MIN_DEPOSIT = 25000000000000000000000; // 25K KAI
    uint256 constant public MIN_VALIDATOR_AMOUNT = 12500000000000000000000000; // 12,5M kai
    
    address private owner;
    uint256 public currentCap;
    mapping (address => mapping(address => uint256)) public delAmount;
    mapping (address => uint256) public valAmount;
    mapping (address => EnumerableSet.AddressSet) private dels;
    address[] public winValAddr;
    address[] public valAddr;
    bool public isRefundAble;

    // Functions with this modifier can only be executed by the owner
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }
    
    function depositKAI(address _valAddr ,uint256 _amount) public {
        require(_amount >= MIN_DEPOSIT, "Amount must be greater or equal 25000 KAI");
        require(isWinValAddr(_valAddr) == false, "The validator is win");
        require(winValAddr.length < 5, "The campaign is ended");
        require(Token(KAI_ADDRESS).transferFrom(msg.sender, address(this), _amount));

        if(!dels[_valAddr].contains(msg.sender)) {
            dels[_valAddr].add(msg.sender);
        }
        delAmount[msg.sender][_valAddr] += _amount;
        currentCap = currentCap.add(_amount);
        valAmount[_valAddr] +=  _amount;

        if (valAmount[_valAddr] >= MIN_VALIDATOR_AMOUNT){
            winValAddr.push(_valAddr);
        }
    }
    
    function burnKAI() public onlyOwner {
        Token(KAI_ADDRESS).burn(getBalanceKAIContract());
    }
    
    // if the validator not win, its delegators must withdraw kai
    function withdrawKAI(address _valAddr) public {
        require(isRefundAble == true, "Is not withdrawable yet");
        require(winValAddr.length == 5, "The campaign is ended");
        require(isWinValAddr(_valAddr) == false, "This is not a winner");
        require(delAmount[msg.sender][_valAddr] > 0, "Can only withdraw once");
    
        uint256 amount = delAmount[msg.sender][_valAddr];
        Token(KAI_ADDRESS).transfer(msg.sender, amount);
        delAmount[msg.sender][_valAddr] = 0;
    }
    
    function getBalanceKAIContract() public view returns (uint256) {
        return Token(KAI_ADDRESS).balanceOf(address(this));
    }
    
    function getWinValidatorLength() public view returns (uint256) {
        return winValAddr.length;
    }

    function getValidatorLength() public view returns (uint256) {
        return valAddr.length;
    }

    function getDelegators(address _valAddr) public view returns (address[] memory, uint256[] memory) {
        uint256 totalDels = dels[_valAddr].length();
        address[] memory delegators = new address[](totalDels);
        uint256[] memory amount = new uint256[](totalDels);
        
        for (uint i=0; i<totalDels; i++){
            delegators[i] = dels[_valAddr].at(i);
            amount[i] = delAmount[delegators[i]][_valAddr];
        }
        return (delegators,amount);
    }

    function isWinValAddr(address _valAddr) public view returns(bool) {
        for (uint i=0; i<winValAddr.length; i++) {
            if (winValAddr[i] == _valAddr) {
                return true;
            }
        }
      return false;
    }
    
    function addValAddr(address _valAddr) public onlyOwner {
        valAddr.push(_valAddr);
    }

    function setIsRefundAble() public onlyOwner {
        isRefundAble = true;
    }

    function emergencyWithdrawalKAI(uint256 amount) public onlyOwner {
        Token(KAI_ADDRESS).transfer(msg.sender, amount);
    }  
}
function withdrawKAI(address _valAddr) public {
        require(isRefundAble == true, "Is not withdrawable yet");
        require(winValAddr.length == 5, "The campaign is ended");
        require(isWinValAddr(_valAddr) == false, "This is not a winner");
        require(delAmount[msg.sender][_valAddr] > 0, "Can only withdraw once");
    
        uint256 amount = delAmount[msg.sender][_valAddr];
        Token(KAI_ADDRESS).transfer(msg.sender, amount);
        delAmount[msg.sender][_valAddr] = 0;
    }
// if the validator not win, its delegators must withdraw kai