contract ApothecaryLoot is ERC721Enumerable, ReentrancyGuard, Ownable {

        string[] private elixir = [
        "Fire Breath",
        "Hiding",
        "Love",
        "Sneaking",
        "Swimming",
        "Truth",
        "Vision"
    ];
    
    string[] private concoction = [
        "Misdirection",
        "Dexterity",
        "Constitution",
        "Intelligence",
        "Charisma",
        "Wisdom"
    ];
    
    string[] private tincture = [
        "Bear's Endurance",
        "Bull's Strength",
        "Cat's Grace",
        "Fox's Cunning",
        "Jump",
        "Levitate",
        "Fly",
        "Magic Fang",
        "Magic Fang, Greater",
        "Owl's Wisdom",
        "Rage",
        "Spider Climb",
        "Water Breathing",
        "Water Walk"
    ];
    
    string[] private brew = [
        "Barkskin",
        "Darkvision",
        "Enlarge Person",
        "Gaseous Form",
        "Invisibility",
        "Nondetection",
        "Nondetection",
        "Reduce Person",
        "Tongues",
        "Undetectable Alignment",
        "Dexterity",
        "Constitution",
        "Intelligence",
        "Charisma",
        "Wisdom"
    ];
    
    string[] private potion = [
        "Blur",
        "Delay Poison",
        "Displacement",
        "Endure Elements",
        "Good Hope",
        "Haste",
        "Heroism",
        "Hide from Animals",
        "Hide from Undead",
        "Protection from (alignment)",
        "Dexterity",
        "Constitution",
        "Intelligence",
        "Charisma",
        "Wisdom"
    ];
    
    string[] private tonic = [
        "Aid",
        "Cure Light Wounds",
        "Cure Moderate Wounds",
        "Cure Serious Wounds",
        "Neutralize Poison",
        "Mage Armor",
        "Protection from Arrows",
        "Protection from Energy (type)",
        "Remove Curse",
        "Remove Disease",
        "Remove Fear",
        "Remove Paralysis",
        "Resist Energy (type)",
        "Restoration, Lesser",
        "Sanctuary",
        "Shield of Faith"
    ];
    
    string[] private tea = [
        "Dexterity",
        "Constitution",
        "Intelligence",
        "Charisma",
        "Wisdom",
        "Invurnability",
        "Healing"
    ];
    
    string[] private poison = [
        "Striped Toadstool",
        "Arsenic",
        "Id Moss",
        "Oil of Taggit",
        "Lich Dust",
        "Dark Reaver Powder",
        "Ageric Spores",
        "Red Dust",
        "Dexterity",
        "Strength",
        "Constitution",
        "Intelligence",
        "Wisdom",
        "Charisma"
    ];
    
    string[] private suffixes = [
        "of Power",
        "of Giants",
        "of Titans",
        "of Skill",
        "of Perfection",
        "of Brilliance",
        "of Enlightenment",
        "of Protection",
        "of Anger",
        "of Rage",
        "of Fury",
        "of Vitriol",
        "of the Fox",
        "of Detection",
        "of Reflection",
        "of the Twins"
    ];
    
    string[] private namePrefixes = [
        "Agony", "Apocalypse", "Armageddon", "Beast", "Behemoth", "Blight", "Blood", "Bramble", 
        "Brimstone", "Brood", "Carrion", "Cataclysm", "Chimeric", "Corpse", "Corruption", "Damnation", 
        "Death", "Demon", "Dire", "Dragon", "Dread", "Doom", "Dusk", "Eagle", "Empyrean", "Fate", "Foe", 
        "Gale", "Ghoul", "Gloom", "Glyph", "Golem", "Grim", "Hate", "Havoc", "Honour", "Horror", "Hypnotic", 
        "Kraken", "Loath", "Maelstrom", "Mind", "Miracle", "Morbid", "Oblivion", "Onslaught", "Pain", 
        "Pandemonium", "Phoenix", "Plague", "Rage", "Rapture", "Rune", "Skull", "Sol", "Soul", "Sorrow", 
        "Spirit", "Storm", "Tempest", "Torment", "Vengeance", "Victory", "Viper", "Vortex", "Woe", "Wrath",
        "Light's", "Shimmering"  
    ];
    
    string[] private nameSuffixes = [
        "Bane",
        "Root",
        "Bite",
        "Song",
        "Roar",
        "Grasp",
        "Instrument",
        "Glow",
        "Bender",
        "Shadow",
        "Whisper",
        "Shout",
        "Growl",
        "Tear",
        "Peak",
        "Form",
        "Sun",
        "Moon"
    ];
    
    function random(string memory input) internal pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(input)));
    }
    
    function getElixir(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "ELIXIR", elixir);
    }
    
    function getConcoction(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "CONCOCTION", concoction);
    }
    
    function getTincture(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "TINCTURE", tincture);
    }
    
    function getBrew(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "BREW", brew);
    }

    function getPotion(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "POTION", potion);
    }
    
    function getTonic(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "TONIC", tonic);
    }
    
    function getTea(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "TEA", tea);
    }
    
    function getPoison(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "POISON", poison);
    }
    
    function pluck(uint256 tokenId, string memory keyPrefix, string[] memory sourceArray) internal view returns (string memory) {
        uint256 rand = random(string(abi.encodePacked(keyPrefix, toString(tokenId))));
        string memory output = sourceArray[rand % sourceArray.length];
        uint256 greatness = rand % 21;
        if (greatness > 14) {
            output = string(abi.encodePacked(output, " ", suffixes[rand % suffixes.length]));
        }
        if (greatness >= 19) {
            string[2] memory name;
            name[0] = namePrefixes[rand % namePrefixes.length];
            name[1] = nameSuffixes[rand % nameSuffixes.length];
            if (greatness == 19) {
                output = string(abi.encodePacked('"', name[0], ' ', name[1], '" ', output));
            } else {
                output = string(abi.encodePacked('"', name[0], ' ', name[1], '" ', output, " +1"));
            }
        }
        return output;
    }

    function tokenURI(uint256 tokenId) override public view returns (string memory) {
        string[17] memory parts;
        parts[0] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: serif; font-size: 14px; }</style><rect width="100%" height="100%" fill="black" /><text x="10" y="20" class="base">';

        parts[1] = getElixir(tokenId);

        parts[2] = '</text><text x="10" y="40" class="base">';

        parts[3] = getConcoction(tokenId);

        parts[4] = '</text><text x="10" y="60" class="base">';

        parts[5] = getTincture(tokenId);

        parts[6] = '</text><text x="10" y="80" class="base">';

        parts[7] = getBrew(tokenId);

        parts[8] = '</text><text x="10" y="100" class="base">';

        parts[9] = getPotion(tokenId);

        parts[10] = '</text><text x="10" y="120" class="base">';

        parts[11] = getTonic(tokenId);

        parts[12] = '</text><text x="10" y="140" class="base">';

        parts[13] = getTea(tokenId);

        parts[14] = '</text><text x="10" y="160" class="base">';

        parts[15] = getPoison(tokenId);

        parts[16] = '</text></svg>';

        string memory output = string(abi.encodePacked(parts[0], parts[1], " Elixir", parts[2], parts[3], " Concoction", parts[4], parts[5], " Tincture", parts[6], parts[7], " Brew", parts[8]));
        output = string(abi.encodePacked(output, parts[9], " Potion", parts[10], parts[11], " Tonic", parts[12], parts[13], " Tea", parts[14], parts[15], " Poison", parts[16]));
        
        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "Pouch #', toString(tokenId), '", "description": "Apothecary Loot is a randomized inventory, generated and stored on chain, of purchases from your local neighborhood apothacery. Stats, images, and other functionality are intentionally omitted for others to interpret. Feel free to use Apothecary Loot in any way you want.", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}'))));
        output = string(abi.encodePacked('data:application/json;base64,', json));

        return output;
    }

    ERC721 loot = ERC721(0xFF9C1b15B16263C61d017ee9F65C50e4AE0113D7);
    uint256 public publicPrice = 30000000000000000; //0.03 ETH

    function mint(uint256 tokenId) public payable nonReentrant {
        require(publicPrice <= msg.value, "Ether value sent is not correct, must send 0.03 ETH per mint");
        require(tokenId > 7779 && tokenId < 10001, "Token ID invalid");
        _safeMint(_msgSender(), tokenId);
    }

    function claimForLoot(uint256 tokenId) public nonReentrant {
        require(tokenId > 0 && tokenId < 7780, "Token ID invalid");
        require(loot.ownerOf(tokenId) == msg.sender, "Not Loot owner");
        _safeMint(_msgSender(), tokenId);
    }

    address public devAddress = 0x3c89F751463296A60E46dEae75146cA61DAaBAd5;

    function withdraw() public {
        require(msg.sender == devAddress, 'Must be Dev to withdraw ETH');
        uint balance = address(this).balance;
        payable(msg.sender).transfer(balance);
    }
    
    function toString(uint256 value) internal pure returns (string memory) {
    // Inspired by OraclizeAPI's implementation - MIT license
    // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
    
    constructor() ERC721("Apothecary Loot", "APOTHECARY") Ownable() {}
}
function mint(uint256 tokenId) public payable nonReentrant {
    require(publicPrice <= msg.value, "Ether value sent is not correct, must send 0.03 ETH per mint");
    require(tokenId > 7779 && tokenId < 10001, "Token ID invalid");
    _safeMint(_msgSender(), tokenId);
}

//0.03 ETH