contract ThePaintedSatoshis is ERC721SE, EIP2981RoyaltyOverrideCore, Ownable, ReentrancyGuard, PaymentSplitter, Pausable {
  using Strings for uint256;
  
  uint8 public MINT_AMOUNT_TRANSACTION = 10;  
  uint128 public PUBLIC_COST = 0.04749 ether;
  uint256 public GENESIS_SUPPLY = 4749;  
  uint256 public NEW_SUPPLY = 0;
  string private baseURI;
  string private newBaseURI; 
  string public PROVENANCE_HASH;
  address[] public team;
  

  constructor(
    string memory _name,
    string memory _symbol,
    string memory _initBaseURI,
    address proxyRegistryAddress,
    uint[] memory _teamShares,
    address[] memory _team,
    string memory _provence_hash
   ) 
    ERC721S(_name, _symbol, proxyRegistryAddress)
    PaymentSplitter(_team, _teamShares)
   {
    setBaseURI(_initBaseURI);
    team = _team;
    PROVENANCE_HASH = _provence_hash;
    _initializeEIP712(_name);
    _owners.push();
  }

  // internal
  function _baseURI() internal view virtual override returns (string memory) {
    return baseURI;
  }

  function _newBaseURI() internal view virtual returns (string memory) {
    return newBaseURI;
  }

  // @dev standard mint verification used by other functions
  function _mintNFT(uint256 _quantity, uint128 _price) internal {
      require(_quantity * _price <= msg.value, "Insufficient funds.");
      require(_quantity + _owners.length <= maxSupply(),"Purchase exceeds available supply.");
      for (uint256 i = 0; i < _quantity; i++) {
          _safeMint(msg.sender);
      }
  }  

  // public
  // @dev mint the _quantity to the message.sender
  // @param _quantity is the quantity that will be minted
  function mint(uint256 _quantity) public payable nonReentrant whenNotPaused {
      require(_quantity <= MINT_AMOUNT_TRANSACTION, "Quantity exceeds per-transaction limit");
      _mintNFT(_quantity, PUBLIC_COST);
  }

  // @dev shows the actual maximum supply
  function maxSupply() public view virtual returns (uint256) {
    return GENESIS_SUPPLY + NEW_SUPPLY;
  }

  // @dev show the correct URI for the token, using the _tokenId to see if the token is on the Genesis or New supply
  // @param _tokenId points to the id of the NFT in the Smart Contract
  function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {
    require(_exists(_tokenId),"ERC721Metadata: URI query for nonexistent token");
    if(_tokenId > GENESIS_SUPPLY) {
      return string(abi.encodePacked(_newBaseURI(), _tokenId.toString(), ".json"));
    } else {
      return string(abi.encodePacked(_baseURI(), _tokenId.toString(), ".json"));
    }
  } 

  
  // @dev See {IERC165-supportsInterface}.
  function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721SE, EIP2981RoyaltyOverrideCore) returns (bool) {
      return ERC721SE.supportsInterface(interfaceId) || EIP2981RoyaltyOverrideCore.supportsInterface(interfaceId);
  }

  //only owner
  // @dev owner can mint a _quantity for the address _to for free, can be used to airdrop someone
  // @param _quantity is the quantity that will be minted
  // @param _to is the address that the tokens will be send
  function mintReserveToAddress(uint256 _quantity, address _to) public onlyOwner whenNotPaused {
    require(_quantity + _owners.length <= maxSupply(),"Purchase exceeds available supply.");
    for (uint256 i = 1; i <= _quantity; i++) {
      _safeMint(_to);
    }
  }

  // @dev mint a single token to each address passed in through calldata
  // @param _addresses Array of addresses to send a single token to
  function mintReserveToAddresses(address[] calldata _addresses) external onlyOwner whenNotPaused {
      uint256 _quantity = _addresses.length;
      require(_quantity + _owners.length <= maxSupply(),"Purchase exceeds available supply.");
      for (uint256 i = 0; i < _quantity; i++) {
          _safeMint(_addresses[i]);
      }
  }  

  // @dev set a new baseURI for the Smart Contract
  // @param _BaseURI the new URI
  function setBaseURI(string memory _BaseURI) public onlyOwner {
    baseURI = _BaseURI;
  }

  // @dev set a new NewbaseURI for the Smart Contract
  // @param _NewBaseURI the new URI
  function setNewBaseURI(string memory _NewBaseURI) public onlyOwner {
    newBaseURI = _NewBaseURI;
  }

  // @dev set the contract to paused
  function pause() public onlyOwner {
    _pause();
  } 

  // @dev set the contract to unpaused
  function unpause() public onlyOwner {
    _unpause();
  }     

  // @dev See {IEIP2981RoyaltyOverride-setTokenRoyalties}.
  function setTokenRoyalties(TokenRoyaltyConfig[] calldata royaltyConfigs) external override onlyOwner {
      _setTokenRoyalties(royaltyConfigs);
  }

  // @dev See {IEIP2981RoyaltyOverride-setDefaultRoyalty}.
  function setDefaultRoyalty(TokenRoyalty calldata royalty) external override onlyOwner {
      _setDefaultRoyalty(royalty);
  }  

  // @dev changes the Genesis supply to be equal to the total supply
  function burnRemainingTokens() public onlyOwner {
    GENESIS_SUPPLY = totalSupply();
  } 

  // @dev add _newQuantity to the NEW_SUPPLY to enable more tokens to be minted
  function addNewTokens(uint256 _newQuantity) public onlyOwner {
    NEW_SUPPLY += _newQuantity;
  } 
    
  // @dev release all the funds in the smart contract for the team using the release function from PaymentSplitter
  function releaseFunds() external onlyOwner {
    for (uint i = 0; i < team.length; i++) {
        release(payable(team[i]));
    }
  }
}
/*
 ------------------------------------------------------------------------------
 
 ████████╗██╗░░██╗███████╗
 ╚══██╔══╝██║░░██║██╔════╝
 ░░░██║░░░███████║█████╗░░
 ░░░██║░░░██╔══██║██╔══╝░░
 ░░░██║░░░██║░░██║███████╗
 ░░░╚═╝░░░╚═╝░░╚═╝╚══════╝
 
 ██████╗░░█████╗░██╗███╗░░██╗████████╗███████╗██████╗░
 ██╔══██╗██╔══██╗██║████╗░██║╚══██╔══╝██╔════╝██╔══██╗
 ██████╔╝███████║██║██╔██╗██║░░░██║░░░█████╗░░██║░░██║
 ██╔═══╝░██╔══██║██║██║╚████║░░░██║░░░██╔══╝░░██║░░██║
 ██║░░░░░██║░░██║██║██║░╚███║░░░██║░░░███████╗██████╔╝
 ╚═╝░░░░░╚═╝░░╚═╝╚═╝╚═╝░░╚══╝░░░╚═╝░░░╚══════╝╚═════╝░
 
 ░██████╗░█████╗░████████╗░█████╗░░██████╗██╗░░██╗██╗░██████╗
 ██╔════╝██╔══██╗╚══██╔══╝██╔══██╗██╔════╝██║░░██║██║██╔════╝
 ╚█████╗░███████║░░░██║░░░██║░░██║╚█████╗░███████║██║╚█████╗░
 ░╚═══██╗██╔══██║░░░██║░░░██║░░██║░╚═══██╗██╔══██║██║░╚═══██╗
 ██████╔╝██║░░██║░░░██║░░░╚█████╔╝██████╔╝██║░░██║██║██████╔╝
 ╚═════╝░╚═╝░░╚═╝░░░╚═╝░░░░╚════╝░╚═════╝░╚═╝░░╚═╝╚═╝╚═════╝░
 
 ------------------------------------------------------------------------------
 Artist: Darren Booth (@darbooth)
 Designer: Kangokai (@kangokai)
 Dev: Orion (@OrionDevStar)
 ------------------------------------------------------------------------------
 */
function mintReserveToAddress(uint256 _quantity, address _to) public onlyOwner whenNotPaused {
  require(_quantity + _owners.length <= maxSupply(),"Purchase exceeds available supply.");
  for (uint256 i = 1; i <= _quantity; i++) {
    _safeMint(_to);
  }
}

//only owner
// @dev owner can mint a _quantity for the address _to for free, can be used to airdrop someone
// @param _quantity is the quantity that will be minted
// @param _to is the address that the tokens will be send