function buyTokens(address _beneficiary) public payable {

    uint256 weiAmount = msg.value;
    require(_beneficiary != address(0));
    require(weiAmount != 0);
    bool isPresale = block.timestamp >= PRESALE_OPENING_TIME && block.timestamp <= PRESALE_CLOSING_TIME && presaleWeiRaised.add(weiAmount) <= PRESALE_WEI_CAP;
    bool isCrowdsale = block.timestamp >= CROWDSALE_OPENING_TIME && block.timestamp <= CROWDSALE_CLOSING_TIME && presaleGoalReached() && crowdsaleWeiRaised.add(weiAmount) <= CROWDSALE_WEI_CAP;
    uint256 tokens;

    if (isCrowdsale) {
      require(crowdsaleContributions[_beneficiary].add(weiAmount) <= getCrowdsaleUserCap());
      
      
      tokens = _getCrowdsaleTokenAmount(weiAmount);
      require(tokens != 0);

      
      crowdsaleWeiRaised = crowdsaleWeiRaised.add(weiAmount);
    } else if (isPresale) {
      require(whitelist[_beneficiary]);
      
      
      tokens = weiAmount.mul(PRESALE_RATE).div(1 ether);
      require(tokens != 0);

      
      presaleWeiRaised = presaleWeiRaised.add(weiAmount);
    } else {
      revert();
    }

    _processPurchase(_beneficiary, tokens);
    emit TokenPurchase(
      msg.sender,
      _beneficiary,
      weiAmount,
      tokens
    );

    if (isCrowdsale) {
      crowdsaleContributions[_beneficiary] = crowdsaleContributions[_beneficiary].add(weiAmount);
      crowdsaleDeposited[_beneficiary] = crowdsaleDeposited[_beneficiary].add(msg.value);
    } else if (isPresale) {
      presaleDeposited[_beneficiary] = presaleDeposited[_beneficiary].add(msg.value);
    }
  }