contract Vesting is DBC {
    using safeMath for uint;

    // FIELDS

    // Constructor fields
    ERC20 public MELON_CONTRACT; // Melon as ERC20 contract
    // Methods fields
    uint public totalVestedAmount; // Quantity of vested Melon in total
    uint public vestingStartTime; // Timestamp when vesting is set
    uint public vestingPeriod; // Total vesting period in seconds
    address public beneficiary; // Address of the beneficiary
    uint public withdrawn; // Quantity of Melon withdrawn so far

    // CONSTANT METHODS

    function isBeneficiary() constant returns (bool) { return msg.sender == beneficiary; }
    function isVestingStarted() constant returns (bool) { return vestingStartTime != 0; }

    /// @notice Calculates the quantity of Melon asset that's currently withdrawable
    /// @return withdrawable Quantity of withdrawable Melon asset
    function calculateWithdrawable() constant returns (uint withdrawable) {
        uint timePassed = now.sub(vestingStartTime);

        if (timePassed < vestingPeriod) {
            uint vested = totalVestedAmount.mul(timePassed).div(vestingPeriod);
            withdrawable = vested.sub(withdrawn);
        } else {
            withdrawable = totalVestedAmount.sub(withdrawn);
        }
    }

    // NON-CONSTANT METHODS

    /// @param ofMelonAsset Address of Melon asset
    function Vesting(address ofMelonAsset) {
        MELON_CONTRACT = ERC20(ofMelonAsset);
    }

    /// @param ofBeneficiary Address of beneficiary
    /// @param ofMelonQuantity Address of Melon asset
    /// @param ofVestingPeriod Vesting period in seconds from vestingStartTime
    function setVesting(address ofBeneficiary, uint ofMelonQuantity, uint ofVestingPeriod)
        pre_cond(!isVestingStarted())
        pre_cond(ofMelonQuantity > 0)
    {
        require(MELON_CONTRACT.transferFrom(msg.sender, this, ofMelonQuantity));
        vestingStartTime = now;
        totalVestedAmount = ofMelonQuantity;
        vestingPeriod = ofVestingPeriod;
        beneficiary = ofBeneficiary;
    }

    /// @notice Withdraw
    function withdraw()
        pre_cond(isBeneficiary())
        pre_cond(isVestingStarted())
    {
        uint withdrawable = calculateWithdrawable();
        withdrawn = withdrawn.add(withdrawable);
        require(MELON_CONTRACT.transfer(beneficiary, withdrawable));
    }

}
function Vesting(address ofMelonAsset) {
    MELON_CONTRACT = ERC20(ofMelonAsset);
}

/// @param ofMelonAsset Address of Melon asset