contract Crowdsale is ReentrancyGuard, PriceReceiver, Ownable {
    using SafeMath for uint256;

    // The token being sold
    IERC20 private _token;

    // Address where funds are collected
    address payable private _wallet;

    // Amount of wei raised
    uint256 private _weiRaised;

    // Price of 1 ether in USD Cents
    uint256 private _currentETHPrice;

    // How many token units a buyer gets per 1 USD Cent
    uint256 private _rate;

    // Minimum amount of wei to invest
    uint256 private _minimum = 0.5 ether;

    event TokensPurchased(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
    event NewETHPrice(uint256 oldValue, uint256 newValue);

    /**
     * @param rate Number of token units a buyer gets per wei
     * @param initialETHPrice Price of Ether in USD Cents
     * @param wallet Address where collected funds will be forwarded to
     * @param token Address of the token being sold
     */
    constructor (uint256 rate, uint256 initialETHPrice, address payable wallet, IERC20 token, address initialOwner) public Ownable(initialOwner) {
        require(rate != 0, "Rate is 0");
        require(initialETHPrice != 0, "Initial ETH price is 0");
        require(wallet != address(0), "Wallet is the zero address");
        require(address(token) != address(0), "Token is the zero address");

        _rate = rate;
        _currentETHPrice = initialETHPrice;
        _wallet = wallet;
        _token = token;
    }

    /**
     * @dev fallback function
     */
    function() external payable {
        buyTokens(msg.sender);
    }

    /**
     * @dev low level token purchase
     * This function has a non-reentrancy guard
     * @param beneficiary Recipient of the token purchase
     */
    function buyTokens(address beneficiary) public nonReentrant payable {
        require(beneficiary != address(0), "Beneficiary is the zero address");
        require(msg.value >= _minimum, "Wei amount is less than 0.5 ether");

        uint256 weiAmount = msg.value;

        uint256 tokens = getTokenAmount(weiAmount);

        _weiRaised = _weiRaised.add(weiAmount);

        _wallet.transfer(weiAmount);

        _token.transfer(beneficiary, tokens);

        emit TokensPurchased(msg.sender, beneficiary, weiAmount, tokens);
    }

    /**
     * @dev Calculate amount of tokens to recieve for a given amount of wei
     * @param weiAmount Value in wei to be converted into tokens
     * @return Number of tokens that can be purchased with the specified _weiAmount
     */
    function getTokenAmount(uint256 weiAmount) public view returns(uint256) {
        return weiAmount.mul(_currentETHPrice).div(1 ether).mul(_rate);
    }

    /**
     * @dev Function to change the rate.
     * Available only to the owner.
     * @param newRate new value.
     */
    function setRate(uint256 newRate) external onlyOwner {
        require(newRate != 0, "New rate is 0");

        _rate = newRate;
    }

    /**
     * @dev Function to change the PriceProvider address.
     * Available only to the owner.
     * @param provider new address.
     */
    function setEthPriceProvider(address provider) external onlyOwner {
        require(provider != address(0), "Provider is the zero address");

        ethPriceProvider = provider;
    }

    /**
     * @dev Function to change the address to receive ether.
     * Available only to the owner.
     * @param newWallet new address.
     */
    function setWallet(address payable newWallet) external onlyOwner {
        require(newWallet != address(0), "New wallet is the zero address");

        _wallet = newWallet;
    }

    /**
     * @dev Function to change the ETH Price.
     * Available only to the owner and to the PriceProvider.
     * @param newPrice amount of USD Cents for 1 ether.
     */
    function receiveEthPrice(uint256 newPrice) external {
        require(newPrice != 0, "New price is 0");
        require(msg.sender == ethPriceProvider || msg.sender == _owner, "Sender has no permission");

        emit NewETHPrice(_currentETHPrice, newPrice);
        _currentETHPrice = newPrice;
    }

    /**
    * @dev Allows to any owner of the contract withdraw needed ERC20 token from this contract (promo or bounties for example).
    * @param ERC20Token Address of ERC20 token.
    * @param recipient Account to receive tokens.
    */
    function withdrawERC20(address ERC20Token, address recipient) external onlyOwner {

        uint256 amount = IERC20(ERC20Token).balanceOf(address(this));
        IERC20(ERC20Token).transfer(recipient, amount);

    }

    /**
     * @return the token being sold.
     */
    function token() public view returns (IERC20) {
        return _token;
    }

    /**
     * @return the address where funds are collected.
     */
    function wallet() public view returns (address payable) {
        return _wallet;
    }

    /**
     * @return the number of token units a buyer gets per wei.
     */
    function rate() public view returns (uint256) {
        return _rate;
    }

    /**
     * @return the price of 1 ether in USD Cents.
     */
    function currentETHPrice() public view returns (uint256) {
        return _currentETHPrice;
    }

    /**
     * @return minimum amount of wei to invest.
     */
    function minimum() public view returns (uint256) {
        return _minimum;
    }

    /**
     * @return the amount of wei raised.
     */
    function weiRaised() public view returns (uint256) {
        return _weiRaised;
    }

}
/**
 * @title Crowdsale contract
 * @author https://grox.solutions
 */
function receiveEthPrice(uint256 newPrice) external {
    require(newPrice != 0, "New price is 0");
    require(msg.sender == ethPriceProvider || msg.sender == _owner, "Sender has no permission");

    emit NewETHPrice(_currentETHPrice, newPrice);
    _currentETHPrice = newPrice;
}

/**
 * @dev Function to change the ETH Price.
 * Available only to the owner and to the PriceProvider.
 * @param newPrice amount of USD Cents for 1 ether.
 */