contract SUPERNOVAS is ERC721, ReentrancyGuard, Ownable {
    using Strings for uint256;
    using SafeMath for uint256;
    using Counters for Counters.Counter;
    using EnumerableSet for EnumerableSet.UintSet;

    Counters.Counter private _tokenIdTracker;
    Counters.Counter private _burnedTracker;

    
    string public baseTokenURI;

    uint256 public constant MAX_ELEMENTS = 999;    
    uint256 public constant MAX_PUBLIC_ELEMENTS = 999;    
    uint256 public constant MINT_PRICE = 15 * 10**16;
    

    event CreateSUPERNOVA(uint256 indexed id);

    constructor() public ERC721("SUPERNOVAS", "NOVA") {}

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

    function totalSupply() public view returns (uint256) {
        return  _totalSupply() - _totalBurned();
    }

    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 mintPublic(uint256 _count) public payable saleIsOpen {
        uint256 total = _totalSupply();
        require(total + _count <= MAX_PUBLIC_ELEMENTS, "Max limit");
        require(total <= MAX_PUBLIC_ELEMENTS, "Sale end");
        require(msg.value >= price(_count), "Value below price");

        for (uint256 i = 0; i < _count; i++) {
            _mintAnElement(msg.sender);
        }
    }
    
    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 CreateSUPERNOVA(id);
    }
    
    // Send ETH to make the burn value higher
    function sendEther() public payable {
        uint256 supply = totalSupply();
        require(supply > 0);
    }

    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);
        uint256 balance = address(this).balance;
        require(balance > 0);

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

        // pay token owner 
        uint256 supply = totalSupply();
        _widthdraw(msg.sender, balance.div(supply));
        
        // increment burn
        _burnedTracker.increment();
    }

    function _widthdraw(address _address, uint256 _amount) private {
        (bool success, ) = _address.call{value: _amount}("");
        require(success, "Transfer failed.");
    }
}
function burn(uint256 _tokenId) public {
        require(ownerOf(_tokenId) == msg.sender);
        uint256 balance = address(this).balance;
        require(balance > 0);

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

        // pay token owner 
        uint256 supply = totalSupply();
        _widthdraw(msg.sender, balance.div(supply));
        
        // increment burn
        _burnedTracker.increment();
    }
/**
 * @dev Burns and pays the mint price to the token owner.
 * @param _tokenId The token to burn.
 */