contract TreumHolidayERC721 is ERC721, ERC721Burnable, Ownable {
    constructor(string memory name, string memory symbol) public ERC721(name, symbol) {}

    uint256 public mintPrice = 0.1 ether;

    mapping(bytes32 => uint256) public tokenURIHashToId;

    uint256 private _totalMinted = 0; // Needed since totalSupply -= 1 on burns()

    bool private _enabled = true;

    function _hashURI(string memory tokenURI) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(tokenURI));
    }

    function tokenIdFromURI(string memory tokenURI) public view returns (uint256) {
        return tokenURIHashToId[_hashURI(tokenURI)];
    }

    function _mapTokenURIToId(string memory tokenURI, uint256 tokenId) internal {
        uint256 existingTokenId = tokenIdFromURI(tokenURI);
        require(existingTokenId == 0, "Token already exists for tokenURI");
        tokenURIHashToId[_hashURI(tokenURI)] = tokenId;
    }

    /**
     * @dev Function to mint tokens: uri must be is unique and msg.value sufficient
     * @param to The address that will receive the minted tokens.
     * @param tokenURI The token URI of the minted token.
     * @return A boolean that indicates if the operation was successful.
     */
    function mintWithTokenURI(address to, string memory tokenURI) public payable returns (bool) {
        require(_enabled == true, "Minting has been disabled");

        // Confirm payment
        require(msg.value == mintPrice, "");

        uint256 tokenId = ++_totalMinted;

        require(bytes(tokenURI).length > 0, "Invalid tokenURI");

        // Set and validate tokenURI unique
        _mapTokenURIToId(tokenURI, tokenId);

        _mint(to, tokenId);
        _setTokenURI(tokenId, tokenURI);
        return true;
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }

    function setPrice(uint256 newMintPrice) public onlyOwner {
        mintPrice = newMintPrice;
    }

    // Owner can withdraw contract ETH balance at any time
    function withdraw() public onlyOwner {
        msg.sender.transfer(address(this).balance);
    }

    // Owner can disable the minting by setting this flag
    /**
     * @dev Function to enable/disable token minting
     * @param enabled The flag to turn minting on or off
     */
    function setEnabled(bool enabled) public onlyOwner {
        _enabled = enabled;
    }
}
function withdraw() public onlyOwner {
    msg.sender.transfer(address(this).balance);
}

// Owner can withdraw contract ETH balance at any time