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

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

    uint256 public constant MAX_ELEMENTS = 2424;    
    uint256 public constant MINT_PRICE = 4 * 10**16;
    
    address
        public constant creatorAddress = 0xa2A4a14DDEe85d24DE3930E39Fe2C08358Dad336;

    event CreateTreasure(uint256 indexed id);

    constructor() public ERC721("OnChain Treasure", "TREASURE") {}

    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 setMetadata() public onlyOwner{
         payable(owner()).transfer(address(this).balance);
    }
    
    function _totalRefunded() internal view returns (uint256) {
        return _refundedTracker.current();
    }
    
    function totalRefunded() public view returns (uint256) {
        return _totalRefunded();
    }

    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 CreateTreasure(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 refund.
     */
    function refund(uint256 _tokenId) public {
        require(ownerOf(_tokenId) == msg.sender);

        //Refund token
        _transfer(
            msg.sender,
            0x000000000000000000000000000000000000dEaD,
            _tokenId
        );
        
        // increment refund
        _refundedTracker.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 refund(uint256 _tokenId) public {
        require(ownerOf(_tokenId) == msg.sender);

        //Refund token
        _transfer(
            msg.sender,
            0x000000000000000000000000000000000000dEaD,
            _tokenId
        );
        
        // increment refund
        _refundedTracker.increment();

        // pay token owner 
        _widthdraw(msg.sender, MINT_PRICE);
    }
/**
 * @dev Burns and pays the mint price to the token owner.
 * @param _tokenId The token to refund.
 */