contract Crowdsale is Ownable {
  using SafeMath for uint256;

  uint256   public constant rate = 680;                   // How many token units a buyer gets per wei
  uint256   public constant cap = 5000000 ether / rate;   // Maximum amount of funds

  bool      public isFinalized = false;
  uint256   public endTime = 1517097600;                  // End timestamps where investments are allowed
                                                          // Sunday, 28 January 2018, 00:00:00 GMT

  ALT0Token public token;                                 // ALT0 token itself
  address   public wallet;                                // Wallet of funds
  uint256   public weiRaised;                             // Amount of raised money in wei

  event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
  event Finalized();

  function Crowdsale (ALT0Token _ALT0, address _wallet) public {
    assert(address(_ALT0) != address(0));
    assert(_wallet != address(0));
    assert(endTime > now);
    assert(rate > 0);
    assert(cap > 0);

    token = _ALT0;
    wallet = _wallet;
  }

  function () public payable {
    buyTokens(msg.sender);
  }

  function buyTokens(address beneficiary) public payable {
    require(beneficiary != address(0));
    require(validPurchase());

    uint256 weiAmount = msg.value;
    uint256 tokens = weiAmount.mul(rate);

    weiRaised = weiRaised.add(weiAmount);

    token.mint(beneficiary, tokens);
    TokenPurchase(msg.sender, beneficiary, weiAmount, tokens);

    forwardFunds();
  }

  /**
   * @dev Calls the contract's finalization function.
   */
  function finalize() onlyOwner public {
    require(!isFinalized);

    finalization();
    Finalized();

    isFinalized = true;
  }

  // send ether to the fund collection wallet
  // override to create custom fund forwarding mechanisms
  function forwardFunds() internal {
    wallet.transfer(msg.value);
  }

  // @return true if the transaction can buy tokens
  function validPurchase() internal view returns (bool) {
    bool tokenMintingFinished = token.mintingFinished();
    bool withinCap = weiRaised.add(msg.value) <= cap;
    bool withinPeriod = now <= endTime;
    bool nonZeroPurchase = msg.value != 0;

    return !tokenMintingFinished && withinCap && withinPeriod && nonZeroPurchase;
  }

  function finalization() internal {
    token.finishMinting();
    endTime = now;
  }

  // @return true if crowdsale event has ended
  function hasEnded() public view returns (bool) {
    return now > endTime;
  }
}
/**
 * @title Crowdsale ALT0 presale token
 */
function validPurchase() internal view returns (bool) {
  bool tokenMintingFinished = token.mintingFinished();
  bool withinCap = weiRaised.add(msg.value) <= cap;
  bool withinPeriod = now <= endTime;
  bool nonZeroPurchase = msg.value != 0;

  return !tokenMintingFinished && withinCap && withinPeriod && nonZeroPurchase;
}

// @return true if the transaction can buy tokens