contract FunkyOstriches is ERC721Enumerable, Ownable {  
    using Address for address;
    
    // Sale state
    bool public saleIsActive = false;

    // Reserved for the team, customs, giveaways, collabs and so on.
    uint256 public reserved = 100;

    // Price of each token
    uint256 public price = 0.04 ether;

    // Maximum limit of tokens that can ever exist
    uint256 constant MAX_SUPPLY = 7500;

    // The base link that leads to the image / video of the token
    string public baseTokenURI;

      
    // Withdraw address
    address withdrawAddress = 0x6b95C8AC63B16376cf137c28d065932f2236CbC0;


    constructor (string memory newBaseURI) ERC721 ("Funky Ostriches", "OSTRICH") {
        setBaseURI(newBaseURI);
    }

    // Override so the openzeppelin tokenURI() method will use this method to create the full tokenURI instead
    function _baseURI() internal view virtual override returns (string memory) {
        return baseTokenURI;
    }

    // See which address owns which tokens
    function tokensOfOwner(address addr) public view returns(uint256[] memory) {
        uint256 tokenCount = balanceOf(addr);
        uint256[] memory tokensId = new uint256[](tokenCount);
        for(uint256 i; i < tokenCount; i++){
            tokensId[i] = tokenOfOwnerByIndex(addr, i);
        }
        return tokensId;
    }


    // Standard mint function
    function mint(uint256 _amount) public payable {
        uint256 supply = totalSupply();
        require( saleIsActive,                     "Sale isn't active" );
        require( _amount > 0 && _amount < 16,     "Can only mint between 1 and 15 tokens at once" );
        require( (supply + _amount) <= (MAX_SUPPLY - reserved), "Purchase would exceed maximum supply" );
        require( msg.value == price * _amount,   "Wrong amount of ETH sent" );
        for(uint256 i; i < _amount; i++){
            _safeMint( msg.sender, supply + i );
        }
    }
    
    // Admin minting function to reserve tokens for the team, collabs, customs and giveaways
    function mintReserved(address _to, uint256 _amount) public onlyOwner {
        // Limited to a publicly set amount
        require( _amount <= reserved, "Can't reserve more than set amount" );
        reserved -= _amount;
        uint256 supply = totalSupply();
        for(uint256 i; i < _amount; i++){
            _safeMint( _to, supply + i );
        }
    }


    /*
     *  Sale state
     */
    function pauseSale() public onlyOwner() {
        require(saleIsActive == true, "Sale is already paused");
        saleIsActive = false;
    }

    function startSale() public onlyOwner() {
        require(saleIsActive == false, "Sale has already started");
        saleIsActive = true;
    }

    // Set new baseURI
    function setBaseURI(string memory baseURI) public onlyOwner {
        baseTokenURI = baseURI;
    }

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

    /*
     *  Withdraw
     */
    function withdraw() public onlyOwner {
        uint balance = address(this).balance;
        require(payable(withdrawAddress).send(balance));
    }
}
function setPrice(uint256 newPrice) public onlyOwner {
        price = newPrice;
    }
// Set a different price in case ETH changes drastically