contract TokenSafeVesting is HasOwner {
    using SafeMath for uint256;

    // The Total number of tokens locked.
    uint256 total;
    uint256 lapsedTotal;
    address account;

    uint[] vestingCommencementDates;
    uint[] vestingPercents;

    bool revocable;
    bool revoked;

    // The `ERC20TokenInterface` contract.
    ERC20TokenInterface token;

    /**
     * @dev constructor new account with locked token balance
     *
     * @param _token The erc20 token address.
     * @param _account The address of th account.
     * @param _balanceTotal The number of tokens to be locked.
     * @param _vestingCommencementDates The vesting commenement date list.
     * @param _vestingPercents The vesting percents list.
     * @param _revocable Whether the vesting is revocable
     */
     constructor (
        address _token,
        address _account,
        uint256 _balanceTotal,
        uint[] _vestingCommencementDates,
        uint[] _vestingPercents,
        bool _revocable) public HasOwner(msg.sender) {

        // check _vestingCommencementDates and _vestingPercents
        require(_vestingPercents.length > 0);
        require(_vestingCommencementDates.length == _vestingPercents.length);
        uint percentSum;
        for (uint32 i = 0; i < _vestingPercents.length; i++) {
            require(_vestingPercents[i]>=0);
            require(_vestingPercents[i]<=100);
            percentSum = percentSum.add(_vestingPercents[i]);
            require(_vestingCommencementDates[i]>0);
            if (i > 0) {
                require(_vestingCommencementDates[i] > _vestingCommencementDates[i-1]);
            }
        }
        require(percentSum==100);

        token = ERC20TokenInterface(_token);
        account = _account;
        total = _balanceTotal;
        vestingCommencementDates = _vestingCommencementDates;
        vestingPercents = _vestingPercents;
        revocable = _revocable;
    }

    /**
     * @dev Allow the account to be released some token if it meets some vesting commencement date.
     * TODO: public -> internal ?
     */
    function release() public {
        require(!revoked);

        uint256 grant;
        uint percent;
        for (uint32 i = 0; i < vestingCommencementDates.length; i++) {
            if (block.timestamp < vestingCommencementDates[i]) {
            } else {
                percent += vestingPercents[i];
            }
        }
        grant = total.mul(percent).div(100);

        if (grant > lapsedTotal) {
            uint256 tokens = grant.sub(lapsedTotal);
            lapsedTotal = lapsedTotal.add(tokens);
            if (!token.transfer(account, tokens)) {
                revert();
            } else {
            }
        }
    }

    /**
     * @dev Revoke token
     */
    function revoke() public onlyOwner {
        require(revocable);
        require(!revoked);

        release();
        revoked = true;
    }
}
/**
 * @title TokenSafeVesting
 *
 * @dev A multi-bundle token safe contract
 */
function revoke() public onlyOwner {
    require(revocable);
    require(!revoked);

    release();
    revoked = true;
}

/**
 * @dev Revoke token
 */