contract elements is ERC721Enumerable, Ownable {
    using SafeMath for uint256;
    using Address for address;
    using Strings for uint256;

    uint256 public MAX_SUPPLY = 300;
    bool public saleIsActive = false;
    
    //code to reference Pixel Runes
    ERC721 planets = ERC721(0xB228077BCE558dd6844032c29630f13818C4C4Dc);
    

    uint256 public startingIndex;
    uint256 public startingIndexBlock;

    string private _baseURIExtended;
    mapping (uint256 => string) _tokenURIs;

    constructor() ERC721("Pixel Elements","ELEMENTS"){
    }


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

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

    function reserveTokens(uint256 num) public onlyOwner {
        uint supply = totalSupply();
        uint i;
        for (i = 0; i < num; i++) {
            _safeMint(msg.sender, supply + i);
        }

        if (startingIndexBlock == 0) {
            startingIndexBlock = block.number;
        }
    }

    function setMaxTokenSupply(uint256 maxSupply) public onlyOwner {
        MAX_SUPPLY = maxSupply;
    }
    
    function mint(uint256 tokenId) public {
        require(planets.ownerOf(tokenId) == msg.sender, "Not Owner Of this planet");
        require(saleIsActive, "Sale is not active at the moment");
        require((totalSupply() + 1) <= MAX_SUPPLY, "Purchase would exceed max supply");

        
        //burn planet
        address burner = planets.ownerOf(tokenId);
        planets.transferFrom(burner, address(0x000000000000000000000000000000000000dEaD), tokenId);
 
        
        if ((totalSupply() + 1) <= MAX_SUPPLY) {
            _safeMint(msg.sender, totalSupply());
        }
        
    }


    function calcStartingIndex() public onlyOwner {
        require(startingIndex == 0, "Starting index has already been set");
        require(startingIndexBlock != 0, "Starting index has not been set yet");

        startingIndex = uint(blockhash(startingIndexBlock)) % MAX_SUPPLY;
        // Just a sanity case in the worst case if this function is called late (EVM only stores last 256 block hashes)
        if(block.number.sub(startingIndexBlock) > 255) {
            startingIndex = uint(blockhash(block.number - 1)) % MAX_SUPPLY;
        }

        // To prevent original sequence
        if (startingIndex == 0) {
            startingIndex = startingIndex.add(1);
        }
    }

    function emergencySetStartingIndexBlock() public onlyOwner {
        require(startingIndex == 0, "Starting index is already set");
        startingIndexBlock = block.number;
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return _baseURIExtended;
    }

    // Sets base URI for all tokens, only able to be called by contract owner
    function setBaseURI(string memory baseURI_) external onlyOwner {
        _baseURIExtended = baseURI_;
    }
    
    function setPlanetContract(address address_) external onlyOwner {
        planets = ERC721(address_);
    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory _tokenURI = _tokenURIs[tokenId];
        string memory base = _baseURI();

        // If there is no base URI, return the token URI.
        if (bytes(base).length == 0) {
            return _tokenURI;
        }
        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
        if (bytes(_tokenURI).length > 0) {
            return string(abi.encodePacked(base, _tokenURI));
        }
        // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
        return string(abi.encodePacked(base, tokenId.toString()));
    }
}
function setBaseURI(string memory baseURI_) external onlyOwner {
    _baseURIExtended = baseURI_;
}

// Sets base URI for all tokens, only able to be called by contract owner