contract VestingTrustee is Ownable {
    using SafeMath for uint256;

    // Kin token contract.
    KinToken public kin;

    // Vesting grant for a speicifc holder.
    struct Grant {
        uint256 value;
        uint256 start;
        uint256 cliff;
        uint256 end;
        uint256 installmentLength; // In seconds.
        uint256 transferred;
        bool revokable;
    }

    // Holder to grant information mapping.
    mapping (address => Grant) public grants;

    // Total tokens available for vesting.
    uint256 public totalVesting;

    event NewGrant(address indexed _from, address indexed _to, uint256 _value);
    event TokensUnlocked(address indexed _to, uint256 _value);
    event GrantRevoked(address indexed _holder, uint256 _refund);

    /// @dev Constructor that initializes the address of the Kin token contract.
    /// @param _kin KinToken The address of the previously deployed Kin token contract.
    function VestingTrustee(KinToken _kin) {
        require(_kin != address(0));

        kin = _kin;
    }

    /// @dev Grant tokens to a specified address. Please note, that the trustee must have enough ungranted tokens to
    /// accomodate the new grant. Otherwise, the call with fail.
    /// @param _to address The holder address.
    /// @param _value uint256 The amount of tokens to be granted.
    /// @param _start uint256 The beginning of the vesting period.
    /// @param _cliff uint256 Duration of the cliff period (when the first installment is made).
    /// @param _end uint256 The end of the vesting period.
    /// @param _installmentLength uint256 The length of each vesting installment (in seconds).
    /// @param _revokable bool Whether the grant is revokable or not.
    function grant(address _to, uint256 _value, uint256 _start, uint256 _cliff, uint256 _end,
        uint256 _installmentLength, bool _revokable)
        external onlyOwner {

        require(_to != address(0));
        require(_to != address(this)); // Protect this contract from receiving a grant.
        require(_value > 0);

        // Require that every holder can be granted tokens only once.
        require(grants[_to].value == 0);

        // Require for time ranges to be consistent and valid.
        require(_start <= _cliff && _cliff <= _end);

        // Require installment length to be valid and no longer than (end - start).
        require(_installmentLength > 0 && _installmentLength <= _end.sub(_start));

        // Grant must not exceed the total amount of tokens currently available for vesting.
        require(totalVesting.add(_value) <= kin.balanceOf(address(this)));

        // Assign a new grant.
        grants[_to] = Grant({
            value: _value,
            start: _start,
            cliff: _cliff,
            end: _end,
            installmentLength: _installmentLength,
            transferred: 0,
            revokable: _revokable
        });

        // Since tokens have been granted, reduce the total amount available for vesting.
        totalVesting = totalVesting.add(_value);

        NewGrant(msg.sender, _to, _value);
    }

    /// @dev Revoke the grant of tokens of a specifed address.
    /// @param _holder The address which will have its tokens revoked.
    function revoke(address _holder) public onlyOwner {
        Grant memory grant = grants[_holder];

        // Grant must be revokable.
        require(grant.revokable);

        // Calculate amount of remaining tokens that can still be returned.
        uint256 refund = grant.value.sub(grant.transferred);

        // Remove the grant.
        delete grants[_holder];

        // Update total vesting amount and transfer previously calculated tokens to owner.
        totalVesting = totalVesting.sub(refund);
        kin.transfer(msg.sender, refund);

        GrantRevoked(_holder, refund);
    }

    /// @dev Calculate the total amount of vested tokens of a holder at a given time.
    /// @param _holder address The address of the holder.
    /// @param _time uint256 The specific time to calculate against.
    /// @return a uint256 Representing a holder's total amount of vested tokens.
    function vestedTokens(address _holder, uint256 _time) external constant returns (uint256) {
        Grant memory grant = grants[_holder];
        if (grant.value == 0) {
            return 0;
        }

        return calculateVestedTokens(grant, _time);
    }

    /// @dev Calculate amount of vested tokens at a specifc time.
    /// @param _grant Grant The vesting grant.
    /// @param _time uint256 The time to be checked
    /// @return An uint256 Representing the amount of vested tokens of a specific grant.
    function calculateVestedTokens(Grant _grant, uint256 _time) private constant returns (uint256) {
        // If we're before the cliff, then nothing is vested.
        if (_time < _grant.cliff) {
            return 0;
        }

        // If we're after the end of the vesting period - everything is vested;
        if (_time >= _grant.end) {
            return _grant.value;
        }

        // Calculate amount of installments past until now.
        //
        // NOTE result gets floored because of integer division.
        uint256 installmentsPast = _time.sub(_grant.start).div(_grant.installmentLength);

        // Calculate amount of days in entire vesting period.
        uint256 vestingDays = _grant.end.sub(_grant.start);

        // Calculate and return the number of tokens according to vesting days that have passed.
        return _grant.value.mul(installmentsPast.mul(_grant.installmentLength)).div(vestingDays);
    }

    /// @dev Unlock vested tokens and transfer them to the grantee.
    function unlockVestedTokens() external {
        Grant storage grant = grants[msg.sender];

        // Make sure the grant has tokens available.
        require(grant.value != 0);

        // Get the total amount of vested tokens, acccording to grant.
        uint256 vested = calculateVestedTokens(grant, now);
        if (vested == 0) {
            return;
        }

        // Make sure the holder doesn't transfer more than what he already has.
        uint256 transferable = vested.sub(grant.transferred);
        if (transferable == 0) {
            return;
        }

        // Update transferred and total vesting amount, then transfer remaining vested funds to holder.
        grant.transferred = grant.transferred.add(transferable);
        totalVesting = totalVesting.sub(transferable);
        kin.transfer(msg.sender, transferable);

        TokensUnlocked(msg.sender, transferable);
    }
}
/// @title Vesting trustee contract for Kin token.
function grant(address _to, uint256 _value, uint256 _start, uint256 _cliff, uint256 _end,
    uint256 _installmentLength, bool _revokable)
    external onlyOwner {

    require(_to != address(0));
    require(_to != address(this)); // Protect this contract from receiving a grant.
    require(_value > 0);

    // Require that every holder can be granted tokens only once.
    require(grants[_to].value == 0);

    // Require for time ranges to be consistent and valid.
    require(_start <= _cliff && _cliff <= _end);

    // Require installment length to be valid and no longer than (end - start).
    require(_installmentLength > 0 && _installmentLength <= _end.sub(_start));

    // Grant must not exceed the total amount of tokens currently available for vesting.
    require(totalVesting.add(_value) <= kin.balanceOf(address(this)));

    // Assign a new grant.
    grants[_to] = Grant({
        value: _value,
        start: _start,
        cliff: _cliff,
        end: _end,
        installmentLength: _installmentLength,
        transferred: 0,
        revokable: _revokable
    });

    // Since tokens have been granted, reduce the total amount available for vesting.
    totalVesting = totalVesting.add(_value);

    NewGrant(msg.sender, _to, _value);
}

/// @dev Grant tokens to a specified address. Please note, that the trustee must have enough ungranted tokens to
/// accomodate the new grant. Otherwise, the call with fail.
/// @param _to address The holder address.
/// @param _value uint256 The amount of tokens to be granted.
/// @param _start uint256 The beginning of the vesting period.
/// @param _cliff uint256 Duration of the cliff period (when the first installment is made).
/// @param _end uint256 The end of the vesting period.
/// @param _installmentLength uint256 The length of each vesting installment (in seconds).
/// @param _revokable bool Whether the grant is revokable or not.