contract BoostCrowdsale is Ownable {
    using SafeMathForBoost for uint256;

    // start and end timestamps where investments are allowed (both inclusive)
    uint256 public startTime;
    uint256 public endTime;

    // rate use during the ico
    uint256 public rate;

    // address of multiSigWallet to store ether
    address public wallet;

    // Boost token
    Boost public boost;

    // cap
    uint256 public cap;

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

    // minimun amount
    uint256 public minimumAmount = 0.1 ether;

    // amount of sold token
    uint256 public soldAmount;

    // isFinalised flag
    bool public isFinalized = false;

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

    // event for finalized
    event Finalized();

    // @dev constructor
    function BoostCrowdsale(uint256 _startTime, uint256 _endTime, address _boostAddress, uint256 _rate, address _wallet, uint256 _cap) public {
        require(_startTime >= now);
        require(_endTime >= _startTime);
        require(_boostAddress != address(0));
        require(_rate > 0);
        require(_wallet != address(0));
        require(_cap > 0);

        startTime = _startTime;
        endTime = _endTime;
        boost = Boost(_boostAddress);
        rate = _rate;
        wallet = _wallet;
        cap = _cap;
    }

    /**
    * @dev Must be called after crowdsale ends, to do some extra finalization
    * work. Calls the contract's finalization function.
    */
    function finalize() public onlyOwner {
        require(!isFinalized);
        require(hasEnded());

        finalization();
        Finalized();

        isFinalized = true;
    }

    // @dev fallback function to exchange the ether for Boost token
    function() public payable {
        uint256 weiAmount = msg.value;

        // calc token amount
        uint256 tokens = getTokenAmount(weiAmount);

        require(validPurchase(tokens));

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

        // transfer boostToken from owner to msg.sender
        boost.transfer(msg.sender, tokens);
        TokenPurchase(msg.sender, weiAmount, tokens);

        forwardFunds();
    }

    // @dev return true if crowdsale event has ended
    function hasEnded() public view returns (bool) {
        bool overPeriod = now > endTime;
        bool underPurchasableAmount = getPurchasableAmount() < 10000;
        return overPeriod || underPurchasableAmount;
    }

    // @dev return the amount of token that user can purchase
    function getPurchasableAmount() public view returns (uint256) {
        return boost.balanceOf(this);
    }

    // @dev return the amount of ether that user can send in order to purchase token
    function getSendableEther() public view returns (uint256) {
        return boost.balanceOf(this).mul(10 ** 18).div(rate);
    }

    // @dev return the amount of token that msg.sender can receive based on the amount of ether that msg.sender sent
    function getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {
        return _weiAmount.mul(rate).div(10 ** 18);
    }

    // @dev send ether to the fund collection wallet
    function forwardFunds() internal {
        wallet.transfer(msg.value);
    }

    // @dev finalization
    function finalization() internal {
        if (boost.balanceOf(this) > 0) {
            require(boost.transfer(owner, boost.balanceOf(this)));
        }
    }

    // @dev return true if the transaction can buy tokens
    function validPurchase(uint256 _tokens) internal view returns (bool) {
        bool withinPeriod = now >= startTime && now <= endTime;
        bool moreThanOrEqualToMinimumAmount = msg.value >= minimumAmount;
        bool validPurchasableAmount = cap >= soldAmount.add(_tokens);
        return withinPeriod && moreThanOrEqualToMinimumAmount && validPurchasableAmount;
    }
}
// @title Boost token interface to use during the ICO
function getSendableEther() public view returns (uint256) {
    return boost.balanceOf(this).mul(10 ** 18).div(rate);
}

// @dev return the amount of ether that user can send in order to purchase token