function buy (address _address, uint _value, uint _time, uint _bonus, bool _manually) internal returns(bool) {
    uint8 currentPhase = getPhase(_time);
    require (currentPhase != 0);

    uint tokensToSend;

    ethCollected = ethCollected.add(_value);

    if (currentPhase == 1){
      tokensToSend = _value.mul((uint)(10).pow(decimals))/(currentExchangePrice*8/100);
      tokensToSend = tokensToSend.add(tokensToSend.mul(_bonus)/100);

      if(tokensToSend.add(privateStageTokensSold) <= PRIVATE_STAGE_MAX_CAP){
        privateStageTokensSold = privateStageTokensSold.add(tokensToSend);
        tokensSold = tokensSold.add(tokensToSend);

        distributionAddress.transfer(address(this).balance);
      }else{
        return false;
      }

    }else if(currentPhase == 2){
      tokensToSend = _value.mul((uint)(10).pow(decimals))/(currentExchangePrice*15/100);
      tokensToSend = tokensToSend.add(tokensToSend.mul(_bonus)/100);

      if(tokensToSend.add(preIcoTokensSold) <= PRE_ICO_MAX_CAP){
        preIcoTokensSold = preIcoTokensSold.add(tokensToSend);
        tokensSold = tokensSold.add(tokensToSend);

        distributionAddress.transfer(address(this).balance);
      }else{
        return false;
      }

    }else if(currentPhase == 3){
      uint icoDiscount = getIcoDiscount();

      tokensToSend = _value.mul((uint)(10).pow(decimals))/((currentExchangePrice*24/100).sub((currentExchangePrice*24/100).mul(icoDiscount)/100));
      tokensToSend = tokensToSend.add(tokensToSend.mul(_bonus)/100);

      if(ethCollected/currentExchangePrice <= ICO_MAX_CAP){
        icoTokensSold = icoTokensSold.add(tokensToSend);
        tokensSold = tokensSold.add(tokensToSend);

        if(_manually){
          contributorEthCollected[_address] = contributorEthCollected[_address].add(_value);
        }
        if (ethCollected/currentExchangePrice >= ICO_MIN_CAP){
          distributionAddress.transfer(address(this).balance);
        }
      }else{
        return false;
      }
    }
    

    token.sendCrowdsaleTokens(_address, tokensToSend);
    return true;
  }