contract VcgERC721Token is IVcgERC721Token, ERC721Enumerable, Ownable {
  using Strings for string;
  using SafeMath for *;

  string private _baseTokenURI;
  string constant private _NFT_NAME = "Vault by 500px's NFT";
  string constant private _NFT_SYMBOL = "NFT@Vault by 500px";

  constructor() ERC721(_NFT_NAME, _NFT_SYMBOL) {
    _baseTokenURI = "https://vault.world/nft/721/";
  }

  /**
    * @dev Mints a token to an address with a tokenURI.
    * @param to address of the future owner of the token
    */
  function mintTo(address to) public onlyOwner returns (uint256){
    uint256 newTokenId = _getNextTokenId();
    _mint(to, newTokenId);
    //2021-10-08 , return New TokenID
    return newTokenId;
  }

  /**
    * @dev calculates the next token ID based on _currentTokenId
    * @return uint256 for the next token ID
    */
  function _getNextTokenId() /**private**/internal view returns (uint256) {
     return totalSupply().add(1);
  }


  /**
    * @dev get getBaseTokenURI
    * @return string of _baseTokenURI
    */
  function getBaseTokenURI() public view override returns (string memory) {
    return _baseTokenURI;
  }

  /**
    * @dev setBaseTokenURI
    * @param url string of baseTokenURI
    */
  function setBaseTokenURI(string memory url) public override onlyOwner() {
    _baseTokenURI = url;
  }  

  /**
    * @dev get baseTokenURI
    * @param tokenId uint256 ID of the token to query
    * @return string of TokenURI
    */
  function tokenURI(uint256 tokenId) override(IVcgERC721Token, ERC721) virtual public view returns (string memory) {
        return string(abi.encodePacked(_baseTokenURI, Strings.toString(tokenId)));
  }

  /**
    * @dev See {IERC165-supportsInterface}.
    * @param interfaceId qeSelector
    */
  function supportsInterface(bytes4 interfaceId) public view override(IERC165, ERC721Enumerable) returns (bool) {
      return interfaceId == type(IVcgERC721Token).interfaceId || super.supportsInterface(interfaceId);
  }  


  function isVcgNftToken(address tokenAddress) public view override(IVcgERC721Token)returns(bool) {
      if( !Address.isContract(tokenAddress) ) 
      {
        return false;
      }
    
      bool result = false;
      string memory name = VcgERC721Token(tokenAddress).name();
      string memory symbol = VcgERC721Token(tokenAddress).symbol();   
      
      result = (keccak256(abi.encodePacked(name)) == keccak256(abi.encodePacked(_NFT_NAME))) 
            && (keccak256(abi.encodePacked(symbol)) == keccak256(abi.encodePacked(_NFT_SYMBOL))) 
            && (supportsInterface(type(IVcgERC721Token).interfaceId) );
           
      return result;
  }

  function isApprovedOrOwner(address spender, uint256 tokenId) external view override returns (bool) {
    if(!_exists(tokenId) || (address(0) == spender))
    {
      return(false);      
    }

    return super._isApprovedOrOwner(spender, tokenId);
  }  

  function exists(uint256 tokenId) external view override returns (bool) {
    
    return(_exists(tokenId));    
  }
}
function mintTo(address to) public onlyOwner returns (uint256){
  uint256 newTokenId = _getNextTokenId();
  _mint(to, newTokenId);
  //2021-10-08 , return New TokenID
  return newTokenId;
}

/**
 * @dev Mints a token to an address with a tokenURI.
 * @param to address of the future owner of the token
 */