contract Burnables is ERC721, Ownable {
    using Strings for uint256;
    using SafeMath for uint256;
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdTracker;
    Counters.Counter private _burnedTracker;
    
    string public baseTokenURI;

    uint256 public constant MAX_ELEMENTS = 999;    
    uint256 public constant MINT_PRICE = 8 * 10**16;
    
    address
        public constant creatorAddress = 0xc988f2D5BDB203955c5fBB70E2191D62478b2ee7;

    event CreateBurnable(uint256 indexed id);

    constructor() public ERC721("Burnables", "BURN") {}

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

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

    function _totalSupply() internal view returns (uint256) {
        return _tokenIdTracker.current();
    }
    
    function _totalBurned() internal view returns (uint256) {
        return _burnedTracker.current();
    }
    
    function totalBurned() public view returns (uint256) {
        return _totalBurned();
    }

    function totalMint() public view returns (uint256) {
        return _totalSupply();
    }
    
    function mint(address _to, uint256 _count) public payable saleIsOpen {
        uint256 total = _totalSupply();
        require(total + _count <= MAX_ELEMENTS, "Max limit");
        require(total <= MAX_ELEMENTS, "Sale end");
        require(msg.value >= price(_count), "Value below price");

        for (uint256 i = 0; i < _count; i++) {
            _mintAnElement(_to);
        }
    }
    
    function price(uint256 _count) public pure returns (uint256) {
        return MINT_PRICE.mul(_count);
    }

    function _mintAnElement(address _to) private {
        uint256 id = _totalSupply();
        _tokenIdTracker.increment();
        _safeMint(_to, id);
        emit CreateBurnable(id);
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        baseTokenURI = baseURI;
    }

    /**
     * @dev Returns an URI for a given token ID
     */
    function tokenURI(uint256 _tokenId) public view override returns (string memory) {
        return string(abi.encodePacked(baseTokenURI, _tokenId.toString()));
    }
    
    /**
     * @dev Burns and pays the mint price to the token owner.
     * @param _tokenId The token to burn.
     */
    function burn(uint256 _tokenId) public {
        require(ownerOf(_tokenId) == msg.sender);

        //Burn token
        _transfer(
            msg.sender,
            0x000000000000000000000000000000000000dEaD,
            _tokenId
        );
        
        // increment burn
        _burnedTracker.increment();

        // pay token owner 
        _widthdraw(msg.sender, MINT_PRICE);
    }

    function _widthdraw(address _address, uint256 _amount) private {
        (bool success, ) = _address.call{value: _amount}("");
        require(success, "Transfer failed.");
    }
}
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
    return string(abi.encodePacked(baseTokenURI, _tokenId.toString()));
}

/**
 * @dev Returns an URI for a given token ID
 */