contract ZooGang is ERC721Enumerable, Ownable {

    using SafeMath for uint256;
 
    uint256 public constant PRICE = 0.05 ether;

    uint256 public constant MAX_TOKENS = 10000;

    uint256 public constant MAX_PURCHASE = 20;

    bool public saleIsActive = false;

    constructor() ERC721("Zoo Gang", "ZGANG") {}

    function withdraw() public onlyOwner {
        address payable sender = payable(_msgSender());
        uint balance = address(this).balance;
        sender.transfer(balance);
    }

    function toggleSale() public onlyOwner {
        saleIsActive = !saleIsActive;
    }

    /**
     * Set some Zoo Gang aside
     */
    function reserve() public onlyOwner {     
        require(saleIsActive == false, "Impossible reserve a Zoo Gang when sale is active");   
        uint supply = totalSupply();
        for (uint i = 0; i < 20; i++) {
            _safeMint(_msgSender(), supply + i);
        }
    }

    /**
    * Mint Zoo Gang
    */
    function mint(uint256 numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint Zoo Gang");
        require(numberOfTokens <= MAX_PURCHASE, "Can only mint 20 tokens at a time");
        require(totalSupply().add(numberOfTokens) <= MAX_TOKENS, "Purchase would exceed max supply of Zoo Gangs");
        require(PRICE.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct");
        
        for(uint i = 0; i < numberOfTokens; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < MAX_TOKENS) {
                _safeMint(_msgSender(), mintIndex);
            }
        }
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }
}
function reserve() public onlyOwner {     
    require(saleIsActive == false, "Impossible reserve a Zoo Gang when sale is active");   
    uint supply = totalSupply();
    for (uint i = 0; i < 20; i++) {
        _safeMint(_msgSender(), supply + i);
    }
}

/**
 * Set some Zoo Gang aside
 */