// Contract: TacosForAdventurers
// Target function: function claim(uint256 tokenId) public nonReentrant
 the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}
contract tacoDrawing {
    
    function _getTacoDrawing() internal pure returns (string memory) {
        
        
        string memory svg = string(abi.encodePacked(

            '<g transform="translate(70,40) scale(1.8)"><polygon id="TortillaFront" class="cls-1" points="29.56 80.48 0.88 75.68 8.17 36.13 52.68 0.86 94.81 18.25 29.56 80.48"/>',
              '<polygon id="Protein" class="cls-2" points="13.79 75.05 11.52 70.02 8.06 66.04 9.7 59.82 8.06 52.99 21.95 39.24 31.85 27.72 60.21 27.21 30.57 76.5 24.21 78.22 19.48 75.99 13.79 75.05"/>'
              '<polygon id="Sauce" class="cls-3" points="13.27 40.78 7.96 46.1 13.14 53.67 20.51 51.63 27.02 56.3 36.19 52.27 37.52 17.88 21.71 31.6 13.27 40.78"/>',
              '<polygon id="Veggie" class="cls-4" points="23.57 30.82 14.11 28.23 21.41 18.35 27.05 23.18 25.43 14.58 34 11.98 35.99 21.06 39.1 12.1 43.83 12.79 43.99 20.43 54.66 15.58 63.15 18.83 52.58 26.48 56.23 37.29 46.58 41.06 42.84 44.7 35.81 36.2 37.33 44.45 25.88 46.38 28.06 36.7 23.67 40.98 14.11 35.53 23.57 30.82"/>',
              '<polygon id="TortillaBack" class="cls-1" points="29.56 80.48 37.77 35.34 76.91 5.1 110.01 24.16 122.46 60.03 83.5 73.33 29.56 80.48"/>',
              '<g id="garnish">',
                
                  '<rect class="cls-5" x="135.54" y="84.92" width="4.2" height="4.2" transform="matrix(0.82, -0.57, 0.57, 0.82, -134.49, 38.87)"/>',
                  '<path d="M138,85.15l1.54,2.21L137.3,88.9l-1.54-2.22L138,85.15m.38-2.09-4.68,3.25L136.92,91l4.68-3.25-3.25-4.68Z" transform="translate(-109.44 -55.14)"/>',
                  '<rect class="cls-5" x="145.88" y="82.09" width="4.2" height="4.2" transform="translate(-74.54 156.33) rotate(-78.02)"/>',
                  '<path d="M146.94,82.59l2.64.56L149,85.79l-2.64-.56.56-2.64m-1.16-1.77-1.18,5.57,5.57,1.18L151.36,82l-5.58-1.18Z" transform="translate(-109.44 -55.14)"/>',
                  '<rect class="cls-5" x="148.04" y="75.25" width="4.2" height="4.2" transform="translate(-127.84 11.31) rotate(-23.56)"/>',
                  '<path d="M150.84,75.57,151.92,78l-2.48,1.08-1.07-2.47,2.47-1.08m.77-2-5.22,2.27,2.28,5.22,5.22-2.27-2.28-5.22Z" transform="translate(-109.44 -55.14)"/>',
                  '<rect class="cls-5" x="136.82" y="76.84" width="4.2" height="4.2" transform="translate(-94.3 124.85) rotate(-68.84)"/>',
                  '<path d="M138.14,77.2l2.52,1-1,2.52-2.51-1,1-2.51m-.85-1.94-2.06,5.31,5.31,2.06,2.06-5.31-5.31-2.06Z" transform="translate(-109.44 -55.14)"/>',
                    '</g></g>',
            '</svg>'
        ));
    
        return svg;
      }
}

contract TacosForAdventurers is ERC721Enumerable, ReentrancyGuard, Ownable, tacoDrawing {
    using ToColor for bytes3;

        string[] private sideEffect = [
        "Diarrhea",
        "Nausea",
        "Indigestion",
        "Heartburn",
        "MeatSweat",
        "Drowsiness",
        "Gas",
        "Obesity",
        "Cancer",
        "Stomach Ulcers",
        "Acid Reflux",
        "Fiery Poop",
        "Bat Plague"
    ];
    
    string[] private magicEffect = [
        "Fire breathing",
        "Thunderbolt",
        "Flash",
        "Warp",
        "Poison",
        "Frost Breath",
        "Blizzard",
        "Holy Light",    
        "Ice Spike",
        "Avalanche",
        "Wind Scythe",
        "Gust",
        "Fire Whip"
    ];
    
    string[] private stat = [
        "Strength",
        "Constitution",
        "Dexterity",
        "Intelligence",
        "Wisdom",
        "Charisma"
    ];
    

    
    string[] private suffixes = [
        "of Power",
        "of Giants",
        "of Mice",
        "of Skill",
        "of Perfection",
        "of Brilliance",
        "of Anger",
        "of Rage",
        "of Fury",
        "of Bats",
        "of the Angels",
        "of Volcanoes",
        "of the Sea",
        "of the Ox",
        "of Light"
    ];
    
    string[] private namePrefixes = [
        "Explosive", "Fiery", "Spicy", "Glowing", "Bloody", "Glorious", "Sharp", "Jagged", "Sloppy", "Slippery", "Giant", "Twisted", "Noisy", "Silent",
        "Hard", "Painful", "Mortal", "Orgasmic", "Pleasant", "Speedy", "Slow", "Turbulent", "Deep", "Wistful", "Damning", "Shimmering", "Endless", "Stinky", 
        "Shimmery", "Steady", "Revolutionary", "Pious", "Distressed", "Gratifying", "Perplexing", "Filthy", "Sticky", "Messy", "Creamy", "Fragmented", "Billowing", "Incendiary",
        "Starry", "Colossal", "Shameful", "Fantastic", "Odd", "Putrid", "Wicked", "Super", "Weak", "Mediocre", "Sore", "Terrible", "Tough", "Wild",
        "Aching", "Aggravating", "Ambitious", "Anguished", "Awkward", "Belated", "Brisk", "Coarse", "Critical", "Cumbersome", "Dazzling", "Deafening", "Dense", "Double",   
        "Ultra","Minor", "Major", "Dismal", "Filthy", "Guilty", "Hideous", "Humuliating", "Irritating", "Itchy", "Juicy", "Kaleidoscope", "Shattered", "Mysterious"
    ];
    
   
    function random(string memory input) internal pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(input)));
    }
    
    function getSideEffect(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "EFFECT", sideEffect);
    }
    
    function getMagicEffect(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "MAGIC", magicEffect);
    }
    
    function getStat(uint256 tokenId) public view returns (string memory) {
        uint256 rand = random(string(abi.encodePacked('STAT', toString(tokenId))));
        string memory output = stat[rand % stat.length];
        uint256 greatness = rand % 10;
        if(greatness == 0){
            return string(abi.encodePacked(output, " +1"));
        } else {
            return string(abi.encodePacked(output, " +", toString(greatness)));
        }

        
    }
    function randomColor(string memory input, string memory input2) internal pure returns (bytes3) {
        bytes3 color;

        bytes32 predictableRandom = keccak256(abi.encodePacked(input, input2));
        color = bytes2(predictableRandom[0]) | ( bytes2(predictableRandom[1]) >> 8 ) | ( bytes3(predictableRandom[2]) >> 16 );
        return color;


    }
    
    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 % 15;
        if (greatness > 5) {
            output = string(abi.encodePacked(output, " ", suffixes[rand % suffixes.length]));
        }
        if (greatness >= 13) {
            string[2] memory name;
            name[0] = namePrefixes[rand % namePrefixes.length];

            if (greatness == 13) {
                output = string(abi.encodePacked(name[0], " ", output));
            } else {
                output = string(abi.encodePacked(name[0], " ", output, " +1"));
            }
        }
        return output;
    }


    function tokenURI(uint256 tokenId) override public view returns (string memory) {
        require(tokenId < 3001, "Theres no such Taco in existance");
        string[10] memory color;
        
        
        color[0] = '<svg id="Taco" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 350"> <defs><style>.base { fill: white; font-family: monospace; font-size: 11px; }.cls-1 {fill: #';
        
        color[1] = randomColor("TortillaFront", toString(tokenId)).toColor();
        
        color[2] = '}.cls-1, .cls-2, .cls-3, .cls-4 {stroke: #000;stroke-miterlimit: 10;stroke-width: 1.5px;}.cls-2 {fill: #';

        color[3] = randomColor("Protein", toString(tokenId)).toColor();
        
        color[4] = '}.cls-3 {fill: #';
        
        color[5] = randomColor("Sauce", toString(tokenId)).toColor();
        
        color[6] = '}.cls-4 {fill: #';
        
        color[7] = randomColor("Veggie", toString(tokenId)).toColor();
        
        color[8] = '}.cls-5 {fill: #';
        
        color[9] = randomColor("TortillaBack", toString(tokenId)).toColor();
        
        string[7] memory svgText;
        
        svgText[0] = '}</style></defs><rect width="100%" height="100%" fill="#1d1d1d" /> <text x="50%" y="59%" class="base" text-anchor="middle">Magic Spell :</text><text x="50%" y="63%" class="base" text-anchor="middle">';

        svgText[1] = getMagicEffect(tokenId);

        svgText[2] ='</text><text x="50%" y="74%" class="base" text-anchor="middle">Stat Modifier :</text><text x="50%" y="78%" class="base" text-anchor="middle">';

        svgText[3] = getStat(tokenId);

        svgText[4] = '</text><text x="50%" y="89%" class="base" text-anchor="middle">Side Effect :</text><text x="50%" y="93%" class="base" text-anchor="middle">';

        svgText[5] = getSideEffect(tokenId);

        svgText[6] = '</text>';
        
        string memory output = string(abi.encodePacked(color[0], color[1], color[2], color[3], color[4]));
        
        output = string(abi.encodePacked(output, color[5], color[6], color[7], color[8], color[9]));

        string memory outputText = string(abi.encodePacked(svgText[0], svgText[1], svgText[2], svgText[3]));

        outputText = string(abi.encodePacked(outputText, svgText[4], svgText[5], svgText[6]));
        
        string memory outputMerge = string(abi.encodePacked(output, outputText));

        string memory Taco = _getTacoDrawing();

        outputMerge = string(abi.encodePacked(outputMerge, Taco));
        
        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "Taco #', toString(tokenId), '", "description": "Tacos for adventurers are generated and stored on chain. Each Taco has a magic power granted and stat modifiers, however... they have side effects, functionality are for others to interpret. Feel free to use these Tacos in any way you want.", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(outputMerge)), '"}'))));
        output = string(abi.encodePacked('data:application/json;base64,', json));

        return output;
    }