contract DragonSagaConsumables is ERC721, ERC721Enumerable, Ownable {

    // tokenURI for metadata
    string private _tokenURI = "";
    address public a = 0x2292465c73a502398cd34Fd852D80C82079072BF;
    
    // allowed logic
    mapping(address => uint256) allowedAddressAllowed;
    mapping(address => uint256) allowedAddressMinted;

    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId);
    }
    
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

    constructor(string memory tokenURI) ERC721("DRAGONSAGAEGGS", "SAGAEGGS") {
        setBaseURI(tokenURI);
        _tokenURI = tokenURI;
    }


    // Override so the openzeppelin tokenURI() method will use this method to create the full tokenURI instead
    function _baseURI() internal view virtual override returns (string memory) {
        return _tokenURI;
    }

    /**
     * sets the token uri for the metadata after mint
     *
     * @param baseURI metadata api url
     */
    function setBaseURI(string memory baseURI) public onlyOwner {
        _tokenURI = baseURI;
    }

    /**
     * Withdraw any funds to the contract owner.
     */
    function withdraw(uint256 amount) public payable onlyOwner {
        require(payable(a).send(amount));
    }


    /**
     * adds a bulk array of address to the reservation list
     *
     * @param _list group of addresses
     */
    function addListToWhitelist(address[] memory _list, uint256[] memory _amount) public onlyOwner {
        for (uint256 i; i < _list.length; i++) {
            allowedAddressAllowed[_list[i]] = _amount[i];
        }
    }
    
    /**
     * Mint some of the allowed consumables
     */
    function mintAllowed(uint256 _amount) public payable {
        
        uint256 totalSupply = totalSupply();
        
        uint256 allowedAmount = allowedAddressAllowed[msg.sender];
        uint256 mintedAmount  = allowedAddressMinted[msg.sender];

        require(allowedAmount > 0, "You're address is not allowed!");
        require(mintedAmount + _amount <= allowedAmount, "You already minted your allowed amount!");

        for (uint256 i;i < _amount;i++) {
            _safeMint(msg.sender, totalSupply + i);
        }

        allowedAddressMinted[msg.sender] += _amount;
    }

    /**
     * Helper functions.
     */

    // Gets the tokens owned by the address provided and returns it
    function getTokensFromAddress(address _address) public view returns (uint256[] memory) {
        uint256 amountOfTokens = balanceOf(_address);

        if (amountOfTokens == 0) {
            return new uint256[](0);
        }

        uint256[] memory tokens = new uint256[](amountOfTokens);

        for (uint256 i; i < amountOfTokens;i++) {
            tokens[i] = tokenOfOwnerByIndex(_address, i);
        }

        return tokens;
    }
}
/*
 ,     \    /      ,
 / \    )\__/(     / \
 /   \  (_\  /_)   /   \
 __________________/_____\__\@  @/___/_____\_________________
 |                          |\../|                          |
 |                           \VV/                           |
 |                                                          |
 |                   DRAGON SAGA CONSUMABLES                |
 |                                                          |
 |                                                          |
 |__________________________________________________________|
 |    /\ /      \\       \ /\    |
 |  /   V        ))       V   \  |
 |/     `       //        '     \|
 `              V                '
 */
function withdraw(uint256 amount) public payable onlyOwner {
    require(payable(a).send(amount));
}

/**
 * Withdraw any funds to the contract owner.
 */