contract PerkyPineapples is ERC721, Ownable {

    bool public saleIsActive = false;

    uint256 public price = 0.025 ether;
	uint public maxPerTx = 10;
	uint public maxFreeMintPerWallet = 20;
	uint public amountAvailableFreeMint = 200;
	uint public maxSupply = 5000;
	address proxyRegistryAddress ; 
	mapping(address => uint) public addressFreeMinted;
    string public _hiddenURI = "ipfs://QmRkNnfQExTwer7vL1PNuRszzshpUWjRb7AerWQt1Ef82Q/hidden.json";
    string public _baseURIextended = "";
	
    using Counters for Counters.Counter;
    Counters.Counter private _tokenSupply;

    constructor() ERC721("PerkyPineapples", "PP") {
        for (uint256 i = 0; i < 10; i++){
            gift(msg.sender);
        }
    }

    function totalSupply() public view returns (uint256 supply) {
        return _tokenSupply.current();
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return _baseURIextended;
    }

    function isApprovedForAll(address owner, address operator)
        public
        view
        override
        returns (bool)
    {
        ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
        if (address(proxyRegistry.proxies(owner)) == operator) {
            return true;
        }

        return super.isApprovedForAll(owner, operator);
    }

    function mint(uint numberOfTokens) external payable {
        require(saleIsActive, "Sale is inactive.");
        require(numberOfTokens <= maxPerTx, "You can only mint 10 at a time.");
        require(_tokenSupply.current() + numberOfTokens <= maxSupply, "Purchase would exceed max supply of tokens");
        
        if (_tokenSupply.current() + numberOfTokens > amountAvailableFreeMint) {
            require((price * numberOfTokens) <= msg.value, "Don't send under (in ETH).");
        } else {
			require(msg.value == 0, "Don't send ether for the free mint.");
			require(addressFreeMinted[msg.sender] < maxFreeMintPerWallet, "You can only adopt 20 free CAU per wallet. Wait for the paid adoption.");
		}
		
		addressFreeMinted[msg.sender] += numberOfTokens;
        for(uint i = 0; i < numberOfTokens; i++) {
		  uint256 _tokenId = _tokenSupply.current() + 1;
            _safeMint(msg.sender, _tokenId);
            _tokenSupply.increment();
        }
    }

     function gift(address _to) public onlyOwner {
        uint256 _tokenId = _tokenSupply.current() + 1;
        _safeMint(_to, _tokenId);
        _tokenSupply.increment();
    }

    function withdraw() public onlyOwner {
        (bool success, ) = msg.sender.call{value: address(this).balance}("");
        require(
            success,
            "Address: unable to send value, recipient may have reverted"
        );
    }

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

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ?
         string(abi.encodePacked(baseURI, Strings.toString(tokenId), ".json")) :
          _hiddenURI;
    }

    function setSaleIsActive(bool newState) public onlyOwner {
        saleIsActive = newState;
    }

    function setPrice(uint newPrice) public onlyOwner {
        price = newPrice;
    }

    function setMaxPerTx(uint _maxPerTx) external onlyOwner() {
        maxPerTx = _maxPerTx;
    }

    function setMaxFreeMintPerWallet(uint _maxFreeMint) public onlyOwner() {
        maxFreeMintPerWallet = _maxFreeMint;
    }

    function setAmountAvailableFreeMint(uint _freeMint) public onlyOwner() {
        amountAvailableFreeMint = _freeMint;
    }

    function setMaxSupply(uint _maxSupply) public onlyOwner() {
        maxSupply = _maxSupply;
    }

    // rinkeby: 0xf57b2c51ded3a29e6891aba85459d600256cf317
    // mainnet: 0xa5409ec958c83c3f309868babaca7c86dcb077c1
    function setProxyRegistryAddress(address proxyAddress) external onlyOwner {
        proxyRegistryAddress = proxyAddress;
    }

    function setHiddenUri(string memory hiddenURI) public onlyOwner() {
        _hiddenURI = hiddenURI;
    }

    function setBaseURI(string memory baseURI_) external onlyOwner() {
        _baseURIextended = baseURI_;
    }
}
function setProxyRegistryAddress(address proxyAddress) external onlyOwner {
    proxyRegistryAddress = proxyAddress;
}

// rinkeby: 0xf57b2c51ded3a29e6891aba85459d600256cf317
// mainnet: 0xa5409ec958c83c3f309868babaca7c86dcb077c1