// Contract: Pizza
// Target function: function tokenURI(uint256 _tokenId)
Types[0].push(Trait("Uranian Blue","Background","B5DEFF",0));
        
        //Sauce
        traitTypes[1].push(Trait("BBQ","Sauce","714c4b",0));
        traitTypes[1].push(Trait("Gold","Sauce","FECD51",0));
        traitTypes[1].push(Trait("Hot","Sauce","cd7542",0));
        traitTypes[1].push(Trait("Pesto","Sauce","7aa579",0));
        traitTypes[1].push(Trait("Tomato","Sauce","c94f49",0));
        traitTypes[1].push(Trait("White","Sauce","acacac",0));
        
        //Thickness
        traitTypes[2].push(Trait("Thin","Thickness","",0));
        traitTypes[2].push(Trait("Thick","Thickness","",0));
        
        //bg colors
        TIERS[0] = [242, 10, 954, 1007, 94, 775, 629, 333, 1393, 118];
        
        //basis colors
        TIERS[1] = [671, 10, 707, 1321, 2355, 491];
        
        //Thickness
        TIERS[2] = [2777, 2778];
        
        //Crust
        TIERS[3] = [2223, 1165, 473, 10, 256, 406, 1022];
        
        //Cheese
        TIERS[4] = [204, 1451, 550, 1239 ,2111];
        
        //Topping
        TIERS[5] = [240, 670, 507, 780, 1, 555, 1773, 30, 999];
        
        //Vegetable
        TIERS[6] = [258, 249, 302, 1420, 1793, 669, 864];
        
        //Spice
        TIERS[7] = [259, 876, 1977, 1231, 1211, 1];

        //Size
        TIERS[8] = [2663, 222, 2663, 7];        
        
        traitTypes[8].push(Trait("Large","Size","",0));
        traitTypes[8].push(Trait("Massive","Size","",0));
        traitTypes[8].push(Trait("Medium","Size","",0));
        traitTypes[8].push(Trait("Nano","Size","",0));
        
       
    }

  
    /**
     * @dev Converts a digit from 0 - 5555 into its corresponding rarity based on the given rarity tier.
     * @param _randinput The input from 0 - 5555 to use for rarity gen.
     * @param _rarityTier The tier to use.
     */
    function rarityGen(uint256 _randinput, uint8 _rarityTier)
        internal
        view
        returns (string memory)
    {
        uint16 currentLowerBound = 0;
        for (uint8 i = 0; i < TIERS[_rarityTier].length; i++) {
            uint16 thisPercentage = TIERS[_rarityTier][i];
            if (
                _randinput >= currentLowerBound &&
                _randinput < currentLowerBound + thisPercentage
            ) return i.toString();
            currentLowerBound = currentLowerBound + thisPercentage;
        }

        revert();
    }

    /**
     * @dev Generates a 9 digit hash from a tokenId, address, and random number.
     * @param _t The token id to be used within the hash.
     * @param _a The address to be used within the hash.
     * @param _c The custom nonce to be used within the hash.
     */
    function hash(
        uint256 _t,
        address _a,
        uint256 _c
    ) internal returns (string memory) {
        require(_c < 10);

        // This will generate a 9 character string.
        string memory currentHash = "";

        for (uint8 i = 0; i < 9; i++) {
            SEED_NONCE++;
            uint16 _randinput = uint16(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            block.timestamp,
                            block.difficulty,
                            _t,
                            _a,
                            _c,
                            SEED_NONCE
                        )
                    )
                ) % 5555
            );

            currentHash = string(
                abi.encodePacked(currentHash, rarityGen(_randinput, i))
            );
        }

        if (hashToMinted[currentHash]) return hash(_t, _a, _c + 1);

        return currentHash;
    }

   

    /**
     * @dev Mint internal, this is to avoid code duplication.
     */
    function mintInternal(address to, uint256 _quantity) internal {
        uint256 _totalSupply = totalSupply();
        require(totalSupply().add(_quantity) <= MAX_SUPPLY, "Public Sale Exceeded");
        require(_quantity > 0,"Quantity must be greater then zero");
        require(!Oven.isContract(to));

        
        for (uint256 i = 0; i <= _quantity; i++) {
             uint256 thisTokenId = _totalSupply + i;
             tokenIdToHash[thisTokenId] = hash(thisTokenId, to, 0);
             hashToMinted[tokenIdToHash[thisTokenId]] = true;
             _mint(to, thisTokenId);
              emit Minted(to, thisTokenId);
        }
    }



    /**
     * @dev Mints new tokens.
     */
    function bakePizza(uint256 _quantity) public payable {
        require(msg.value >= PUBLIC_MINT_PRICE, "Payment too low, try .03");
        require(totalSupply().add(_quantity) <= MAX_SUPPLY - RESERVED, "Public Sale Exceeded");
        require(balanceOf(_msgSender()) <= 20,"Max mints per wallet = 20");
        require( !_paused, "Sale paused");
            return mintInternal(_msgSender(), _quantity);
    }
    
    /**
     * @dev Private Mint.
     */
    function privateMint() public {
        require( 1 <= RESERVED, "Exceeds reserved supply" );
        require( totalSupply().add(1) <= MAX_SUPPLY, "Supply Exceeded");
        require(isWhitelisted(_msgSender()) == true, "Not Whitelisted");
        _privateSaleWhitelist[_msgSender()] = false;
        RESERVED -= 1;
        return mintInternal(_msgSender(), 1);
    }
    


    /*
 ____     ___   ____  ___        _____  __ __  ____     __ ______  ____  ___   ____   _____
|    \   /  _] /    ||   \      |     ||  |  ||    \   /  ]      ||    |/   \ |    \ / ___/
|  D  ) /  [_ |  o  ||    \     |   __||  |  ||  _  | /  /|      | |  ||     ||  _  (   \_ 
|    / |    _]|     ||  D  |    |  |_  |  |  ||  |  |/  / |_|  |_| |  ||  O  ||  |  |\__  |
|    \ |   [_ |  _  ||     |    |   _] |  :  ||  |  /   \_  |  |   |  ||     ||  |  |/  \ |
|  .  \|     ||  |  ||     |    |  |   |     ||  |  \     | |  |   |  ||     ||  |  |\    |
|__|\_||_____||__|__||_____|    |__|    \__,_||__|__|\____| |__|  |____|\___/ |__|__| \___|
                                                                                           
*/

   
   /**
     * @dev Helper function to reduce pixel size within contract
     */
    function letterToNumber(string memory _inputLetter)
        internal
        view
        returns (uint8)
    {
        for (uint8 i = 0; i < LETTERS.length; i++) {
            if (Oven.compareStrings((LETTERS[i]),_inputLetter))
               return (i);
        }
        revert();
    }
    
    
    function isWhitelisted(address _from) public view returns (bool) {
        return _privateSaleWhitelist[_from];
    }
    
    /**
     * @dev Hash to SVG function
     */
    function hashToSVG(string memory _hash)
        public
        view
        returns (string memory)
    {
        string memory svgString;
        string memory bgRect;
        string memory basisRect;
        string memory crustRect;
        string memory crustColor;
        
        
        bgRect = string(
                    abi.encodePacked(
                        '<rect class="bg" fill="#',
                        traitTypes[0][Oven.parseInt(Oven.substring(_hash, 0, 1))].pixels,
                        '"/>'
                    )
                );
                
        basisRect = string(
                    abi.encodePacked(
                        '<circle fill="#',
                        traitTypes[1][Oven.parseInt(Oven.substring(_hash, 1, 2))].pixels,
                        '" cx="12" cy="12" r="9.9" />'
                    )
                );
                
        
             
        if(Oven.compareStrings(traitTypes[2][Oven.parseInt(Oven.substring(_hash, 2, 3))].traitName, "Thick")){  
             crustColor = string(
                    abi.encodePacked('c',
                    Oven.substring(traitTypes[3][Oven.parseInt(Oven.substring(_hash, 3, 4))].pixels, 14, 16)
                    )
                );
                
            crustRect = string(
                    abi.encodePacked(
                            '<rect x="0" y="9" class="a p"/><rect x="1" y="7" class="b o"/><rect x="2" y="5" class="c n"/><rect x="3" y="4" class="d m"/><rect x="4" y="3" class="e l"/><rect x="5" y="2" class="f k"/><rect x="7" y="1" class="g j"/><rect x="9" y="0" class="h i"/>'
                    )
                );
            }
        
        for (uint8 i = 2; i < 8; i++) {
            uint8 thisTraitIndex = Oven.parseInt(
                Oven.substring(_hash, i, i + 1)
            );

            for (
                uint16 j = 0;
                j < traitTypes[i][thisTraitIndex].pixelCount;
                j++
            ) {
                
                string memory thisPixel;
                
                if(j <= traitTypes[i][thisTraitIndex].pixelCount - 1){
                 thisPixel = Oven.substring(
                    traitTypes[i][thisTraitIndex].pixels,
                    j * 4,
                    j * 4 + 4
                );
                

                uint8 x = letterToNumber(
                    Oven.substring(thisPixel, 0, 1)
                );
                uint8 y = letterToNumber(
                    Oven.substring(thisPixel, 1, 2)
                );

                
                svgString = string(
                    abi.encodePacked(
                        svgString,
                        "<rect class='c",
                        Oven.substring(thisPixel, 2, 4),
                        "' x='",
                        x.toString(),
                        "' y='",
                        y.toString(),
                        "'/>"
                    )
                );

                }
            }
        
        }

        svgString = string(
            abi.encodePacked(
                '<svg id="pizza-svg" class="',
                crustColor,
                '" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 48 48">',
                bgRect,
                '<g transform="matrix(1 0 0 1 12 12)">',
                crustRect,
                basisRect,
                svgString,
                '</g><style>rect {width: 1px;height: 1px;}#pizza-svg {shape-rendering: crispedges;}.bg {width: 100%;height: 100%}.z{fill:#590a01}..c00{fill:#c2d7cf}.c01{fill:#aabeb6}.c02{fill:#ed8126}.c03{fill:#ecf69e}.c04{fill:#708848}.c05{fill:#efffd4}.c06{fill:#b45230}.c07{fill:#d36d4a}.c08{fill:#63363a}.c09{fill:#6a160a}.c10{fill:#903e20}.c11{fill:#b6742f}.c12{fill:#d59049}.c13{fill:#590a01}.c14{fill:#6b2e09}.c15{fill:#915a1f}.c16{fill:#2e2e2e}.c17{fill:#393939}.c18{fill:#171717}.c19{fill:#232323}.c20{fill:#acbfd3}.c21{fill:#b8cce0}.c22{fill:#d1d9da}.c23{fill:#98a9b4}.c24{fill:#a3b2c4}.c25{fill:#c5a51f}.c26{fill:#e5c339}.c27{fill:#856900}.c28{fill:#744e00}.c29{fill:#9e8412}.c30{fill:#dfc6a7}.c31{fill:#ecd2b2}.c32{fill:#d0c4c2}.c33{fill:#bfa897}.c34{fill:#cfbba0}.c35{fill:#373737}.c36{fill:#837554}.c37{fill:#9f906e}.c38{fill:#3a241b}.c39{fill:#483925}.c40{fill:#665a3e}.c41{fill:#466930}.c42{fill:#779a61}.c43{fill:#fffae1}.c44{fill:#311500}.c45{fill:#2d2a26}.c46{fill:#821003}.c47{fill:#4e1e03}.c48{fill:#864420}.c49{fill:#862520}.c50{fill:#ff7244}.c51{fill:#9a4025}.c52{fill:#db8e2e}.c53{fill:#efca66}.c54{fill:#7c1f1f}.c55{fill:#9a4126}.c56{fill:#b85805}.c57{fill:#ce402a}.c58{fill:#b75704}.c59{fill:#7e1d13}.c60{fill:#620f06}.c61{fill:#e4bc0e}.c62{fill:#e4d20e}.c63{fill:#91112c}.c64{fill:#ba193a}.c65{fill:#d7f66a}.c66{fill:#f6ea6a}.c67{fill:#2d7717}.c68{fill:#366028}.c69{fill:#e6d7d7}.c70{fill:#c7bfac}.c71{fill:#131913}.c72{fill:#c74833}.c73{fill:#e99a8c}',
                '.a{width:24px}.b{width:22px}.c{width:20px}.d{width:18px}.e{width:16px}.f{width:14px}.g{width:10px}.h{width:6px}.i{height:24px}.j{height:22px}.k{height:20px}.l{height:18px}.m{height:16px}.n{height:14px}.o{height:10px}.p{height:6px}',
                '</style></svg>'
         )
        );
        

        return svgString;
    }



    /**
     * @dev Hash to metadata function
     */
    function hashToMetadata(string memory _hash)
        public
        view
        returns (string memory)
    {
        string memory metadataString;

        for (uint8 i = 0; i < 9; i++) {
            uint8 thisTraitIndex = Oven.parseInt(
                Oven.substring(_hash, i, i + 1)
            );

            metadataString = string(
                abi.encodePacked(
                    metadataString,
                    '{"trait_type":"',
                    traitTypes[i][thisTraitIndex].traitType,
                    '","value":"',
                    traitTypes[i][thisTraitIndex].traitName,
                    '"}'
                )
            );

            if (i != 8)
                metadataString = string(abi.encodePacked(metadataString, ","));
        }

        return string(abi.encodePacked("[", metadataString, "]"));
    }