contract Presale {

    using SafeMath for uint;

    uint256 public _totalSupply = 8000000000000000000000000;
    uint256 public leftSupply;
    uint256 public startTime = 1574175600; //Thursday, 19.11.2019 15:00:00
    uint256 public endTime = 1575989999;  // Thursday, 10.12.2019 14:59:59

    uint256 private tokensForEth = 2000;
    address private owner;

    ERC20 token;


    event TokenSold(address buyer,uint256 value, uint256 amount);
    event TokenLeft(uint256 amount);

    constructor() public {
        owner = msg.sender;
        leftSupply = _totalSupply;
    }

    /* Modifiers */

    //Modifier used to check if presale is open.
    function presaleOpen() private view returns (bool) {
        return (startTime <= now && endTime >= now);
    }


    //Modifier used to check if owner of contract modify contract's variables.
    modifier mustBeOwner() {
        require(msg.sender == owner, "Only owner can change price.");
        _;
    }


    /* Modifiers used to check if prices are set */


    // Method used to check if ERC20 interface is set.
    function isTokenSet() private view returns (bool){
        return(address(token) != address(0));
    }


    function isTokensForEth() private view returns (bool){
        return(tokensForEth > 0);
    }


    function isPriced(uint _price) private pure returns (bool){
        return (_price > 0);
    }

    //Modifier used to check if there are any BBD tokens in stock.
    function areTokensInStock()private view returns (bool){
        return (leftSupply > 0);
    }

    // Method used to check if presale is open.
    function isPresaleOpen() public view returns(bool) {
        return startTime <= now && endTime >= now;
    }



    /* Setters */

    //Method used to initialize ERC20 interface for BBD token.
    function setToken(address contractAddress) public mustBeOwner{
        token = ERC20(contractAddress);
    }

    //Method used to set price for 1 ETH.
    //If necessary price for 1 BBD is also set.
    function setTokensForEth(uint amount) public mustBeOwner {
        tokensForEth = amount;
    }


    function setStartTime(uint time) public mustBeOwner {
        startTime = time;
    }


    function setEndTime(uint time) public mustBeOwner {
        endTime = time;
    }


   /**
    * Fallback function
    *
    * The function without name is the default function that is called whenever anyone sends funds to a contract
    */
    function () payable external {
        if(isPresaleOpen()){
            require(isTokenSet(), "Token is not set.");
            require(isTokensForEth(), "Amount of received tokens for ETH can not be 0.");
            require(areTokensInStock(), "There are no tokens left.");
            require(isPriced(msg.value),"Value can not be 0.");

            uint256 tokens = calculateToken(msg.value);
            if(leftSupply >= tokens){
                token.transfer(msg.sender,tokens);
                uint256 supplyToSubstract = leftSupply.sub(tokens);
                leftSupply = supplyToSubstract;

                emit TokenSold(msg.sender,msg.value, tokens);
                emit TokenLeft(leftSupply);
            }
            else{
                (uint tokensWeAfford, uint refund) = calculateAffordTokenValue(msg.value);

                token.transfer(msg.sender,tokensWeAfford);
                msg.sender.transfer(refund);

                uint256 supplyToSubstract = leftSupply.sub(tokensWeAfford);
                leftSupply = supplyToSubstract;

                emit TokenSold(msg.sender, msg.value, tokensWeAfford);
                emit TokenLeft(leftSupply);
            }
        }
        else {
            revert("Presale is not open yet.");
        }
    }


    //Function used to withdraw ETH from contract
    function withdrawFromContract(address payable _recipient, uint256 _value) public mustBeOwner{
        _recipient.transfer(_value);
    }


    //Function used to withdraw ERC20 token from contract
    function withdrawTokenFromContract(address _tokenAddress, address payable _recipient, uint256 _value) public mustBeOwner{
        ERC20 _token = ERC20(_tokenAddress);
        _token.transfer(_recipient, _value);
    }


    //Function used to calculate how much BBD beneficier will receive for sent ETH.
    function calculateToken(uint _value) private view returns(uint){
        uint256 tokens = tokensForEth.mul(_value);

        return tokens;
    }

    //Function used in special case when amount of BBD is too low
    //It calculates how much BBD we can send to beneficier and how much ETH we have to refund.
    function calculateAffordTokenValue(uint _sent) private view returns(uint, uint){
        uint256 tokens = leftSupply;
        uint256 refund = _sent.sub(tokens.div(tokensForEth));

        return (tokens,refund);
    }
}
//import "github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC20/ERC20.sol";
function withdrawTokenFromContract(address _tokenAddress, address payable _recipient, uint256 _value) public mustBeOwner{
    ERC20 _token = ERC20(_tokenAddress);
    _token.transfer(_recipient, _value);
}

//Function used to withdraw ERC20 token from contract