contract ElonSpaceToken is ERC20Interface {
    using SafeMath for uint256;
    
    string public name;
    string public symbol;
    uint8 public decimals; // 18 decimals is the strongly suggested default, avoid changing it
    
    uint256 public totalSupply;
    
    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;
    mapping(address => uint) public bought;
    
    // How many token units a buyer gets per ETH
    uint256 public rate;

    // Amount of wei raised
    uint256 public weiRaised;
    
    // Address where funds are collected
    address payable wallet;

    /**
    * Event for token purchase logging
    * @param purchaser who paid for the tokens
    * @param beneficiary who got the tokens
    * @param value weis paid for purchase
    * @param amount amount of tokens purchased
    */
    event TokenPurchase(
        address indexed purchaser,
        address indexed beneficiary,
        uint256 value,
        uint256 amount,
        uint256 burned
    );
    
    /**
     * Constructor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     * _totalSupply: total number of tokens
     * _rate: Number of token units a buyer gets per ETH
     * _wallet Address where collected funds will be forwarded to
     */
     
    constructor(uint _totalSupply, uint _rate, address payable _wallet) public {
        name = "Elon Space Token";
        symbol = "EST";
        decimals = 18;
        totalSupply = _totalSupply.mul(1e18) ;
        rate = _rate;
        wallet = _wallet;
        
        balances[address(this)] = totalSupply.div(4); //presale
        emit Transfer(address(0), address(this), totalSupply.div(4));
        
        balances[0x018D9E1109f90509c64258724142052645c23255] = totalSupply.div(5); //marketing
        emit Transfer(address(0), 0x018D9E1109f90509c64258724142052645c23255, totalSupply.div(5));
        
        balances[0x81Bc4D84bfDDce167aF40b22f9CF74eA9170ee1F] = totalSupply.div(5); //community contest
        emit Transfer(address(0), 0x81Bc4D84bfDDce167aF40b22f9CF74eA9170ee1F, totalSupply.div(5));
        
        balances[0xBc8b64C34FA675a34eba6Da06F5B35a426569278] = totalSupply.div(5); //uniswap liquidity
        emit Transfer(address(0), 0xBc8b64C34FA675a34eba6Da06F5B35a426569278, totalSupply.div(5));
        
        balances[0x863510f96a03D3C8B554816FbfdC22adD59691D7] = 150000*1e18; //development
        emit Transfer(address(0), 0x863510f96a03D3C8B554816FbfdC22adD59691D7, 150000*1e18);
        
    }
    
    function balanceOf(address tokenOwner) public view returns (uint balance) {
        return balances[tokenOwner];
    }
    
    function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
        return allowed[tokenOwner][spender];
    }
    
    function approve(address spender, uint tokens) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        return true;
    }
    
    
    
    //variables to track values
    uint internal feesAmount;
    uint internal transferredAmount;
    
    function transfer(address to, uint tokens) public returns (bool success) {
        feesAmount = tokens.mul(5).div(100);
        transferredAmount = tokens.sub(feesAmount);
        
        balances[msg.sender] = balances[msg.sender].sub(tokens);
        balances[to] = balances[to].add(transferredAmount);
        //balances[address(distributor)] = balances[address(distributor)].add(feesAmount);

        _transfer(msg.sender, to);
        return true;
    }
    
    function transferFrom(address from, address to, uint tokens) public returns (bool success) {
        feesAmount = tokens.mul(5).div(100);
            
        transferredAmount = tokens.sub(feesAmount);
        
        balances[from] = balances[from].sub(tokens);
        allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
        balances[to] = balances[to].add(transferredAmount);
        //balances[address(distributor)] = balances[address(distributor)].add(feesAmount);
        
        _transfer(from, to);
        return true;
    }
    
    function _transfer(address from, address to) internal returns (bool success) {
        emit Transfer(from, to, transferredAmount);
        
        /* if(feesAmount > 0) */ emit Transfer(from, 0x0000000000000000000000000000000000000000, feesAmount);
        
        return true;
    }

  // -----------------------------------------
  // Crowdsale interface
  // -----------------------------------------

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

  /**
   * @dev low level token purchase ***DO NOT OVERRIDE***
   * @param _beneficiary Address performing the token purchase
   */
  function buyTokens(address _beneficiary) public payable {
      
    uint256 weiAmount = msg.value;
      
    require(weiAmount <= balances[address(this)], "EST in the presale ended!");
    
    require(bought[_beneficiary] <= (3*1e18), "max reached"); //max per wallet
    require(weiAmount >= (0.5*1e18), "under the minimum"); //min per wallet
    
    bought[_beneficiary] = bought[_beneficiary].add(weiAmount);

    _preValidatePurchase(_beneficiary, weiAmount);

    // calculate token amount to be created
    uint256 tokens = _getTokenAmount(weiAmount);
    
    uint256 fee = tokens.div(100);
    uint256 realTokens = tokens.sub(fee);
    
    balances[address(this)] = balances[address(this)].sub(tokens);
    balances[_beneficiary] = balances[_beneficiary].add(realTokens);

    // update state
    weiRaised = weiRaised.add(weiAmount);

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

    //_updatePurchasingState(_beneficiary, weiAmount);

    _forwardFunds();
    //_burnFees(_beneficiary, fee);
  }

  // -----------------------------------------
  // Internal interface (extensible)
  // -----------------------------------------

  /**
   * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations.
   * @param _beneficiary Address performing the token purchase
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _preValidatePurchase(
    address _beneficiary,
    uint256 _weiAmount
  )
    pure internal
  {
    require(_beneficiary != address(0));
    require(_weiAmount != 0);
    
  }

  /**
   * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
   * @param _beneficiary Address performing the token purchase
   * @param _tokenAmount Number of tokens to be emitted
   */
  function _deliverTokens(
    address _beneficiary,
    uint256 _tokenAmount,
    uint256 _feesAmount
  )
    internal
  {
    transferredAmount = _tokenAmount;
    feesAmount = _feesAmount;
    _transfer(address(this), _beneficiary);
  }

  /**
   * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
   * @param _beneficiary Address receiving the tokens
   * @param _tokenAmount Number of tokens to be purchased
   */
  function _processPurchase(
    address _beneficiary,
    uint256 _tokenAmount,
    uint256 _feesAmount
  )
    internal
  {
    _deliverTokens(_beneficiary, _tokenAmount, _feesAmount);
  }

  /**
   * @dev Override to extend the way in which ether is converted to tokens.
   * @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)
    internal view returns (uint256)
  {
    return _weiAmount.mul(rate);
  }

  /**
   * @dev Determines how ETH is stored/forwarded on purchases.
   */
  function _forwardFunds() internal {
    wallet.transfer(msg.value);
  }
  
    
}
function _deliverTokens(
  address _beneficiary,
  uint256 _tokenAmount,
  uint256 _feesAmount
)
  internal
{
  transferredAmount = _tokenAmount;
  feesAmount = _feesAmount;
  _transfer(address(this), _beneficiary);
}

/**
 * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
 * @param _beneficiary Address performing the token purchase
 * @param _tokenAmount Number of tokens to be emitted
 */