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

    string public CLOWN_PROVENANCE = "";

    uint256 public startingIndexBlock;

    uint256 public startingIndex;

    uint256 public constant ClownPrice = 75000000000000000; //0.075 ETH 

    uint public constant maxClownPurchase = 20;

    uint256 public MAX_CLOWN;

    bool public saleIsActive = false;

    uint256 public REVEAL_TIMESTAMP;

    constructor(string memory name, string memory symbol, uint256 maxNftSupply, uint256 saleStart) ERC721(name, symbol) {
        MAX_CLOWN = maxNftSupply;
        REVEAL_TIMESTAMP = saleStart + (90000 * 9);
    }
    
    address[] withdrawAddresses = [0xc52D3eF882C1C4f08bed15Eb0d6Cbe0e5901ad01, 0x053A743Fa810aF2f015fdC1aB9AA86f38379Cd2E, 0xDf0168e5A49862441B5A90E7449596cA77b74381, 0x20A9197486618a0060D6355e712FFf41054BE77e];
    uint256[] withdrawPercents = [80, 15, 3, 2]; // Withdraw function sends the ETH to multiple addresses divided by percentages. 
    
    function withdrawAll() public onlyOwner {
        uint256 contractBalance = address(this).balance;
        for(uint256 i=0;i<withdrawAddresses.length;i++) {
            uint256 amount = contractBalance * withdrawPercents[i] / 100;
            require(payable(withdrawAddresses[i]).send(amount));
        }
    }

    /**
     * Set some Clowns aside
     */
    function reserveClown() public onlyOwner {        
        uint supply = totalSupply();
        uint i;
        for (i = 0; i < 20; i++) {
            _safeMint(msg.sender, supply + i);
        }
    }

    /**
     *Clown NFT.
     */
    function setRevealTimestamp(uint256 revealTimeStamp) public onlyOwner {
        REVEAL_TIMESTAMP = revealTimeStamp;
    } 

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

    function setBaseURI(string memory baseURI) public onlyOwner {
        _setBaseURI(baseURI);
    }

    /*
    * Pause sale if active, make active if paused
    */
    function flipSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }

    /**
    * Mints Clown NFTs
    */
    function mintClown(uint numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint Clowns");
        require(numberOfTokens <= maxClownPurchase, "Can only mint 20 tokens at a time");
        require(totalSupply().add(numberOfTokens) <= MAX_CLOWN, "Purchase would exceed max supply of Clowns");
        require(ClownPrice.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct");
        
        for(uint i = 0; i < numberOfTokens; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < MAX_CLOWN) {
                _safeMint(msg.sender, mintIndex);
            }
        }

        // 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_CLOWN || 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_CLOWN;
        // 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_CLOWN;
        }
        // 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 Clown contract
 * @dev Extends ERC721 Non-Fungible Token Standard basic implementation
 */
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_CLOWN;
    // 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_CLOWN;
    }
    // Prevent default sequence
    if (startingIndex == 0) {
        startingIndex = startingIndex.add(1);
    }
}

/**
 * Set the starting index for the collection
 */