contract TheRameniers is ERC721, Ownable {  
    using Address for address;
    using Counters for Counters.Counter;

    Counters.Counter private _tokenSupply;
    
    // Starting and stopping sale and presale
    bool public saleActive = false;
    bool public presaleActive = false;

    // Price of each token
    uint256 public PRESALE_MINT_PRICE = 0.10 ether;
    uint256 public MINT_PRICE = 0.15 ether;

    uint256 public constant MAX_SUPPLY = 10000;
    uint256 public constant MAX_PRESALE_SUPPLY = 500;
    uint256 public constant RESERVED = 100;
    uint256 private totalTeam;

    constructor () ERC721 ("The Rameniers", "WAGER") {
    }
    
    // Standard mint function
    function mint() public payable {
        require(saleActive, "Sale isn't active.");
        uint256 mintIndex = _tokenSupply.current() ;
        require(mintIndex < MAX_SUPPLY, "Sale sold out");
        require(msg.value >= MINT_PRICE, "Wrong amount of ETH sent.");
        
        _tokenSupply.increment();
        _safeMint(msg.sender, mintIndex);
    }

    // Presale minting
        function presaleMint() public payable {
        require(presaleActive, "Presale isn't active.");
        uint256 mintIndex = _tokenSupply.current() ;
        require(mintIndex < MAX_PRESALE_SUPPLY, "Presale sold out");
        require(msg.value >= PRESALE_MINT_PRICE, "Wrong amount of ETH sent.");
        
        _tokenSupply.increment();
        _safeMint(msg.sender, mintIndex);
    }

    // Admin minting function to reserve tokens for the team, collabs, customs and giveaways
        function mintReserved() public onlyOwner {
        uint256 mintIndex = _tokenSupply.current() ;

        totalTeam = totalTeam+1;
        require(totalTeam <= RESERVED, "No more for the team");
        require(mintIndex < MAX_SUPPLY, "Sold out");
        
        _tokenSupply.increment();
        _safeMint(msg.sender, mintIndex);
    }

  /** URI HANDLING **/
    string private customBaseURI;

    function setBaseURI(string memory customBaseURI_) external onlyOwner {
      customBaseURI = customBaseURI_;
    }   
    
    function _baseURI() internal view virtual override returns (string memory) {
      return customBaseURI;
    }   

    function tokenURI(uint256 tokenId) public view override
      returns (string memory)
    {
      return string(abi.encodePacked(super.tokenURI(tokenId)));
    }


// ============ OWNER-ONLY ADMIN FUNCTIONS ============

    function tokensMinted() public view returns (uint256) {
        return _tokenSupply.current();
    }

    // Start and stop presale
    function setPresaleActive(bool val) public onlyOwner {
        presaleActive = val;
    }

    // Start and stop sale
    function setSaleActive(bool val) public onlyOwner {
        saleActive = val;
    }

    // Set a different preprice in case ETH changes drastically
    function setPresalePrice(uint256 newPrice) public onlyOwner {
        PRESALE_MINT_PRICE = newPrice;
    }

    // Set a different price in case ETH changes drastically
    function setSalePrice(uint256 newPrice) public onlyOwner {
        MINT_PRICE = newPrice;
    }

    /** PAYOUT **/
    function withdrawAll() external onlyOwner {
        uint256 balance = address(this).balance;
        require(balance > 0, "No ether left to withdraw");
        Address.sendValue(payable(owner()), balance);
    }

    
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721) {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721) returns (bool) {
        return super.supportsInterface(interfaceId);
    }


}
function withdrawAll() external onlyOwner {
    uint256 balance = address(this).balance;
    require(balance > 0, "No ether left to withdraw");
    Address.sendValue(payable(owner()), balance);
}

/** PAYOUT **/