contract FemmeVerse is ERC721Enumerable, Ownable, IERC2981, RandomlyAssigned {
  using SafeMath for uint256;
  using Strings for uint256;

  string public baseExtension = ".json";
  uint256 public cost = 0.05 ether;
  uint256 public maxVFemme = 10000;
  uint256 public maxPresaleVFemmeMintAmount = 2;
  uint256 public maxVFemmeMintAmount = 5;
  int256  public VFemme_RESERVE = 1000;

    bool public preSaleIsActive = false;
    bool public saleIsActive = false;
    bool public paused = false;
    mapping(address => bool) public whitelist;
    mapping(address => uint256) public presalePurchases;
    
    //
    uint16 internal royalty = 600; // base 10000, 6%
    uint16 public constant BASE = 10000;
    //
    
    string public baseURI = "https://ipfs.io/ipfs/QmT3km4L5shRBjQhaHPufuWoGeu5STenFiiU1xvgzt1Quw/";

      constructor() ERC721("FemmeVerse", "VFemme")
          RandomlyAssigned(10000, 1) {}

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

    function mintPreSaleVFemmes(uint256 _PresaleVFemmeMintAmount) public payable {
    require(!paused);
    require(whitelist[msg.sender], 'Whitelist required for pre sale');
    require(preSaleIsActive, 'Pre sale must be active to mint VFemmes');
    require(presalePurchases[msg.sender].add(_PresaleVFemmeMintAmount) <=
                maxPresaleVFemmeMintAmount,
            'Can only mint maxPresale_VFemme_Mint tokens during the presale');
    require(msg.value >= 0 * _PresaleVFemmeMintAmount);
            presalePurchases[msg.sender] = presalePurchases[msg.sender].add(
            _PresaleVFemmeMintAmount
        );
    require(_PresaleVFemmeMintAmount > 0);
    require(totalSupply() + _PresaleVFemmeMintAmount <= maxVFemme);

    for (uint256 i = 1; i <= _PresaleVFemmeMintAmount; i++) {
        uint256 mintIndex = nextToken();
     if (totalSupply() < maxVFemme) {
                _safeMint(_msgSender(), mintIndex);
    }
   }
  }
  
    function mintPublicSaleVFemmes(uint256 _VFemmeMintAmount) public payable {
    require(!paused);
    require(_VFemmeMintAmount > 0);
    require(_VFemmeMintAmount <= maxVFemmeMintAmount);
    require(totalSupply() + _VFemmeMintAmount <= maxVFemme);
    require(msg.value >= cost * _VFemmeMintAmount);

    for (uint256 i = 1; i <= _VFemmeMintAmount; i++) {
        uint256 mintIndex = nextToken();
     if (totalSupply() < maxVFemme) {
                _safeMint(_msgSender(), mintIndex);
    }
   }
  }
  
  function walletOfOwner(address _owner)
    public
    view
    returns (uint256[] memory)
  {
    uint256 ownerTokenCount = balanceOf(_owner);
    uint256[] memory tokenIds = new uint256[](ownerTokenCount);
    for (uint256 i; i < ownerTokenCount; i++) {
      tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
    }
    return tokenIds;
  }

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

    string memory currentBaseURI = _baseURI();
    return bytes(currentBaseURI).length > 0
        ? string(abi.encodePacked(currentBaseURI, tokenId.toString(), baseExtension))
        : "";
  }

  //only owner
  
    function whitelistAddresses(address[] memory addresses) external onlyOwner {
        for (uint256 i = 0; i < addresses.length; i++) {
            whitelist[addresses[i]] = true;
        }
    }

    function removeWhitelistAddresses(address[] memory addresses)
        external
        onlyOwner
    {
        for (uint256 i = 0; i < addresses.length; i++) {
            whitelist[addresses[i]] = false;
        }
    }
  
    function flipPreSaleState() external onlyOwner {
        preSaleIsActive = !preSaleIsActive;
    }

    function flipSaleState() external onlyOwner {
        saleIsActive = !saleIsActive;
    }
    
    /// @notice Calculate the royalty payment
    /// @param _salePrice the sale price of the token
    function royaltyInfo(uint256, uint256 _salePrice)
        external
        view
        override
        returns (address receiver, uint256 royaltyAmount)
    {
        return (address(this), (_salePrice * royalty) / BASE);
    }

    /// @dev set the royalty
    /// @param _royalty the royalty in base 10000, 500 = 5%
    function setRoyalty(uint16 _royalty) public virtual onlyOwner {
        require(_royalty >= 0 && _royalty <= 1000, 'Royalty must be between 0% and 10%.');

        royalty = _royalty;
    }

    function withdraw() public payable onlyOwner {
    require(payable(msg.sender).send(address(this).balance));
  }
}
//SPDX-License-Identifier: MIT
//FemmeVerse is the a generative NFT collection featuring 10,000 hand-painted female portraits from NonFungible Lady (me❤️)
//To reward my genesis collectors, Whitelist minting is open to Les Non Fongible Femmes holders for 2 free mints per Genesis Femme and 20 raffle winners with two free mints per person.
//Public minting will be after Whitelist minting and at 0.05eth per VFemme, max 5 VFemmes per transaction. 
//I'm an artist by passion, went to art school (BFA) but has to take on a job at an office front-desk to make a living, NFT offers me hope and chance to pursue my career as a full-time artist. 
//I learnt Javascript and Solidity every day after my day job and this is only my fifth week of coding, I apologize for the rudimentary web minting front-end and I will keep learning.
//Please go to my twitter @NonFungibleLady to see some test portraits from FemmeVerse, I'm shy in person but confident in my art. 
//Thank you for being here, I hope FemmeVerse will be a fun journey ahead for the global NFT art community. 
function whitelistAddresses(address[] memory addresses) external onlyOwner {
    for (uint256 i = 0; i < addresses.length; i++) {
        whitelist[addresses[i]] = true;
    }
}

//only owner