contract PxelMfer is ERC721Delegated, ReentrancyGuard {
  using Counters for Counters.Counter;

  constructor(address baseFactory, string memory customBaseURI_)
    ERC721Delegated(
      baseFactory,
      "pxel mfer",
      "PXMFER",
      ConfigSettings({
        royaltyBps: 0,
        uriBase: customBaseURI_,
        uriExtension: "",
        hasTransferHook: false
      })
    )
  {}

  /** MINTING **/

  uint256 public constant MAX_SUPPLY = 6969;

  uint256 public MAX_FREE_SUPPLY = 1420;

  uint256 public constant MAX_MULTIMINT = 20;

  uint256 public constant MAX_FREE_MULTIMINT = 10;

  uint256 public PRICE = 10000000000000000;

  string extensionURI = ".json";

  Counters.Counter private supplyCounter;

  function mint(uint256 count) public payable nonReentrant {
    require(saleIsActive, "minting not started");

    require(totalSupply() + count - 1 < MAX_SUPPLY, "can't mint more than max supply mfer");

    require(count <= MAX_MULTIMINT, "can only mint 20 at once mfer");

    require(
      msg.value >= PRICE * count, "need 0.01 ETH mfer"
    );

    for (uint256 i = 0; i < count; i++) {
      _mint(msg.sender, totalSupply());

      supplyCounter.increment();
    }
  }

  function freeMint(uint256 count) public payable nonReentrant {
    require(saleIsActive, "minting not started");

    require(totalSupply() + count - 1 < MAX_FREE_SUPPLY, "no more free ones mfer");
    
    require(totalSupply() + count - 1 < MAX_SUPPLY, "can't mint more than max supply mfer");

    require(count <= MAX_FREE_MULTIMINT, "can only mint 10 at once mfer");

    for (uint256 i = 0; i < count; i++) {
      _mint(msg.sender, totalSupply());

      supplyCounter.increment();
    }
  }

  function totalSupply() public view returns (uint256) {
    return supplyCounter.current();
  }

  /** ACTIVATION **/

  bool public saleIsActive = true;

  function setSaleIsActive(bool saleIsActive_) external onlyOwner {
    saleIsActive = saleIsActive_;
  }

  /** URI HANDLING **/

  function setBaseURI(string memory customBaseURI_) external onlyOwner {
    _setBaseURI(customBaseURI_, "");
  }

  function setExtensionURI(string memory customExtensionURI_) external onlyOwner {
    extensionURI = customExtensionURI_;
  }

  function tokenURI(uint256 tokenId) public view returns (string memory) {
    return string(abi.encodePacked(_tokenURI(tokenId), extensionURI));
  }

  function setPrice(uint256 _price) external onlyOwner {
    PRICE = _price;
  }

  function increaseFreeMintSupply(uint256 _maxfree) external onlyOwner {
    MAX_FREE_SUPPLY = _maxfree;
  }

  /** PAYOUT **/

  function withdraw() public nonReentrant onlyOwner {
    uint256 balance = address(this).balance;

    Address.sendValue(payable(_owner()), balance);
  }
}
function withdraw() public nonReentrant onlyOwner {
  uint256 balance = address(this).balance;

  Address.sendValue(payable(_owner()), balance);
}

/** PAYOUT **/