contract CrazyMummiez is ERC721Enum, Ownable, ReentrancyGuard {
    using Strings for uint256;
    string public baseURI;
    //sale settings
    uint256 public cost = 0.1 ether;
    uint256 public maxSupply = 3333;
    uint256 public maxClaim = 3333;
    uint256 public maxMint = 3;
    uint256 public requiredParentTokensForClaim = 3;
    bool public status = false;
    ParentContractInterface parentContractInterface;

    mapping(uint256 => bool) _claimedParents;

    //presale settings
    constructor(
        string memory _name,
        string memory _symbol,
        string memory _initBaseURI,
        address _parentContractAddress
    ) ERC721P(_name, _symbol) {
        parentContractInterface = ParentContractInterface(_parentContractAddress);
        setBaseURI(_initBaseURI);
    }
    // internal
    function _baseURI() internal view virtual returns (string memory) {
        return baseURI;
    }
    // public minting
    function mint(uint256 _mintAmount) public payable nonReentrant{
        uint256 s = totalSupply();
        require(status, "Off" );
        require(_mintAmount > 0, "Duh" );
        require(_mintAmount <= maxMint, "Too many" );
        require(s + _mintAmount < maxSupply, "Sorry" );
        require(msg.value >= cost * _mintAmount);
        for (uint256 i = 0; i < _mintAmount; ++i) {
            _safeMint(msg.sender, s + i, "");
        }
        delete s;
    }

    // admin minting
    function gift(uint[] calldata quantity, address[] calldata recipient) external onlyOwner{
        require(quantity.length == recipient.length, "Provide quantities and recipients" );
        uint totalQuantity = 0;
        uint256 s = totalSupply();
        for(uint i = 0; i < quantity.length; ++i){
            totalQuantity += quantity[i];
        }
        require( s + totalQuantity <= maxSupply, "Too many" );
        delete totalQuantity;
        for(uint i = 0; i < recipient.length; ++i){
            for(uint j = 0; j < quantity[i]; ++j){
                _safeMint( recipient[i], s++, "" );
            }
        }
        delete s;
    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: Nonexistent token");
        string memory currentBaseURI = _baseURI();
        return bytes(currentBaseURI).length > 0	? string(abi.encodePacked(currentBaseURI, tokenId.toString(), '.json')) : "";
    }
    function setCost(uint256 _newCost) public onlyOwner {
        cost = _newCost;
    }
    function setMaxMintAmount(uint256 _newMaxMintAmount) public onlyOwner {
        maxMint = _newMaxMintAmount;
    }
    function setMaxSupply(uint256 _newMaxSupply) public onlyOwner {
        maxSupply = _newMaxSupply;
    }
    function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseURI = _newBaseURI;
    }
    function setSaleStatus(bool _status) public onlyOwner {
        status = _status;
    }
    function withdraw() public onlyOwner {
        uint balance = address(this).balance;
        payable(msg.sender).transfer(balance);
    }

    function isClaimed (uint256 id) public view returns (bool) {
        return _claimedParents[id];
    }

    function claimByIds(uint256[] memory ids) public {
        require(status, "Claiming is not active at the moment");
        require(ids.length % requiredParentTokensForClaim == 0, "You require 3 tokens in order to claim a Mummy");
        for (uint256  i = 0; i < ids.length; i++) {
            address owner = parentContractInterface.ownerOf(ids[i]);
            require(owner == msg.sender, "You do not own the token with the provided id");
            require(!isClaimed(ids[i]), "The token has been already claimed");
        }

        for (uint256  i = 0; i < ids.length; i = i + requiredParentTokensForClaim) {
            _safeMint(msg.sender, totalSupply());
            _claimedParents[ids[i]] = true;
            _claimedParents[ids[i + 1]] = true;
            _claimedParents[ids[i + 2]] = true;
        }
    }

}
function mint(uint256 _mintAmount) public payable nonReentrant{
    uint256 s = totalSupply();
    require(status, "Off" );
    require(_mintAmount > 0, "Duh" );
    require(_mintAmount <= maxMint, "Too many" );
    require(s + _mintAmount < maxSupply, "Sorry" );
    require(msg.value >= cost * _mintAmount);
    for (uint256 i = 0; i < _mintAmount; ++i) {
        _safeMint(msg.sender, s + i, "");
    }
    delete s;
}

// public minting