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

    string public provenance = "";

    uint256 public starting_index_block;

    uint256 public starting_index;

    uint256 public constant price = 60000000000000000; // 0.06 ETH

    uint256 public constant maximum_purchase = 50;

    uint256 public total;

    bool public sale_status = true;

    uint256 public timestamp;

    constructor(
        string memory name,
        string memory symbol,
        string memory base_uri,
        uint256 maximum_supply,
        uint256 epoch
    ) public ERC721(name, symbol) {
        total = maximum_supply;
        timestamp = epoch;
        _setBaseURI(base_uri);
    }

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

    // Set some TroubleMakers aside
    function reserve() public onlyOwner {
        uint256 supply = totalSupply();
        uint256 i;
        for (i = 0; i < 60; i++) {
            _safeMint(msg.sender, supply + i);
        }
    }

    // Timestamp
    function set_timestamp(uint256 reset_timestamp) public onlyOwner {
        timestamp = reset_timestamp;
    }

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

    function set_base_uri(string memory base_uri) public onlyOwner {
        _setBaseURI(base_uri);
    }

    // Pause sale if active, make active if paused
    function switch_sale_status() public onlyOwner {
        sale_status = !sale_status;
    }

    // Mint TroubleMakers
    function mint(uint256 quantity) public payable {
        require(
            sale_status,
            "OOOPS! Sale must be ready to mint TroubleMakers."
        );
        require(
            quantity <= maximum_purchase,
            "OOOPS! Can only mint 50 tokens at a time."
        );
        require(
            totalSupply() + quantity <= total,
            "OOOPS! Purchase would exceed the maximum supply of TroubleMakers."
        );
        require(
            price * quantity <= msg.value,
            "OOOPS! Ether value sent is not correct."
        );

        require(
            block.timestamp >= timestamp,
            "OOOPS! Sale has not started yet."
        );

        for (uint256 i = 0; i < quantity; i++) {
            uint256 mint_index = totalSupply();
            if (totalSupply() < total) {
                _safeMint(msg.sender, mint_index);
            }
        }

        // condition to deal with:
        //    - The last saleable token or
        //    - The first token to be sold after the end of pre-sale, set the starting index block
        if (
            starting_index_block == 0 &&
            (totalSupply() == total || block.timestamp >= timestamp)
        ) {
            starting_index_block = block.number;
        }
    }

    // Set the starting index for the collection
    function set_starting_index() public {
        require(starting_index == 0, "OOOPS! Starting index is already set.");
        require(
            starting_index_block != 0,
            "OOOPS! Starting index block must be set."
        );

        starting_index = uint256(blockhash(starting_index_block)) % total;
        // Sanity case in the worst case if this function is called late
        // (EVM only stores last 256 block hashes)
        if (block.number - starting_index_block > 255) {
            starting_index = uint256(blockhash(block.number - 1)) % total;
        }
        // Prevent default sequence
        if (starting_index == 0) {
            starting_index = starting_index + 1;
        }
    }

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

        starting_index_block = block.number;
    }
}
/**
 * @title TheTroubleMarkersClub contract
 * @dev Extends ERC721 Non-Fungible Token Standard basic implementation
 */
function emergency_set_starting_index_block() public onlyOwner {
    require(starting_index == 0, "Starting index is already set.");

    starting_index_block = block.number;
}

// Set the starting index block for the collection, essentially unblocking
// setting starting index