contract DoodShib is ERC721("DoodShib", "DOOD"), ERC721Enumerable, Ownable {
    using SafeMath for uint256;
    using Strings for uint256;

    string private baseURI;
    string private blindURI;
    uint256 public constant MAX_PUBLIC_ONE_WALLET = 10;
    uint256 public constant MAX_FREE_MINT = 900;
    uint256 public constant MAX_NFT_PUBLIC = 6962;
    uint256 private constant MAX_NFT = 6969;
    uint256 public  price = 35000000000000000;  // 0.035 ETH
    bool public reveal;
    bool public isActive;

    uint256 public freeMintCount;
    mapping(address => uint256) private userMinted;



    /*
     * Function to reveal all NFTs
    */
    function revealNow() 
        external 
        onlyOwner 
    {
        reveal = true;
    }
    
    
    /*
     * Function setIsActive to activate/desactivate the smart contract
    */
    function setIsActive(
        bool _isActive
    ) 
        external 
        onlyOwner 
    {
        isActive = _isActive;
    }
    
    /*
     * Function to set Base and Blind URI 
    */
    function setURIs(
        string memory _blindURI, 
        string memory _URI
    ) 
        external 
        onlyOwner 
    {
        blindURI = _blindURI;
        baseURI = _URI;
    }
    
    /*
     * Function to withdraw collected amount during minting by the owner
    */

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

    /*
     * Function to mint new NFTs during the public sale
     * It is payable. Amount is calculated as per (price.mul(_numOfTokens))
    */
    function mint(
        uint256 _numOfTokens
    )
        public
        payable
    {
        require(isActive, "Contract is not active");
        require(_numOfTokens.add(userMinted[msg.sender]) <= MAX_PUBLIC_ONE_WALLET, "Cannot mint about max limit");
        require(totalSupply().add(_numOfTokens) <= MAX_NFT_PUBLIC, "Purchase would exceed max public supply of NFTs");
        require(price.mul(_numOfTokens) == msg.value, "Ether value sent is not correct");

        uint256 feeBack = 0;
        for (uint i = 0; i < _numOfTokens; i++) {
            userMinted[msg.sender] += 1;
            _safeMint(msg.sender, totalSupply().add(1));

            uint ran = random(totalSupply().add(i));
            if (ran == 1 && freeMintCount <= 900) {
                freeMintCount = freeMintCount.add(1);
                feeBack = feeBack.add(price);
            }
        }

        if (feeBack > 0) {
            payable(msg.sender).transfer(feeBack);
        }

    }

    function random(
        uint256 salt
    ) 
        public view returns (uint) 
    {
        return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, salt))) % 2;
    }

    
    /*
     * Function to mint NFTs for giveaway and partnerships
    */
    function mintByOwner(
        address _to, 
        uint256 _tokenId
    )
        public 
        onlyOwner
    {
        require(_tokenId <= MAX_NFT, "Tokens number to mint cannot exceed number of MAX tokens");
        _safeMint(_to, _tokenId);
    }
    
    /*
     * Function to mint all NFTs for giveaway and partnerships
    */
    function mintMultipleByOwner(
        address[] memory _to, 
        uint256[] memory _tokenId
    )
        public
        onlyOwner
    {
        require(_to.length == _tokenId.length, "Should have same length");
        for(uint256 i = 0; i < _to.length; i++){
            require(_tokenId[i] > MAX_NFT_PUBLIC, "Tokens number to mint must exceed number of public tokens");
            require(_tokenId[i] <= MAX_NFT, "Tokens number to mint cannot exceed number of MAX tokens");
            _safeMint(_to[i], _tokenId[i]);
        }
    }

    /*
     * Function to get token URI of given token ID
     * URI will be blank untill totalSupply reaches MAX_NFT_PUBLIC
    */
    function tokenURI(
        uint256 _tokenId
    )
        public 
        view 
        virtual 
        override 
        returns (string memory) 
    {
        require(_exists(_tokenId), "ERC721Metadata: URI query for nonexistent token");
        uint256 blindId = _tokenId % 7;
        if (!reveal) {
            if (blindId == 0) {
                blindId = 7;
            }
            return string(abi.encodePacked(blindURI, abi.encodePacked(blindId.toString(), ".json")));
        } else {
            return string(abi.encodePacked(baseURI, abi.encodePacked(_tokenId.toString(), ".json")));
        }
    }
    
    function supportsInterface(
        bytes4 _interfaceId
    ) 
        public
        view 
        override (ERC721, ERC721Enumerable) 
        returns (bool) 
    {
        return super.supportsInterface(_interfaceId);
    }

    // Standard functions to be overridden 
    function _beforeTokenTransfer(
        address _from, 
        address _to, 
        uint256 _tokenId
    ) 
        internal 
        override(ERC721, ERC721Enumerable) 
    {
        super._beforeTokenTransfer(_from, _to, _tokenId);
    }

}
function revealNow() 
    external 
    onlyOwner 
{
    reveal = true;
}

/*
 * Function to reveal all NFTs
 */