contract IRBPreCrowdsale is Ownable, Pausable {
    using SafeMath for uint;

    /**
     * @dev token contract
     */
    IRBToken public token;

    /**
     * @dev refund vault used to hold funds while crowdsale is running
     */
    IRBPreRefundVault public vault;

    /**
     * @dev tokensale(presale) start time: Dec 12, 2017, 11:00:00 + 3
     */
    uint startTime = 1513065600;

    /**
     * @dev tokensale end time: Jan 14, 2018 23:59:59 +3
     */
    uint endTime = 1515963599;

    /**
     * @dev minimum purchase amount for presale
     */
    uint256 public constant minPresaleAmount = 108 * 10 ** 15; // 400 IRB

    /**
     * @dev minimum and maximum amount of funds to be raised in weis
     */
    uint256 public constant goal = 1125 * 10 ** 18;  // 1.125 Kether
    uint256 public constant cap = 2250 * 10 ** 18; // 2.25 Kether

    /**
     * @dev amount of raised money in wei
     */
    uint256 public weiRaised;

    /**
     * @dev tokensale finalization flag
     */
    bool public isFinalized = false;

    /**
     * @dev 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 event for tokensale final logging
     */
    event Finalized();

    /**
     * @dev Pre Crowdsale in the constructor takes addresses of
     *      the just deployed IRBToken and IRBPreRefundVault contracts
     * @param _tokenAddress address of the IRBToken deployed contract
     * @param _vaultAddress address of the IRBPreRefundVault deployed contract
     */
    function IRBPreCrowdsale(address _tokenAddress, address _vaultAddress) {
        require(_tokenAddress != address(0));
        require(_vaultAddress != address(0));

        // IRBToken and IRBPreRefundVault was deployed separately
        token = IRBToken(_tokenAddress);
        vault = IRBPreRefundVault(_vaultAddress);
    }

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

    /**
     * @dev main function to buy tokens
     * @param beneficiary target wallet for tokens can vary from the sender one
     */
    function buyTokens(address beneficiary) whenNotPaused public payable {
        require(beneficiary != address(0));
        require(validPurchase(msg.value));

        uint256 weiAmount = msg.value;

        // buyer and beneficiary could be two different wallets
        address buyer = msg.sender;

        // calculate token amount to be created
        uint256 tokens = convertAmountToTokens(weiAmount);

        weiRaised = weiRaised.add(weiAmount);

        if (!token.transferFrom(token.preCrowdsaleTokensWallet(), beneficiary, tokens)) {
            revert();
        }

        TokenPurchase(buyer, beneficiary, weiAmount, tokens);

        vault.deposit.value(weiAmount)(buyer);
    }

    /**
     * @dev check if the current purchase valid based on time and amount of passed ether
     * @param _value amount of passed ether
     * @return true if investors can buy at the moment
     */
    function validPurchase(uint256 _value) internal constant returns (bool) {
        bool nonZeroPurchase = _value != 0;
        bool withinPeriod = now >= startTime && now <= endTime;
        bool withinCap = weiRaised.add(_value) <= cap;
        // For presale we want to decline all payments less then minPresaleAmount
        bool withinAmount = msg.value >= minPresaleAmount;

        return nonZeroPurchase && withinPeriod && withinCap && withinAmount;
    }

    /**
     * @dev check if crowdsale still active based on current time and cap
     * consider minPresaleAmount
     * @return true if crowdsale event has ended
     */
    function hasEnded() public constant returns (bool) {
        bool capReached = weiRaised.add(minPresaleAmount) >= cap;
        bool timeIsUp = now > endTime;
        return timeIsUp || capReached;
    }

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

        vault.refund(msg.sender);
    }

    /**
     * @dev finalize crowdsale. this method triggers vault and token finalization
     */
    function finalize() onlyOwner public {
        require(!isFinalized);
        require(hasEnded());

        // trigger vault and token finalization
        if (goalReached()) {
            vault.close();
        }
        else {
            vault.enableRefunds();
        }

        token.endPreTokensale();

        isFinalized = true;

        Finalized();
    }

    /**
     * @dev check if hard cap goal is reached
     */
    function goalReached() public constant returns (bool) {
        return weiRaised >= goal;
    }

    /**
    * @dev withdraw method that can be used by owner for
    *      withdraw funds from vault to owner
    */
    function withdraw(uint256 amount) onlyOwner public {
        require(!isFinalized);
        require(goalReached());
        require(amount > 0);

        vault.withdraw(amount);
    }

    /**
     * @dev returns current token price
     */
    function convertAmountToTokens(uint256 amount) public constant returns (uint256) {
        // 1 token = 0.00027 ETH
        uint256 tokens = amount.div(27).mul(100000);
        // bonus +25%
        uint256 bonus = tokens.div(4);

        return tokens.add(bonus);
    }

    /**
     * @dev killer method that can bu used by owner to
     *      kill the contract and send funds to owner
     */
    function kill() onlyOwner whenPaused {
        selfdestruct(owner);
    }
}
/**
 * @title IRBPreCrowdsale
 * @dev IRB pre crowdsale contract borrows Zeppelin Finalized, Capped and Refundable crowdsales implementations
 */
function convertAmountToTokens(uint256 amount) public constant returns (uint256) {
    // 1 token = 0.00027 ETH
    uint256 tokens = amount.div(27).mul(100000);
    // bonus +25%
    uint256 bonus = tokens.div(4);

    return tokens.add(bonus);
}

/**
 * @dev returns current token price
 */