contract Crowns is ERC721, Ownable {

    using SafeMath for uint256;
    using Strings for uint256;

    // Time when the claim starts.
    uint256 public sale_start_timestamp = 1627661808;
    bool public paused = false;

    // Maximum amount of Crowns in existance. 
    uint256 public constant MAX_CROWNS_SUPPLY = 8888 + 10;

    address public constant FAMELADYSQUAD = 0xf3E6DbBE461C6fa492CeA7Cb1f5C5eA660EB1B47;

    constructor(string memory name, string memory symbol, string memory baseURI) ERC721(name, symbol) {
        _setBaseURI(baseURI);

        for (uint256 i = 0; i < 10; i++) {
            _safeMint(msg.sender, uint256(8888) + i);
        }
    }

    // Shows if a lady can claim a crown
    function canClaim(uint256 tokenId) view public returns (bool) {
        return !_exists(tokenId);
    }

    // Returns amount of crowns available for claim
    function getMintableTokenNumber(address user) view public returns (uint256 mintableTokenNumber) {
        mintableTokenNumber = 0;
        for (uint256 i = 0; i < IERC721Enumerable(FAMELADYSQUAD).balanceOf(user); i++) {
            uint256 tokenId = IERC721Enumerable(FAMELADYSQUAD).tokenOfOwnerByIndex(user, i);
            if (canClaim(tokenId))
                mintableTokenNumber++;
        }
        return mintableTokenNumber;
    }

    // Claim crowns                          
    function mintCrowns(uint256 numberOfTokens) public {
        // Some exceptions that need to be handled.
        require(!paused, "Claim has not started yet");
        require(block.timestamp <= sale_start_timestamp + 5 * 86400, "Claim has finished");
        require(numberOfTokens <= 10, "You can't claim more than 10 crowns in one tx");
        require(numberOfTokens > 0, "You can't claim 0 Crowns");
        // it requires a lot of gas for view call. a user won't get a revert or an error, only a null tx with claiming as much as it can(if getMintableTokenNumber is 0 then tx won't mint any NFTs)
        //require(numberOfTokens <= getMintableTokenNumber(msg.sender), "You can't claim more than you can claim");

        uint256 j = 0;
        for (uint256 i = 0; i < IERC721Enumerable(FAMELADYSQUAD).balanceOf(msg.sender); i++) {
            uint256 tokenId = IERC721Enumerable(FAMELADYSQUAD).tokenOfOwnerByIndex(msg.sender, i);
            if (canClaim(tokenId)) {
                _safeMint(msg.sender, tokenId);
                j++;
            }
            if (j == numberOfTokens) {
                break;
            }
        }
    }

    /**
    * @dev Changes the base URI if we want to move things in the future (Callable by owner only)
    */
    function changeBaseURI(string memory baseURI) onlyOwner public {
       _setBaseURI(baseURI);
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        return string(abi.encodePacked(baseURI(), tokenId.toString()));
    }

    function pause() onlyOwner public {
        paused = !paused;
    }

    function setNewSaleTimestamp(uint256 new_sale_start_timestamp) onlyOwner public {
        sale_start_timestamp = new_sale_start_timestamp;
    }

}
function getMintableTokenNumber(address user) view public returns (uint256 mintableTokenNumber) {
    mintableTokenNumber = 0;
    for (uint256 i = 0; i < IERC721Enumerable(FAMELADYSQUAD).balanceOf(user); i++) {
        uint256 tokenId = IERC721Enumerable(FAMELADYSQUAD).tokenOfOwnerByIndex(user, i);
        if (canClaim(tokenId))
            mintableTokenNumber++;
    }
    return mintableTokenNumber;
}

// Returns amount of crowns available for claim