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

    if(funders[_address].active && _value >= funders[_address].amount){
      uint bufferTokens = funders[_address].amount.mul((uint)(10).pow(decimals))/tokenPrice;
      bufferTokens = bufferTokens.add(bufferTokens.mul(funders[_address].bonus)/100);

      uint bufferEth = _value.sub(funders[_address].amount);
      bufferTokens = bufferTokens.add(bufferEth.mul((uint)(10).pow(decimals))/tokenPrice); 

      token.sendCrowdsaleTokens(_address,bufferTokens);
      
      ethCollected = ethCollected.add(_value);

      if (ethCollected >= ICO_MIN_CAP){
        distributionAddress.transfer(address(this).balance.sub(oraclizeBalance));
      }
      funders[_address].active = false;

      emit OnSuccessBuy(_address, _value, 0, bufferTokens);
      return true;
    }

    uint bonusPercent = 0;

    ethCollected = ethCollected.add(_value);

    uint tokensToSend = (_value.mul((uint)(10).pow(decimals))/tokenPrice);

    if (currentPhase == 1){
      require (_value >= PRE_ICO_MIN_DEPOSIT);

      bonusPercent = getPreIcoBonus(_value);

      tokensToSend = tokensToSend.add(tokensToSend.mul(bonusPercent)/100);

      require (ethCollected.add(_value) <= PRE_ICO_MAX_CAP);

      if (ethCollected >= PRE_ICO_MIN_CAP){
        distributionAddress.transfer(address(this).balance.sub(oraclizeBalance));
      }

    }else if(currentPhase == 2){
      require (_value >= ICO_MIN_DEPOSIT);

      contributorEthCollected[_address] = contributorEthCollected[_address].add(_value);

      bonusPercent = getIcoBonus();

      tokensToSend = tokensToSend.add(tokensToSend.mul(bonusPercent)/100);

      if (ethCollected >= ICO_MIN_CAP){
        distributionAddress.transfer(address(this).balance.sub(oraclizeBalance));
      }
    }

    token.sendCrowdsaleTokens(_address,tokensToSend);

    emit OnSuccessBuy(_address, _value, bonusPercent, tokensToSend);

    return true;
  }