contract CryptoChampions is ERC721, Ownable {
    using SafeMath for uint256;

    string public HOUND_PROVENANCE = "";

    uint256 public startingIndexBlock;

    uint256 public startingIndex;

    uint256 public championPrice = 100000000000000000; //0.1 ETH

    uint public maxChampionPurchase = 2;

    uint256 public MAX_CHAMPIONS;

    bool public saleIsActive = false;

    uint256 public REVEAL_TIMESTAMP;

    constructor(string memory name, string memory symbol, uint256 maxNftSupply, uint256 saleStart) ERC721(name, symbol) {
        MAX_CHAMPIONS = maxNftSupply;
        REVEAL_TIMESTAMP = block.timestamp + 7 days;

    }

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

    function setRevealTimestamp(uint256 revealTimeStamp) public onlyOwner {
        REVEAL_TIMESTAMP = revealTimeStamp;
    }

    function setChampionPrice(uint256 newChampionPrice) public onlyOwner {
        championPrice = newChampionPrice;
    }

    function setMaxChampionPurchase(uint newMaxChampionPurchase) public onlyOwner {
        maxChampionPurchase = newMaxChampionPurchase;
    }

    /*
    * Set provenance once it's calculated
    */
    function setProvenanceHash(string memory provenanceHash) public onlyOwner {
        HOUND_PROVENANCE = provenanceHash;
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }
    /*
    * Set tokenURI (new Added)
    */
    function setTokenURI(uint256 tokenId, string memory _tokenURI) public onlyOwner {
        _setTokenURI(tokenId, _tokenURI);
    }
    /*
    * Pause sale if active, make active if paused
    */
    function flipSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }

    function transferFrom(address from, address to, uint256 tokenId) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        require(block.timestamp >= REVEAL_TIMESTAMP, "ERC721: can not transfer before REVEAL TIME");
        require(balanceOf(to) < maxChampionPurchase, "ERC721: can not possess more than MAX_PURCHASE");
        _transfer(from, to, tokenId);
    }

    /**
    * Mints Crypto Champions
    */
    function mintCryptoChampions(uint numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint Crypto Champion");
        require(numberOfTokens <= maxChampionPurchase, "Can only mint 2 tokens at a time");
        require(totalSupply().add(numberOfTokens) <= MAX_CHAMPIONS, "Purchase would exceed max supply of Crypto Champions");
        require(championPrice.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct");
        require(balanceOf(msg.sender) + numberOfTokens <= maxChampionPurchase, "ERC721: can not possess more than MAX_PURCHASE");

        for(uint i = 0; i < numberOfTokens; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < MAX_CHAMPIONS) {
                _safeMint(msg.sender, mintIndex.add(1));
            }
        }

        // If we haven't set the starting index and this is either 1) the last saleable token or 2) the first token to be sold after
        // the end of pre-sale, set the starting index block
        if (startingIndexBlock == 0 && (totalSupply() == MAX_CHAMPIONS || block.timestamp >= REVEAL_TIMESTAMP)) {
            startingIndexBlock = block.number;
        }
    }
    
    /**
     * Set the starting index for the collection
     */
    function setStartingIndex() public {
        require(startingIndex == 0, "Starting index is already set");
        require(startingIndexBlock != 0, "Starting index block must be set");

        startingIndex = uint(blockhash(startingIndexBlock)) % MAX_CHAMPIONS;
        // 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_CHAMPIONS;
        }
        // Prevent default sequence
        if (startingIndex == 0) {
            startingIndex = startingIndex.add(1);
        }
    }

    /**
     * Set the starting index block for the collection, essentially unblocking
     * setting starting index
     */
    function emergencySetStartingIndexBlock() public onlyOwner {
        require(startingIndex == 0, "Starting index is already set");

        startingIndexBlock = block.number;
    }
}
/**
 * @title CryptoChampions contract
 * @dev Extends ERC721 Non-Fungible Token Standard basic implementation
 */
function mintCryptoChampions(uint numberOfTokens) public payable {
    require(saleIsActive, "Sale must be active to mint Crypto Champion");
    require(numberOfTokens <= maxChampionPurchase, "Can only mint 2 tokens at a time");
    require(totalSupply().add(numberOfTokens) <= MAX_CHAMPIONS, "Purchase would exceed max supply of Crypto Champions");
    require(championPrice.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct");
    require(balanceOf(msg.sender) + numberOfTokens <= maxChampionPurchase, "ERC721: can not possess more than MAX_PURCHASE");

    for(uint i = 0; i < numberOfTokens; i++) {
        uint mintIndex = totalSupply();
        if (totalSupply() < MAX_CHAMPIONS) {
            _safeMint(msg.sender, mintIndex.add(1));
        }
    }

    // If we haven't set the starting index and this is either 1) the last saleable token or 2) the first token to be sold after
    // the end of pre-sale, set the starting index block
    if (startingIndexBlock == 0 && (totalSupply() == MAX_CHAMPIONS || block.timestamp >= REVEAL_TIMESTAMP)) {
        startingIndexBlock = block.number;
    }
}

/**
 * Mints Crypto Champions
 */