contract preICO is FinalizableCrowdsale, WhitelistedCrowdsale {
    Token public token;

    // May 01, 2018 @ UTC 0:01
    uint256 public startDate;

    // May 14, 2018 @ UTC 23:59
    uint256 public endDate;

    // amount of raised money in wei
    uint256 public weiRaised;

    // how many token units a buyer gets per wei
    uint256 public constant rate = 1920;

    uint256 public constant softCap = 500 * (1 ether);

    uint256 public constant hardCap = 1000 * (1 ether);

    // refund vault used to hold funds while crowdsale is running
    RefundVault public vault;

    /**
     * event for token purchase logging
     * @param purchaser who paid for the tokens
     * @param beneficiary who got the tokens
     * @param value weis paid for purchase
     * @param amount amount of tokens purchased
     */
    event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);

    /**
     * @dev _wallet where collect funds during crowdsale
     * @dev _startDate should be 1525132860
     * @dev _endDate should be 1526342340
     * @dev _maxEtherPerInvestor should be 10 ether
     */
    function preICO(address _token, address _wallet, uint256 _startDate, uint256 _endDate) public {
        require(_token != address(0) && _wallet != address(0));
        require(_endDate > _startDate);
        startDate = _startDate;
        endDate = _endDate;
        token = Token(_token);
        vault = new RefundVault(_wallet);
    }

    /**
     * @dev Investors can claim refunds here if crowdsale is unsuccessful
     */
    function claimRefund() public {
        require(isFinalized);
        require(!goalReached());

        vault.refund(msg.sender);
    }

    /**
     * @dev Checks whether funding goal was reached.
     * @return Whether funding goal was reached
     */
    function goalReached() public view returns (bool) {
        return weiRaised >= softCap;
    }

    /**
     * @dev vault finalization task, called when owner calls finalize()
     */
    function finalization() internal {
        require(hasEnded());
        if (goalReached()) {
            vault.close();
        } else {
            vault.enableRefunds();
        }
    }

    // fallback function can be used to buy tokens
    function() external payable {
        buyTokens(msg.sender);
    }

    // low level token purchase function
    function buyTokens(address beneficiary) whenNotPaused isWhitelisted(beneficiary) isWhitelisted(msg.sender) public payable {
        require(beneficiary != address(0));
        require(validPurchase());
        require(!hasEnded());

        uint256 weiAmount = msg.value;

        // calculate token amount to be created
        uint256 tokens = weiAmount.mul(rate);

        // Minimum contribution level in TKP tokens for each investor = 100 TKP
        require(tokens >= 100 * (10 ** 18));

        // update state
        weiRaised = weiRaised.add(weiAmount);

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

    // send ether to the fund collection wallet
    function forwardFunds() internal {
        vault.deposit.value(msg.value)(msg.sender);
    }

    // @return true if the transaction can buy tokens
    function validPurchase() internal view returns (bool) {
        return !isFinalized && now >= startDate && msg.value != 0;
    }

    // @return true if crowdsale event has ended
    function hasEnded() public view returns (bool) {
        return (now > endDate || weiRaised >= hardCap);
    }
}
function hasEnded() public view returns (bool) {
    return (now > endDate || weiRaised >= hardCap);
}

// @return true if crowdsale event has ended