// Contract: ApesOnChain
// Target function: function getTraits(Ape memory ape) internal view returns (string memory)
     * @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();
    }
}

// Bring on the ApesOnChain!
contract ApesOnChain is ERC721Enumerable, ReentrancyGuard, Ownable {
  using Strings for uint256;

  uint256 public constant maxSupply = 3500;
  uint256 public numClaimed = 0;
  string[] private background = ["1eb","dda","e92","656","663","9de","367","ccc"]; // only trait that is uniform, no need for rarity weights
  string[] private fur1 = ["444","532","653","a71","ffc","ca9","f89","777","049","901","fc5","ffe","574","bcc","d04","222","889","7f9","fd1"];
  string[] private fur2 = ["344","653","653","653","110","653","653","653","653","653","344","653","711","110","799","555","8a8","32f","110"];
  uint8[] private fur_w =[249, 246, 223, 141, 116, 114, 93, 90, 89, 86, 74, 28, 55, 48, 39, 32, 72, 14, 8];
  string[] private eyes = ["888","0a0","653","653","be7","abe","0a0","653","888","be7","cef","abe","0a0","653","888","be7","cef","abe","0a0","abe","888","be7","cef"];
  uint8[] private eyes_w = [68, 121, 107, 101, 33, 78, 70, 245, 62, 58, 56, 51, 50, 48, 44, 38, 35, 79, 31, 22, 15, 10, 7];
  string[] private mouth = ["bcc","049","f89","777","ffc","901","653","d04","fd1","ffc","bcc","f89","777","049","049","901","901","bcc","653","d04","ffc","f89","bcc","049","fd1","f89","777","bcc","d04","049","ffc","901","fd1"];
  uint8[] private mouth_w = [252, 172, 80, 10, 27, 49, 37, 33, 31, 30, 28, 56, 26, 23, 22, 18, 15, 14, 13, 12, 11, 79, 10, 10, 9, 8, 7, 7, 6, 5, 5, 4, 3];
  string[] private earring = ["999","fe7","999","999","fe7","bdd"];
  uint8[] private earring_w = [251, 32, 29, 17, 16, 8, 5];
  string[] private clothes1 = ["222","f00","222","f00","f00","f00","90f","f00","90f","00f","00f","00f","00f","00f","00f","00f","222","00f","f0f","222","f0f","f0f","f0f","f0f","f0f","f0f","f0f","f80","f80","f80","f80","f80","f00","f80","f80","f80","90f","90f","00f","90f","00f","90f","222"];
  string[] private clothes2 = ["ddd","00f","f00","f0f","f80","ddd","f48","0f0","ff0","f0f","00d","f0f","f80","90f","f48","0f0","ddd","ff0","f00","653","00f","d0d","f80","90f","f48","0f0","ff0","f00","f0f","00f","d60","f48","ddd","90f","0f0","ff0","f00","00f","fd1","f0f","f80","70d","fd1"];
  uint8[] private clothes_w = [251, 55, 31, 43, 38, 37, 34, 33, 32, 31, 31, 31, 45, 45, 30, 30, 29, 29, 28, 27, 27, 27, 26, 25, 24, 22, 21, 20, 19, 19, 19, 19, 19, 19, 18, 17, 16, 15, 14, 13, 11, 9, 8, 6];
  string[] private hat1 = ["ff0","f80","f00","f00","90f","f80","f00","00f","00f","00f","00f","00f","00f","00f","f00","f00","f0f","f0f","f0f","f00","f00","f0f","f80","f80","f80","f80","22d","f80","f00","f80","90f","f48","22d","90f","90f","ff0",""];
  string[] private hat2 = ["0f0","00f","f80","ff0","f80","f0f","f48","f00","0f0","00f","f80","ff0","90f","f80","000","f00","0f0","00f","f80","000","90f","f0f","90f","f80","00f","f80","ff0","90f","f00","f0f","f00","000","000","0f0","00f","f48",""];  
  uint8[] private hat_w = [36, 64, 47, 42, 39, 38, 251, 35, 34, 34, 33, 29, 28, 26, 26, 25, 25, 25, 22, 21, 20, 20, 18, 17, 17, 15, 14, 14, 13, 13, 12, 12, 12, 10, 9, 8, 7];
  string[] private z = ['<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 500 500"><rect x="0" y="0" width="500" height="500" style="fill:#',
    '"/><rect width="300" height="120" x="99" y="400" style="fill:#', '"/><circle cx="190" cy="470" r="5" style="fill:#', '"/><circle cx="310" cy="470" r="5" style="fill:#',
    '"/><circle cx="100" cy="250" r="50" style="fill:#', '"/><circle cx="100" cy="250" r="20" style="fill:#', '"/><circle cx="400" cy="250" r="50" style="fill:#',
    '"/><circle cx="400" cy="250" r="20" style="fill:#', '"/><circle cx="250" cy="250" r="150" style="fill:#', '"/><circle cx="250" cy="250" r="120" style="fill:#',
    '"/><circle cx="200" cy="215" r="35" style="fill:#fff"/><circle cx="305" cy="222" r="31" style="fill:#fff"/><circle cx="200" cy="220" r="20" style="fill:#',
    '"/><circle cx="300" cy="220" r="20" style="fill:#', '"/><circle cx="200" cy="220" r="7" style="fill:#000"/><circle cx="300" cy="220" r="7" style="fill:#000"/>',
    '<ellipse cx="250" cy="315" rx="84" ry="34" style="fill:#',
     '"/><rect x="195" y="330" width="110" height="3" style="fill:#000"/><circle cx="268" cy="295" r="5" style="fill:#000"/><circle cx="232" cy="295" r="5" style="fill:#000"/>',
    '</svg>'];
  string private cross='<rect x="95" y="275" width="10" height="40" style="fill:#872"/><rect x="85" y="285" width="30" height="10" style="fill:#872"/>';
  string private clo1='<rect width="300" height="120" x="99" y="400" style="fill:#';
  string private clo2='"/><rect width="50" height="55" x="280" y="430" style="fill:#';
  string private hh1='<rect width="200" height="99" x="150" y="40" style="fill:#';
  string private hh2='"/><rect width="200" height="33" x="150" y="106" style="fill:#';
  string private sl1='<rect x="150" y="190" width="200" height="30" style="fill:#';
  string private sl2='"/><rect x="160" y="170" width="180" height="50" style="fill:#';
  string private mou='<line x1="287" y1="331" x2="320" y2="366" style="stroke:#000;stroke-width:5"/>';
  string private ey1='<rect x="160" y="190" width="75" height="15" style="fill:#';
  string private ey2='"/><rect x="275" y="190" width="65" height="15" style="fill:#';
  string private ey3='<rect x="160" y="235" width="180" height="50" style="fill:#';
  string private zz='"/>';
  string private ea1='<circle cx="100" cy="290" r="14" style="fill:#';
  string private ea2='fe7';
  string private ea3='999';
  string private ea4='"/><circle cx="100" cy="290" r="4" style="fill:#000"/>';
  string private ea5='<circle cx="100" cy="290" r="12" style="fill:#';
  string private ea6='bdd';
  string private mo1='<line x1="';
  string private mo2='" y1="307" x2="';
  string private mo3='" y2="312" style="stroke:#000;stroke-width:2"/>';
  string private mo4='" y1="317" x2="';
  string private mo5='" y2="322" style="stroke:#000;stroke-width:2"/>';
  string private tr1='", "attributes": [{"trait_type": "Background","value": "';
  string private tr2='"},{"trait_type": "Fur","value": "';
  string private tr3='"},{"trait_type": "Earring","value": "';
  string private tr4='"},{"trait_type": "Hat","value": "';
  string private tr5='"},{"trait_type": "Eyes","value": "';
  string private tr6='"},{"trait_type": "Clothes","value": "';
  string private tr7='"},{"trait_type": "Mouth","value": "';
  string private tr8='"}],"image": "data:image/svg+xml;base64,';
  string private ra1='A';
  string private ra2='C';
  string private ra3='D';
  string private ra4='E';
  string private ra5='F';
  string private ra6='G';
  string private co1=', ';
  string private rl1='{"name": "Ape On Chain #';
  string private rl3='"}';
  string private rl4='data:application/json;base64,';

  struct Ape { 
    uint8 bg;
    uint8 fur;
    uint8 eyes;
    uint8 mouth;
    uint8 earring;
    uint8 clothes;
    uint8 hat;
  }

  // this was used to create the distributon of 3,500 and tested for uniqueness for the given parameters of this collection
  function random(string memory input) internal pure returns (uint256) {
    return uint256(keccak256(abi.encodePacked(input)));
  }

  function usew(uint8[] memory w,uint256 i) internal pure returns (uint8) {
    uint8 ind=0;
    uint256 j=uint256(w[0]);
    while (j<=i) {
      ind++;
      j+=uint256(w[ind]);
    }
    return ind;
  }

  function randomOne(uint256 tokenId) internal view returns (Ape memory) {
    tokenId=12839-tokenId; // avoid dupes
    Ape memory ape;
    ape.bg = uint8(random(string(abi.encodePacked(ra1,tokenId.toString()))) % 8);
    ape.fur = usew(fur_w,random(string(abi.encodePacked(clo1,tokenId.toString())))%1817);
    ape.eyes = usew(eyes_w,random(string(abi.encodePacked(ra2,tokenId.toString())))%1429);
    ape.mouth = usew(mouth_w,random(string(abi.encodePacked(ra3,tokenId.toString())))%1112);
    ape.earring = usew(earring_w,random(string(abi.encodePacked(ra4,tokenId.toString())))%358);
    ape.clothes = usew(clothes_w,random(string(abi.encodePacked(ra5,tokenId.toString())))%1329);
    ape.hat = usew(hat_w,random(string(abi.encodePacked(ra6,tokenId.toString())))%1111);
    if (tokenId==7403) {
      ape.hat++; 
    }
    return ape;
  }