contract GOATzAccessUtilityToken is ERC721, Ownable {
    using SafeMath for uint256;

    uint256 public totalAccessTokenMinted;

    constructor (string memory _tokenBaseUri) ERC721("GOATz Access Utility Token", "GAUT") {
        _setBaseURI(_tokenBaseUri);
    }

    ////////////////////
    // Action methods //
    ////////////////////

	function claimAccessToken(bytes calldata _data) external {
        (,, uint256[] memory _unclaimedToken,,,) = abi.decode(_data, (bytes, address, uint256[], uint256, bytes, string));
        uint256 length = _unclaimedToken.length;
	    require(length > 0, "Minimum 1 tokens need to be claimed");
		for (uint256 i = 0; i < length; i++) {
			_mintAccessToken(_msgSender());
		}
	}
    
    function _mintAccessToken(address _to) private {
        totalAccessTokenMinted++;
        require(!_exists(totalAccessTokenMinted), "Mint: Token already exist.");
        _mint(_to, totalAccessTokenMinted);
        _setTokenURI(totalAccessTokenMinted, "metadata");
    }

    function mintAccessToken(address _to) external onlyOwner {
		_mintAccessToken(_to);
    }

    function burn(uint256 _tokenId) external {
        require(_exists(_tokenId), "Burn: token does not exist.");
        require(ownerOf(_tokenId) == _msgSender(), "Burn: caller is not token owner.");
        _burn(_tokenId);
    }

    ///////////////////
    // Query methods //
    ///////////////////

    function exists(uint256 _tokenId) external view returns (bool) {
        return _exists(_tokenId);
    }

    function isUnclaimed(uint256 _tokenId) external view returns (bool) {
        return _exists(_tokenId);
    }

    function isApprovedOrOwner(address _spender, uint256 _tokenId) external view returns (bool) {
        return _isApprovedOrOwner(_spender, _tokenId);
    }

    /////////////
    // Setters //
    /////////////

    function withdrawETH(uint256 _amount) external onlyOwner {
        payable(owner()).transfer(_amount);
    }

    function setTokenURI(uint256 _tokenId, string memory _uri) external onlyOwner {
        _setTokenURI(_tokenId, _uri);
    }

    function setBaseURI(string memory _baseURI) external onlyOwner {
        _setBaseURI(_baseURI);
    }

    function _beforeTokenTransfer(address _from, address _to, uint256 _tokenId) internal virtual override(ERC721) {
        super._beforeTokenTransfer(_from, _to, _tokenId);
    }
}
function withdrawETH(uint256 _amount) external onlyOwner {
        payable(owner()).transfer(_amount);
    }
/////////////