contract cRGB is ERC721Enumerable, ReentrancyGuard, Ownable{
  using Strings for uint256;
  
  uint256 public cost = 0.005 ether;
  address payable private _passch;
  address payable private _holstein;
    
  int colorId;
  int public Red;
  int public Green;
  int public Blue;
  int public bgRed;
  int public bgGreen;
  int public bgBlue;

  constructor(
      address holstein
      ) ERC721("cRGB", "cRGB"){
        _passch = payable(owner());
        _holstein = payable(holstein);
  }

  struct Color { 
      string colorName;
      string colorNameMeta;
      string bgRed;
      string bgGreen;
      string bgBlue;
  }
  
  mapping (uint256 => Color) public colors;
   
  // public
  function mint(uint256 _tokenId, string memory colorName) public nonReentrant payable {
    require(msg.value >= cost, "Ether amount sent is insufficient");
    require(_tokenId >= 0 && _tokenId <= 16777215, "Token ID invalid");
    require(bytes(colorName).length <= 32, "Color name can have a maximum length of 32 characters");
    require(bytes(colorName).length >= 1, "Color name requires a minimum of 1 character");
    
    // ColorShifter
    // Convert TokenId to RGB values
    colorId = int(_tokenId);
    Red = colorId; Red >> 0; bgRed = (Red & 0xFF0000) >> 16;
    Green = colorId; Green >> 0; bgGreen = (Green & 0xFF00) >> 8;
    Blue = colorId; Blue >> 0; bgBlue = Blue & 0xFF; 

    Color memory newColor = Color(
    string(abi.encodePacked('"', colorName,'"')),
    string(abi.encodePacked(' \\"',colorName,'\\" ')),
    uint(bgRed).toString(),
    uint(bgGreen).toString(),
    uint(bgBlue).toString());
    colors[_tokenId] = newColor;

    // safeMint 
     _safeMint(msg.sender, _tokenId); 
  }

  function changeColorName(uint256 _tokenId, string memory colorName) public nonReentrant payable {
    require(_isApprovedOrOwner(_msgSender(), _tokenId), "ERC721Burnable: caller is not owner nor approved");
    require(bytes(colorName).length <= 32, "Color name can have a maximum length of 32 characters");
    require(bytes(colorName).length >= 1, "Color name requires a minimum of 1 character");
    
    // ColorShifter
    // Convert TokenId to RGB values
    colorId = int(_tokenId);
    Red = colorId; Red >> 0; bgRed = (Red & 0xFF0000) >> 16;
    Green = colorId; Green >> 0; bgGreen = (Green & 0xFF00) >> 8;
    Blue = colorId; Blue >> 0; bgBlue = Blue & 0xFF; 
    
    Color memory newColor = Color(
    string(abi.encodePacked('"', colorName,'"')),
    string(abi.encodePacked(' \\"',colorName,'\\" ')),
    uint(bgRed).toString(),
    uint(bgGreen).toString(),
    uint(bgBlue).toString());
    colors[_tokenId] = newColor;

    //burn token
    _burn(_tokenId); 
    // safeMint the same token with new color name
    _safeMint(msg.sender, _tokenId);
  }
  
    function buildImage(uint256 _tokenId) public view returns(string memory) {
      Color memory currentColor = colors[_tokenId];
      return Base64.encode(bytes(abi.encodePacked(
          '<svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">',
          '<rect width="1000" height="1000" stroke-width="1" stroke="#DEDEDE" fill="rgb(',currentColor.bgRed,',',currentColor.bgGreen,',',currentColor.bgBlue,')"/>',
          '<style> text {fill: white; mix-blend-mode: difference; stroke: #808080; font: bold 45px Helvetica, Arial, sans-serif;} </style>',
          '<text x="50%" y="75" text-anchor="middle" text-rendering="geometricPrecision">',
          currentColor.colorName,
          '</text>',
          '<text letter-spacing="1.5" style="font: bold 36px Helvetica, Arial, sans-serif;" text-rendering="geometricPrecision">',
          '<tspan x="25" y="975" text-anchor="start">#',
          uint256(_tokenId).toString(),'</tspan>',
          '<tspan x="980" y="975" text-anchor="end">(',currentColor.bgRed,',',currentColor.bgGreen,',',currentColor.bgBlue,')',
          '</tspan>',
          '</text>',
          '</svg>'
          )));
    }

    function buildMetadata(uint256 _tokenId) public view returns(string memory) {
      Color memory currentColor = colors[_tokenId];
      return string(abi.encodePacked(
                  'data:application/json;base64,', Base64.encode(bytes(abi.encodePacked(
                  '{"name": "#',uint256(_tokenId).toString(),
                  currentColor.colorNameMeta,
                  '(',currentColor.bgRed,',',currentColor.bgGreen,',',currentColor.bgBlue,')',
                  '","description":"cRGB is the first on-chain NFT series that is based entirely on sRGB values. It is limited to a total of 16,777,216 pieces, which is the maximum number of sRGB value combinations. Color owners are able to set or change the \\"color name\\" as they please. Feel free to use cRGB in any way you want.',
                  '", "image": "',
                  'data:image/svg+xml;base64,',
                  buildImage(_tokenId),
                  '","attributes":[ {"trait_type": "Red","value":"',
                  currentColor.bgRed,
                  '"}, {"trait_type": "Green","value":"',
                  currentColor.bgGreen,
                  '"}, {"trait_type": "Blue","value":"',
                   currentColor.bgBlue,
                  '"}]}'
                  )))));
    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId),"ERC721Metadata: URI query for nonexistent token");
        return buildMetadata(tokenId);
    }

    function withdraw() external {
      // Split payment 50/50 between Passch and Holstein
      uint256 half = address(this).balance / 2;
      Address.sendValue(_passch, half);
      Address.sendValue(_holstein, half);
    }

  //only owner
 // function withdraw() public payable onlyOwner {
  //  (bool success, ) = payable(msg.sender).call{value: address(this).balance}("");
  //  require(success);
  //}
}
function mint(uint256 _tokenId, string memory colorName) public nonReentrant payable {
  require(msg.value >= cost, "Ether amount sent is insufficient");
  require(_tokenId >= 0 && _tokenId <= 16777215, "Token ID invalid");
  require(bytes(colorName).length <= 32, "Color name can have a maximum length of 32 characters");
  require(bytes(colorName).length >= 1, "Color name requires a minimum of 1 character");
    
  // ColorShifter
  // Convert TokenId to RGB values
  colorId = int(_tokenId);
  Red = colorId; Red >> 0; bgRed = (Red & 0xFF0000) >> 16;
  Green = colorId; Green >> 0; bgGreen = (Green & 0xFF00) >> 8;
  Blue = colorId; Blue >> 0; bgBlue = Blue & 0xFF; 

  Color memory newColor = Color(
  string(abi.encodePacked('"', colorName,'"')),
  string(abi.encodePacked(' \\"',colorName,'\\" ')),
  uint(bgRed).toString(),
  uint(bgGreen).toString(),
  uint(bgBlue).toString());
  colors[_tokenId] = newColor;

  // safeMint 
   _safeMint(msg.sender, _tokenId); 
}

// public