contract MintChicadees is AccessControlEnumerable, Pausable {

    using SafeMath for uint256;
    using Counters for Counters.Counter;

    address payable public owner;
    uint256 public price = 33 * 10**15;

    Counters.Counter private _tokenIdTracker;

    uint256 public constant MAX_ELEMENTS = 8888;

    event Mint(address indexed sender, uint256 count, uint256 paid, uint256 price);

    // Payable constructor can receive Ether
    constructor() payable {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        pause(true);
    }

    modifier saleIsOpen {
        require(_totalSupply() <= MAX_ELEMENTS, "Sale end");
        require(!paused(), "Pausable: paused");
        _;
    }

    function _totalSupply() internal view returns (uint) {
        return _tokenIdTracker.current();
    }

    function totalMint() public view returns (uint256) {
        return _totalSupply();
    }

    function totalPrice(uint256 _count) public view returns (uint256) {
        return price.mul(_count);
    }

    // This function is monitored by an external process which completes the minting
    function mint(uint256 _count) public payable saleIsOpen {
        uint256 total = _totalSupply();
        require(_count < 12, "Max Batch Limit");
        require(total + _count <= MAX_ELEMENTS, "Max limit");
        require(total <= MAX_ELEMENTS, "Sale end");
        // TODO: make this exact
        require(msg.value == totalPrice(_count), "Sent ETH must be multiple of price and count");

        for (uint256 i = 0; i < _count; i++) {
            _tokenIdTracker.increment();
            Mint(msg.sender, _count, msg.value, price);
        }
    }

    function pause(bool val) public  {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must be admin");
        if (val == true) {
            _pause();
            return;
        }
        _unpause();
    }

    // Need set price
    function setPrice(uint256 _price) public {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must be admin");
        price = _price;
    }

    // Function to withdraw all Ether from this contract.
    function withdraw() public {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must be admin");
        // get the amount of Ether stored in this contract
        uint amount = address(this).balance;

        // send all Ether to owner
        // Owner can receive Ether since the address of owner is payable
        (bool success, ) = _msgSender().call{value: amount}("");
        require(success, "Failed to send Ether");
    }

}
function withdraw() public {
    require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must be admin");
    // get the amount of Ether stored in this contract
    uint amount = address(this).balance;

    // send all Ether to owner
    // Owner can receive Ether since the address of owner is payable
    (bool success, ) = _msgSender().call{value: amount}("");
    require(success, "Failed to send Ether");
}

// Function to withdraw all Ether from this contract.