contract CARTELLOOTCRATES is Ownable, ERC721Enumerable, ReentrancyGuard {
    using SafeMath for uint256;

    string public CARTEL_LOOTS_PROVENANCE = "";
    string public LICENSE_TEXT = ""; 
    string public BASE_URI = "";
    uint256 public RESERVE = 10;

    uint256 public constant PRICE = 0 ether;
    uint256 public constant PURCHASE_LIMIT = 20;
    uint256 public constant MAX_CARTEL_LOOTS = 10000;
    uint256 public totalPublicSupply;

    bool public saleIsActive = false;
    bool public licenseLocked = false; 

    event licenseisLocked(string _licenseText);

    constructor() ERC721("CARTELLOOTCRATES", "CARTELLOOT") {}

    function withdraw() public onlyOwner {
        sendValueTo(msg.sender, address(this).balance);
    }

    function sendValueTo(address to_, uint256 value) internal {
        address payable to = payable(to_);
        (bool success, ) = to.call{value: value}("");
        require(success, "Transfer failed.");
    }

    // SALE ACTIVE FLAGS
    function flipSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }

    // BASE URI
    function _baseURI() internal view override returns (string memory) {
        return BASE_URI;
    }

    function setBaseURI(string memory baseURI_) public onlyOwner {
        BASE_URI = baseURI_;
    }

    function setProvenanceHash(string memory provenanceHash) public onlyOwner {
        CARTEL_LOOTS_PROVENANCE = provenanceHash;
    }

    // LICENSE
    function tokenLicense(uint256 _id) public view returns (string memory) {
        require(_id < totalSupply(), "CHOOSE TOKEN WITHIN RANGE");
        return LICENSE_TEXT;
    }

    function lockLicense() public onlyOwner {
        licenseLocked = true;
        emit licenseisLocked(LICENSE_TEXT);
    }

    function changeLicense(string memory _license) public onlyOwner {
        require(licenseLocked == false, "License already locked");
        LICENSE_TEXT = _license;
    }

    function claim(uint256 numberOfTokens) public payable nonReentrant {
        require(saleIsActive, 'Contract is not active');
        require(totalSupply().add(numberOfTokens) <= MAX_CARTEL_LOOTS, 'All tokens have been minted');
        require(numberOfTokens > 0 && numberOfTokens <= PURCHASE_LIMIT, 'Would exceed PURCHASE_LIMIT');

        for (uint256 i = 0; i < numberOfTokens; i++) {
            if (totalPublicSupply < MAX_CARTEL_LOOTS) {
                uint256 tokenId = totalPublicSupply + 1;
                totalPublicSupply += 1;
                _safeMint(msg.sender, tokenId);
            }
        }
    }

    function tokensOfOwner(address _owner) external view returns (uint256[] memory)
    {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
            // Return an empty array
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](tokenCount);
            uint256 index;
            for (index = 0; index < tokenCount; index++) {
                result[index] = tokenOfOwnerByIndex(_owner, index);
            }
            return result;
        }
    }
}
function flipSaleState() public onlyOwner {
    saleIsActive = !saleIsActive;
}

// SALE ACTIVE FLAGS