contract GhostGang is ERC721Enumerable, Ownable {

    using SafeMath for uint256;
    using Strings for uint256;

    string public baseTokenURI;
    string public baseExtension = ".json";

    uint256 public price = 0.05 ether;
    uint256 public saleState = 0;
    
    // vault address
    address public vault = 0xf3Bad257c2541d228e837Df5857187717795C280;

    constructor(string memory baseURI) ERC721("Ghost Gang", "GHOST")  {
        setBaseURI(baseURI);
    }

    function mint(uint256 num) public payable {
        uint256 supply = totalSupply();
        require( saleState == 1,            "The sale has not started");
        require( num > 0,                   "Unable to mint 0 Ghosts");
        require( num < 11,                  "Only 10 per mint");
        require( supply + num < 10001,      "Exceeds max Ghost supply");
        require( msg.value >= price * num,  "Insufficient ETH");

        for(uint256 i; i < num; i++){
            _safeMint( msg.sender, supply + i );
        }
    }

    function walletOfOwner(address _owner)
        public
        view
        returns (uint256[] memory)
    {
        uint256 tokenCount = balanceOf(_owner);

        uint256[] memory tokensId = new uint256[](tokenCount);
        for (uint256 i; i < tokenCount; i++) {
            tokensId[i] = tokenOfOwnerByIndex(_owner, i);
        }
        return tokensId;
    }

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

        string memory currentBaseURI = _baseURI();
        return
            bytes(currentBaseURI).length > 0
                ? string(
                    abi.encodePacked(
                        currentBaseURI,
                        tokenId.toString(),
                        baseExtension
                    )
                )
                : "";
    }
    
    // token URI
    function _baseURI() internal view virtual override returns (string memory) {
        return baseTokenURI;
    }
    
    function setBaseURI(string memory _baseTokenURI) public onlyOwner {
        baseTokenURI = _baseTokenURI;
    }

    function setBaseExtension(string memory _baseExtension) public onlyOwner {
        baseExtension = _baseExtension;
    }
    
    // other functions
    function setSaleState(uint256 _saleState) public onlyOwner {
        saleState = _saleState;
    }
    
    function setPrice(uint256 _newPrice) public onlyOwner() {
        price = _newPrice;
    }
    
    function setVault(address _newVaultAddress) public onlyOwner {
        vault = _newVaultAddress;
    }

    function withdrawAll() public payable onlyOwner {
        require(payable(vault).send(address(this).balance));
    }
}
function _baseURI() internal view virtual override returns (string memory) {
    return baseTokenURI;
}

// token URI