contract UNHUMAN is Ownable, ERC721URIStorage {

    // Keep a mapping of token ids and corresponding IPFS hashes
    mapping(string => uint8) hashes;
    // Maximum amounts of mintable tokens
    uint256 public constant MAX_SUPPLY = 777;
    // Address of the royalties recipient
    address private _royaltiesReceiver;
    // Percentage of each sale to pay as royalties
    uint256 public constant royaltiesPercentage = 10;

    mapping (address => uint) public artBalance;
    mapping (uint => bytes32) public storedData;

    // Events
    event Mint(uint256 tokenId, address recipient);

constructor(address initialRoyaltiesReceiver) ERC721("UNHUMAN COMPOSITIONS", "UNHUMAN") {
        _royaltiesReceiver = initialRoyaltiesReceiver;
        artBalance[address(this)] = MAX_SUPPLY;
        
    }

    /** Overrides ERC-721's _baseURI function */
    function _baseURI() internal pure override returns (string memory) {
        return 'data:application/json;base64,';
    }

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

    function _burn(uint256 tokenId)
    internal override(ERC721URIStorage) {
        super._burn(tokenId);
    }

    /// @notice Getter function for _royaltiesReceiver
    /// @return the address of the royalties recipient
    function royaltiesReceiver() external view returns(address) {
        return _royaltiesReceiver;
    }

    /// @notice Changes the royalties' recipient address (in case rights are
    ///         transferred for instance)
    /// @param newRoyaltiesReceiver - address of the new royalties recipient
    function setRoyaltiesReceiver(address newRoyaltiesReceiver)
    external onlyOwner {
        require(newRoyaltiesReceiver != _royaltiesReceiver); // dev: Same address
        _royaltiesReceiver = newRoyaltiesReceiver;
    }

    /// @notice Returns a token's URI
    /// @dev See {IERC721Metadata-tokenURI}.
    /// @param tokenId - the id of the token whose URI to return
    /// @return a string containing an URI pointing to the token's ressource
    function tokenURI(uint256 tokenId)
    public view override(ERC721URIStorage)
    returns (string memory) {
        return super.tokenURI(tokenId);
    }

    /// @notice Informs callers that this contract supports ERC2981
    function supportsInterface(bytes4 interfaceId)
    public view override(ERC721)
    returns (bool) {
        return interfaceId == type(IERC2981).interfaceId ||
        super.supportsInterface(interfaceId);
    }


    /// @notice Returns all the tokens owned by an address
    /// @param _owner - the address to query
    /// @return ownerTokens - an array containing the ids of all tokens
    ///         owned by the address
    

    /// @notice Called with the sale price to determine how much royalty
    //          is owed and to whom.
    /// @param _tokenId - the NFT asset queried for royalty information
    /// @param _salePrice - sale price of the NFT asset specified by _tokenId
    /// @return receiver - address of who should be sent the royalty payment
    /// @return royaltyAmount - the royalty payment amount for _value sale price
    function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view
    returns (address receiver, uint256 royaltyAmount) {
        uint256 _royalties = (_salePrice * royaltiesPercentage) / 100;
        return (_royaltiesReceiver, _royalties);
    }

    function mint(string memory coords, uint256 noObjects, uint256 noColors, uint[] memory colors) external payable {
        require(mintingActive || msg.sender == owner(), "Minting is paused");
        require(msg.value >= 100000000000000000 wei, "You must pay at least 0.1 Eth per art");
        require(artBalance[address(this)]+1 >= 1, "Not enough art in stock to complete this purchase");
        _safeMint(msg.sender, MAX_SUPPLY-artBalance[address(this)]+1);
        _setCoords(MAX_SUPPLY-artBalance[address(this)]+1, coords);
        _setNoObjects(MAX_SUPPLY-artBalance[address(this)]+1, noObjects);
        _setNoColors(MAX_SUPPLY-artBalance[address(this)]+1, noColors);
        _setColors(MAX_SUPPLY-artBalance[address(this)]+1, colors); 
        
        artBalance[address(this)] -= 1;
        artBalance[msg.sender] += 1;
    }


    function setMintingActive(bool isMintingActive) public onlyOwner {
        mintingActive = isMintingActive;
    }

    function withdraw(uint amount) onlyOwner public returns(bool) {
        require(amount <= address(this).balance);
        address someone = msg.sender;
        payable(someone).transfer(amount);
        return true;
    }
}
/**
 * @title Sample NFT contract
 * @dev Extends ERC-721 NFT contract and implements ERC-2981
 */
function royaltiesReceiver() external view returns(address) {
    return _royaltiesReceiver;
}

/// @notice Getter function for _royaltiesReceiver
/// @return the address of the royalties recipient