contract NFTPassTokens is
  NFTokenEnumerable,
  NFTokenMetadata,
  Ownable
{
  
  uint256 mint_price = 100000000000000000; //wei (0,1 eth)
  string public nftUrl = '';
 
  
  uint256 next_token_id = 1;
  uint256 max_token_id = 10;
                
 
 
 
  /**
   * @dev not bullet-proof check, but additional measure, actually we require specific (contract) address, 
   * which is key (see onlymanagingContract)
   */
  function isContract(address _addr) 
    internal
    view    
    returns (bool)
  {
      uint32 size;
      assembly {
          size := extcodesize(_addr)
      }
      
      return (size > 0);
  }
  
  function concatenate(
        string memory a,
        string memory b)
        internal 
        pure
        returns(string memory) {
            return string(abi.encodePacked(a, b));
  }
  
  /**
   * @dev Contract constructor. Sets metadata extension `name` and `symbol`.
   */
  constructor()
    public
  {
    nftName = "the.art_Club Membership";
    nftSymbol = "the.art_Club Membership";
    nftUrl = "https://nft.nonfungible-art.net/nftpass.json";
  }
  
  function getMintPrice() external view returns(uint256){
      return mint_price;
  }
  
  function setMintPrice(uint256 new_price) external onlyOwner {
      mint_price = new_price;
  }
  
  function getMaxTokenId() external view returns(uint256){
      return max_token_id;
  }
  
  function setMaxTokenId(uint256 new_max_token_id) external onlyOwner {
      max_token_id = new_max_token_id;
  }
  
  
 /**
  * @dev only to be used if you do not have minted tokens, 
  * all minted tokens will become unusable 
  */
  function setNFTName(string calldata new_name) external onlyOwner{
          nftName = new_name;
  }
  
  /**
  * @dev only to be used if you do not have minted tokens, 
  * all minted tokens will become unusable 
  */
  function setNFTSymbol(string calldata new_symbol) external onlyOwner{
          nftSymbol = new_symbol;
  }
  
  /**
  * @dev only to be used if you do not have minted tokens, 
  * all minted tokens will become unusable 
  */
  function setNFTUrl(string calldata new_url) external onlyOwner{
          nftUrl = new_url;
  }
  
  
  
  
  /**
   * @dev returns contract balance
   */
  function getContractBalance() 
     public 
     view 
     returns (uint256) 
  {
     return address(this).balance;
  }

  /**
   * @dev sends eth from contract balance to specified address
   * @param sendTo address to send amount
   * @param amount - amount to send (should be less than current balance)
   */
  function withdraw(
      address payable sendTo, 
      uint256 amount
  ) 
      external 
      onlyOwner 
  {
      require(address(this).balance >= amount, "unsufficient funds");
      sendTo.transfer(amount);
  }
   
  
  function isFreeTokenId(uint256 _tokenId) public view returns (bool){
      if (bytes(idToUri[_tokenId]).length != 0){
          return false;
      } else {
          return true;
      }
  }
  

  

  
  
    
  function mint(
    address _to,
    uint256 amount //amount tokens to mint, max 5
  ) 
    external
    payable
  {
    require(amount >= 1 && amount <=5,"1 to 5 tokens can be minted");
    require((next_token_id+amount-1) <= max_token_id, "with this amount we will be over max_token_id");
    
    uint256 val = msg.value.div(amount);
    require(val == mint_price, "you should send value of [mint_price] X [amount]");
    
    for (uint256 i=0; i< amount; i++){
        while (!isFreeTokenId(next_token_id)){
            next_token_id++;
        }
        uint256 _tokenId = next_token_id;
        
        
        super._mint(_to, _tokenId);
        super._setTokenUri(_tokenId, nftUrl);
        
        next_token_id++;
    }
  }
       
  /**
   * @dev Removes a NFT from owner.
   * @param _tokenId Which NFT we want to remove.
   */
  function burn(
    uint256 _tokenId
  )
    external
  {
    require(msg.sender == owner || idToOwner[_tokenId] == msg.sender, "no rights to burn");
    
    super._burn(_tokenId);
  }

  /**
   * @dev Mints a new NFT.
   * @notice This is an internal function which should be called from user-implemented external
   * mint function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _to The address that will own the minted NFT.
   * @param _tokenId of the NFT to be minted by the msg.sender.
   */
  function _mint(
    address _to,
    uint256 _tokenId
  )
    internal
    override(NFToken, NFTokenEnumerable)
    virtual
  {
    NFTokenEnumerable._mint(_to, _tokenId);
  }

  /**
   * @dev Burns a NFT.
   * @notice This is an internal function which should be called from user-implemented external
   * burn function. Its purpose is to show and properly initialize data structures when using this
   * implementation. Also, note that this burn implementation allows the minter to re-mint a burned
   * NFT.
   * @param _tokenId ID of the NFT to be burned.
   */
  function _burn(
    uint256 _tokenId
  )
    internal
    override(NFTokenMetadata, NFTokenEnumerable)
    virtual
  {
    NFTokenEnumerable._burn(_tokenId);
    if (bytes(idToUri[_tokenId]).length != 0)
    {
      delete idToUri[_tokenId];
    }
  }

  /**
   * @dev Removes a NFT from an address.
   * @notice Use and override this function with caution. Wrong usage can have serious consequences.
   * @param _from Address from wich we want to remove the NFT.
   * @param _tokenId Which NFT we want to remove.
   */
  function _removeNFToken(
    address _from,
    uint256 _tokenId
  )
    internal
    override(NFToken, NFTokenEnumerable)
  {
    NFTokenEnumerable._removeNFToken(_from, _tokenId);
  }

  /**
   * @dev Assignes a new NFT to an address.
   * @notice Use and override this function with caution. Wrong usage can have serious consequences.
   * @param _to Address to wich we want to add the NFT.
   * @param _tokenId Which NFT we want to add.
   */
  function _addNFToken(
    address _to,
    uint256 _tokenId
  )
    internal
    override(NFToken, NFTokenEnumerable)
  {
    NFTokenEnumerable._addNFToken(_to, _tokenId);
  }

   /**
   * @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable
   * extension to remove double storage(gas optimization) of owner nft count.
   * @param _owner Address for whom to query the count.
   * @return Number of _owner NFTs.
   */
  function _getOwnerNFTCount(
    address _owner
  )
    internal
    override(NFToken, NFTokenEnumerable)
    view
    returns (uint256)
  {
    return NFTokenEnumerable._getOwnerNFTCount(_owner);
  }
  
  function hasPass(
    address _wallet
  )
    external
    view
    returns (bool)
  {
    require(_wallet != address(0), ZERO_ADDRESS);
    return (_getOwnerNFTCount(_wallet) > 0);
  }

}
function _removeNFToken(
  address _from,
  uint256 _tokenId
)
  internal
  override(NFToken, NFTokenEnumerable)
{
  NFTokenEnumerable._removeNFToken(_from, _tokenId);
}

/**
 * @dev Removes a NFT from an address.
 * @notice Use and override this function with caution. Wrong usage can have serious consequences.
 * @param _from Address from wich we want to remove the NFT.
 * @param _tokenId Which NFT we want to remove.
 */