contract DegenDogs is ERC721URIStorage, Ownable {
    event MintDogs(address indexed minter, uint256 startWith, uint256 times);
    uint256 public totalDogs;
    uint256 public totalCount = 5555;
    uint256 public allowedMintedToken = 1500;
    uint256 public maxBatch = 5;
    uint256 public price = 0.05 ether; // 1 eth
    uint256 public whitelistPrice = 0.04 ether;
    string public baseURI;
    bool public started;
    bool public whiteListStart;
  
    mapping(address => bool) whiteList;
    mapping(address => uint256) whiteListMintCount;
    constructor(
        string memory name_,
        string memory symbol_,
        string memory baseURI_
    ) ERC721(name_, symbol_) {
        baseURI = baseURI_;
       _mint(owner(), 1 + totalDogs++);
    }
    modifier canWhitelistMint(uint256 _times) {
        require(whiteListStart, "Hang on boys, youll get in soon");
        require(whiteList[msg.sender] == true, "Not whitelisted.");
        require(totalDogs + _times <= allowedMintedToken, "you cannot mint anymore");
        require(whiteListMintCount[msg.sender] - _times >= 0, "Over mint limit for address.");
        require(totalDogs + _times <= totalCount, "Mint amount will exceed total collection amount.");
        require(_times > 0 && _times <= maxBatch, "mint wrong number");
        require(msg.value == _times * whitelistPrice, "Incorrect transaction value.");
        _;
    }
    modifier canMintMain(uint256 _times){
        require(started, "not started");
        require(_times > 0 && _times <= maxBatch, "mint wrong number");
        require(totalDogs + _times <= allowedMintedToken, "you cannot mint anymore");
        require(totalDogs + _times <= totalCount, "Mint amount will exceed total collection amount.");
        require(msg.value == _times * price, "Incorrect transaction value.");
        _;
    }
  
    function totalSupply() public view virtual returns (uint256) {
        return totalDogs;
    }
    function _baseURI() internal view virtual override returns (string memory) {
        return baseURI;
    }
    function setBaseURI(string memory _newURI) public onlyOwner {
        baseURI = _newURI;
    }
    function setTotalCount(uint256 _totalCount) public onlyOwner {
        totalCount = _totalCount;
    }
     function setAllowedMintedToken(uint256 _AllowedTokenAmount) public onlyOwner {
        allowedMintedToken = _AllowedTokenAmount;
    }
    
    function changePrice(uint256 _newPrice) public onlyOwner {
        price = _newPrice;
    }
    // maxBatch
    function setMaxBatch(uint256 _newMaxBatch) public onlyOwner {
        maxBatch = _newMaxBatch;
    }
     function changeWhiteListPrice(uint256 _newPrice) public onlyOwner {
        whitelistPrice = _newPrice;
    }
    function setTokenURI(uint256 _tokenId, string memory _tokenURI)
        public
        onlyOwner
    {
        _setTokenURI(_tokenId, _tokenURI);
    }
    function setNormalStart(bool _start) public onlyOwner {
        started = _start;
    }
    function setWhiteListStart(bool _start) public onlyOwner {
        whiteListStart = _start;
    }
    function getWhitelistMintAmount(address _addr)
        public
        view
        virtual
        returns (uint256)
    {
        return whiteListMintCount[_addr];
    }
    function publicMint(uint256 _times) public payable canMintMain(_times){
        payable(owner()).transfer(msg.value);
        emit MintDogs(_msgSender(), totalDogs + 1, _times);
        for (uint256 i = 0; i < _times; i++) {
            _mint(_msgSender(), 1 + totalDogs++);
        }
    }
  
    function whitelistMint(uint256 _times) public payable canWhitelistMint(_times) {
        payable(owner()).transfer(msg.value);
        whiteListMintCount[_msgSender()] -= _times;
        emit MintDogs(_msgSender(), totalDogs + 1, _times);
        for (uint256 i = 0; i < _times; i++) {
            _mint(_msgSender(), 1 + totalDogs++);
        }
    }
    function adminMintGiveaways(address _addr) public onlyOwner {
        require(
            totalDogs + 1 <= totalCount,
            "Mint amount will exceed total collection amount."
        );
        emit MintDogs(_addr, totalDogs + 1, 1);
        _mint(_addr, 1 + totalDogs++);
    }
    function addToWhitelist(address _addr)
        public
        onlyOwner
    {
        whiteList[_addr] = true;
        whiteListMintCount[_addr] = 3;
    }
    function addToWhitelistBulk(
        address[] memory _addr
    ) public onlyOwner {
        for (uint256 i = 0; i < _addr.length; i++) {
            whiteList[_addr[i]] = true;
            whiteListMintCount[_addr[i]] = 3;
        }
    }
    //Check address is in whiteList
    function isAddressInWhitelist(address _addr)
        public
        view
        virtual
        returns (bool)
    {
        return whiteList[_addr] == true;
    }
}
function setMaxBatch(uint256 _newMaxBatch) public onlyOwner {
    maxBatch = _newMaxBatch;
}

// maxBatch