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

    uint256 public constant maxSupply = 6000;
    uint256 public constant price = 5*10**16;
    uint256 public constant purchaseLimit = 20;
    uint256 public constant reserveAmount = 50;
    uint256 public constant reservations = 2;
    uint256 public saleStart = 1631228400;
    
    string public contractURI;
    string public provenance;
    bool public saleIsActive = true;
    uint256 public reserved = 0;
    address public treasury = 0xa84410A90214E2217E957C85690D4133912d81C1;
    address payable public payee = payable(0x2CB0cF7882244f4A3B89aB42c5D9296BBed2685F);
    

    constructor (
        string memory name,
        string memory symbol
        ) public ERC721(name, symbol) {
    }

    /** 
     * emergency withdraw function, callable by anyone
     */
    function withdraw() public {
        payee.transfer(address(this).balance);
    }

    /**
     * reserve
     */
    function reserve() public onlyOwner {
        //rug prevention
        require(totalSupply().add(reserveAmount) < maxSupply, "mint would exceed maxSupply");
        require(reserved < reservations, "reservations have been claimed already");
        reserved ++;
        uint supply = totalSupply();
        uint i;
        for (i = 0; i < reserveAmount; i++) {
            if (i > 34 && reserved == 2 ) {
                _safeMint(msg.sender, supply + i);
            } else{ 
                _safeMint(treasury, supply + i);
            }
        }
    }

    /**
     *
    */
    function setProvenance(string memory _provenance) public onlyOwner {
        provenance = _provenance;
    }

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

    /*
    * set contractURI
    */
    function setContractURI(string memory _contractURI) public onlyOwner {
        contractURI = (_contractURI);
    }

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

    /*
    * updates saleStart
    */
    function setSaleStart(uint256 _saleStart) public onlyOwner {
        saleStart = _saleStart;
    }

    /**
    * mint
    */
    function mint(uint numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint");
        require(block.timestamp >= saleStart, "Sale has not started yet, timestamp too low");
        require(numberOfTokens <= purchaseLimit, "Can only mint purchaseLimit() at a time");
        require(totalSupply().add(numberOfTokens) <= maxSupply, "Purchase would exceed maxSupply");
        require(price.mul(numberOfTokens) <= msg.value, "Ether value sent is too low");
        
        payee.transfer(address(this).balance);
        
        for(uint i = 0; i < numberOfTokens; i++) {
            uint mintIndex = totalSupply();
            if (totalSupply() < maxSupply) {
                _safeMint(msg.sender, mintIndex);
            }
        }
    }

}
/**
 * @title NFT contract - forked from BAYC
 * @dev Extends ERC721 Non-Fungible Token Standard basic implementation
 */
function setSaleStart(uint256 _saleStart) public onlyOwner {
    saleStart = _saleStart;
}

/*
 * updates saleStart
 */