contract BabyDoodleApes is ERC721Enumerable, Ownable
{
    using SafeMath for uint256;
    using Strings for uint256;

    uint public constant _TOTALSUPPLY = 3333;
    
    uint public maxPerTxn = 20; // 10 - whitelist , 10 - public
    // uint public maxPerWallet = 2; // 2 - whitelist , none - public
    
    uint256 public price = 0.02 ether; 
    uint public status = 0; //0 - pause , 1 - public
    
    bool public revealed = false;
    string public unrevealedUri = "https://gateway.pinata.cloud/ipfs/QmXKWdxoizpb6vXAicGG4iCDVBZsR7hcfeY8MXghKFQC72";
    
    uint private reserved = 30;

    mapping(address => bool) public trackFree;

    constructor() ERC721("BabyDoodleApes", "BDA")  {
        setBaseURI("");
    }
    function gotFree(address a) public returns(bool){
        return trackFree[a];
    }
    function setBaseURI(string memory baseURI) public onlyOwner {
        _baseURI = baseURI;
    }
    function setRevealed() public onlyOwner{
        revealed = !revealed;
    }
    function setunrevealedUri(string memory baseURI) public onlyOwner {
        unrevealedUri = baseURI;
    }
    function setPrice(uint256 _newPrice) public onlyOwner() {
        price = _newPrice;
    }
    function setReserved(uint256 _q) public onlyOwner() {
        reserved = _q;
    }
    function setMaxxQtPerTx(uint256 _quantity) public onlyOwner {
        maxPerTxn=_quantity;
    }
    // function setMaxxQtPerWallet(uint256 _quantity) public onlyOwner {
    //     maxPerWallet=_quantity;
    // }
    function giveaway(address a, uint q) public onlyOwner{
        for(uint i=0; i<q; i++)
            _safeMint(a, totalsupply()+1);
            reserved-=q;
    }
    modifier isSaleOpen{
        require(totalSupply() < _TOTALSUPPLY, "Sale end");
        _;
    }
    function seteStatus(uint s) public onlyOwner {
        status = s;
    }
    function getPrice() public view returns (uint256) {
           return price ;
    }

    function mint(uint chosenAmount) public payable isSaleOpen{
        require( status == 1 , "Sale is not active at the moment" );
        require( totalSupply() + chosenAmount <= _TOTALSUPPLY - reserved , "Quantity must be lesser then MaxSupply" );
        require( chosenAmount > 0 , "Number of tokens can not be less than or equal to 0" );
        require( chosenAmount <= maxPerTxn , "Chosen Amount exceeds MaxQuantity" );
        // require( status == 1 && ( chosenAmount + balanceOf( msg.sender ) <= maxPerWallet ) , "Chosen Amount exceeds MaxQuantity" );
        require( price.mul( trackFree[msg.sender]  ? chosenAmount : chosenAmount-1 ) == msg.value, "Sent ether value is incorrect" );
        for (uint i = 0; i < chosenAmount; i++) {
            _safeMint(msg.sender, totalsupply()+1);
        }
        trackFree[msg.sender] = true;
    }
 
    function tokensOfOwner(address _owner) public view returns (uint256[] memory) {
        uint256 count = balanceOf(_owner);
        uint256[] memory result = new uint256[](count);
        for (uint256 index = 0; index < count; index++) {
            result[index] = tokenOfOwnerByIndex(_owner, index);
        }
        return result;
    }

    function withdraw() public onlyOwner {
        uint balance = address(this).balance;
        payable(msg.sender).transfer(balance);
    }
    function totalsupply() private view returns (uint) {
        return super.totalSupply();
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory base = baseURI();

        if(revealed)
            return bytes(base).length > 0 ? string(abi.encodePacked(base, tokenId.toString(), ".json")) : "";
        else
        return unrevealedUri;
    }
    function contractURI() public view returns (string memory) {
        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "Baby Doodle Apes", "description": "Baby Doodle Apes supports artists, musicians, actors and writers to pursue their dreams, by providing a source of passive income.", "seller_fee_basis_points": 1000, "fee_recipient": "0x34465664e2096eACE7F8d62874aE8B26Eb63b5f9"}'))));
        json = string(abi.encodePacked('data:application/json;base64,', json));
        return json;
    }
}
function giveaway(address a, uint q) public onlyOwner{
        for(uint i=0; i<q; i++)
            _safeMint(a, totalsupply()+1);
            reserved-=q;
    }
// function setMaxxQtPerWallet(uint256 _quantity) public onlyOwner {
//     maxPerWallet=_quantity;
// }