contract LoomTimeVault is Ownable {
  // only after the release time the beficiary will be
  // able to transfer the balance of the token
  LoomToken public loomToken;

  // beneficiaries of tokens
  mapping(address => uint256) public beneficiaries; // beneficiary => amount

  // timestamp when token release is enabled
  uint256 public releaseTime;

  // events --------------------------------------------------------------------

  event BeneficiaryAdded(address _beneficiaryAddress, uint256 _amount);
  event BeneficiaryWithdrawn(address _beneficiaryAddress, uint256 _amount);
  event OwnerWithdrawn(address _ownerAddress, uint256 _amount);

  // modifiers -----------------------------------------------------------------

  modifier onlyAfterReleaseTime() {
    require(now >= releaseTime);
    _;
  }

  // constructor function ------------------------------------------------------

  function LoomTimeVault(uint256 _releaseTime, address _loomTokenAddress) public {
    require(_releaseTime > now);
    require(_loomTokenAddress != address(0));

    owner = msg.sender;
    releaseTime = _releaseTime;
    loomToken = LoomToken(_loomTokenAddress);
  }

  // external functions --------------------------------------------------------

  /**
  * @dev the owner of the vault can add the beneficiary accounts
  * @param _beneficiaryAddress address which will receive the benefit in the future
  * @param _amount quantity of tokens to beneficiary receive
  */
  function addBeneficiary(address _beneficiaryAddress, uint256 _amount)
    external
    onlyOwner
  {
    require(_beneficiaryAddress != address(0));
    require(_amount > 0);
    require(_amount <= loomToken.balanceOf(this));

    beneficiaries[_beneficiaryAddress] = _amount;
    BeneficiaryAdded(_beneficiaryAddress, _amount);
  }

  /**
  * @dev the beneficiary can withdraw the tokens from the vault after the time the
  * releaseTime expired, the beneficiary will only receive the amount specified
  */
  function withdraw()
    external
    onlyAfterReleaseTime
  {
    uint256 amount = beneficiaries[msg.sender];
    require(amount > 0);

    beneficiaries[msg.sender] = 0;

    assert(loomToken.transfer(msg.sender, amount));
    BeneficiaryWithdrawn(msg.sender, amount);
  }

  /**
  * @dev the owner of the vault can withdraw the tokens from the vault after the time the
  * releaseTime expire
  */
  function ownerWithdraw()
    external
    onlyOwner
    onlyAfterReleaseTime
  {
    uint256 amount = loomToken.balanceOf(this);
    require(amount > 0);

    assert(loomToken.transfer(msg.sender, amount));
    OwnerWithdrawn(msg.sender, amount);
  }

  /**
  * @dev get how many tokens the beneficiary address has to withdraw after the release time
  * expire
  * @param _beneficiaryAddress address of the beneficiary to inspect
  */
  function beneficiaryAmount(address _beneficiaryAddress)
    public
    view
    returns (uint256)
  {
    return beneficiaries[_beneficiaryAddress];
  }
}
function withdraw()
  external
  onlyAfterReleaseTime
{
  uint256 amount = beneficiaries[msg.sender];
  require(amount > 0);

  beneficiaries[msg.sender] = 0;

  assert(loomToken.transfer(msg.sender, amount));
  BeneficiaryWithdrawn(msg.sender, amount);
}

/**
 * @dev the beneficiary can withdraw the tokens from the vault after the time the
 * releaseTime expired, the beneficiary will only receive the amount specified
 */