contract MeeTipCrowdsale is FinalizableCrowdsale {
    using SafeMath for uint256;

    address public foundersWallet;
    address public bountyWallet;
    // minimal purchase is 0.05 Ether
    uint256 public constant MINIMAL_PURCHASE = 50 finney;
    // hard cap is 27 000 000 MTIP
    uint256 public tokenCap = 27000000 * 10**18;
    // minimum amount of tokens to be sold
    uint256 public tokenGoal = 50000 * 10**18;
    uint256 public tokenSold;
    uint256 public endTimePreICO;
    uint256 public startTimeICO;
    uint256 public endFirstDayICO;
    uint256 public endFirstWeekICO;
    uint256 public endSecondWeekICO;
    uint256 public endThirdWeekICO;

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

    function MeeTipCrowdsale(
        uint256 _startTime,
        uint256 _endTimePreICO,
        uint256 _startTimeICO,
        uint256 _endFirstDayICO,
        uint256 _endFirstWeekICO,
        uint256 _endSecondWeekICO,
        uint256 _endThirdWeekICO,
        uint256 _endTime,
        address _contributionWallet,
        address _foundersWallet,
        address _bountyWallet
        )
        FinalizableCrowdsale()
        // convertion rate is 900 MTIP per 1 ether during preICO
        Crowdsale(_startTime, _endTime, 900, _contributionWallet)
        {
        require(_foundersWallet != 0x0);
        require(_bountyWallet != 0x0);
        require(_endTimePreICO >= _startTime);
        require(_startTimeICO >= _endTimePreICO);
        require(_endFirstDayICO >= _startTimeICO);
        require(_endFirstWeekICO >= _endFirstDayICO);
        require(_endSecondWeekICO >= _endFirstWeekICO);
        require(_endThirdWeekICO >= _endSecondWeekICO);
        require(_endTime >= _endThirdWeekICO);

        vault = new RefundVault(wallet);

        endTimePreICO = _endTimePreICO;
        startTimeICO = _startTimeICO;
        endFirstDayICO = _endFirstDayICO;
        endFirstWeekICO = _endFirstWeekICO;
        endSecondWeekICO = _endSecondWeekICO;
        endThirdWeekICO = _endThirdWeekICO;

        foundersWallet = _foundersWallet;
        bountyWallet = _bountyWallet;

        // allocate 1 500 000 MTIP for company
        token.mint(foundersWallet, 1500000 * (10**18));

        // allocate 1 500 000 MTIP for bounty program
        token.mint(bountyWallet, 1500000 * (10**18));
        }

    function createTokenContract() internal returns (MintableToken) {
        return new MeeTip();
    }

    // low level token purchase function
    function buyTokens(address beneficiary) public payable {
        require(beneficiary != 0x0);

        updateRate();

        require(validPurchase());

        uint256 weiAmount = msg.value;

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

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

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

        forwardFunds();
    }

    function updateRate() internal constant {
        if (now <= endTimePreICO) {
            rate = 900;
        } else if (now <= endFirstDayICO ) {
            rate = 800;
        } else if (now <= endFirstWeekICO) {
            rate = 750;
        } else if (now <= endSecondWeekICO) {
            rate = 700;
        } else if (now <= endThirdWeekICO) {
            rate = 650;
        } else if (now <= endTime) {
            rate = 600;
        }
    }

    // @return true if the transaction can buy tokens
    function validPurchase() internal constant returns (bool) {
        bool withinPreICO = startTime <= now && now <= endTimePreICO;
        bool withinICO = startTimeICO <= now && now <= endTime;
        bool enoughPurchase = msg.value >= MINIMAL_PURCHASE;
        bool withinTokenCap = tokenSold.add(msg.value.mul(rate)) <= tokenCap;
        return (withinPreICO || withinICO) && enoughPurchase && withinTokenCap;
    }

    // We're overriding the fund forwarding from Crowdsale.
    // In addition to sending the funds, we want to call
    // the RefundVault deposit function
    function forwardFunds() internal {
        // no refunds during preICO
        if ( now <= endTimePreICO ) {
            wallet.transfer(msg.value);
        } else {
            vault.deposit.value(msg.value)(msg.sender);
        }
    }

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

        vault.refund(msg.sender);
    }

    // vault finalization task, called when owner calls finalize()
    function finalization() internal {
        if (goalReached()) {
            vault.close();
        } else {
            vault.enableRefunds();
        }
        super.finalization();
    }

    function goalReached() public constant returns (bool) {
        return tokenSold >= tokenGoal;
    }

    // overriding Crowdsale#hasEnded to add cap logic
    // @return true if crowdsale event has ended
    function hasEnded() public constant returns (bool) {
        bool tokenCapReached = tokenSold >= tokenCap;
        return super.hasEnded() || tokenCapReached;
    }
}
function forwardFunds() internal {
    // no refunds during preICO
    if ( now <= endTimePreICO ) {
        wallet.transfer(msg.value);
    } else {
        vault.deposit.value(msg.value)(msg.sender);
    }
}

// We're overriding the fund forwarding from Crowdsale.
// In addition to sending the funds, we want to call
// the RefundVault deposit function