contract DirtyDevils is ERC721URIStorage, Ownable{
 
    event MintDevils (address indexed minter, uint256 startWith, uint256 times);
    
    
    uint256 public totalDevils;
    uint256 public totalCount = 8888; //bruhTotal
    uint256 public maxBatch = 20; // bruhBatch
    uint256 public price = 70000000000000000; // 0.07 eth
    string public baseURI;
    bool public started;
    bool public whiteListStart;
    mapping(address => bool) whiteList;
    mapping(address => uint256) whiteListMintCount;
    uint addressRegistryCount;
    
    constructor(string memory name_, string memory symbol_, string memory baseURI_) ERC721(name_, symbol_) {
        baseURI = baseURI_;
    }
    
    modifier canWhitelistMint() {
        require(whiteListStart, "Hang on boys, youll get in soon");
        require(whiteList[msg.sender] == true, "Not whitelisted.");
        _; 
    }

    modifier mintEnabled() {
        require(started, "not started");
        _;
    }
 
    function totalSupply() public view virtual returns (uint256) {
        return totalDevils;
    }
 
    function _baseURI() internal view virtual override returns (string memory){
        return baseURI;
    }
 
    function setBaseURI(string memory _newURI) public onlyOwner {
        baseURI = _newURI;
    }
 
    function changePrice(uint256 _newPrice) public onlyOwner {
        price = _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 mintDevil(uint256 _times) payable public mintEnabled {
        require(_times >0 && _times <= maxBatch, "mint wrong number");
        require(totalDevils + _times <= totalCount, "too much");
        require(msg.value == _times * price, "value error");
        payable(owner()).transfer(msg.value);
        emit MintDevils(_msgSender(), totalDevils+1, _times);
        for(uint256 i=0; i< _times; i++){
            _mint(_msgSender(), 1 + totalDevils++);
        }
    } 
    
    function adminMint(uint256 _times) payable public onlyOwner {
        require(_times >0 && _times <= maxBatch, "mint wrong number");
        require(totalDevils + _times <= totalCount, "too much");
        require(msg.value == _times * price, "value error");
        payable(owner()).transfer(msg.value);
        emit MintDevils(_msgSender(), totalDevils+1, _times);
        for(uint256 i=0; i< _times; i++){
            _mint(_msgSender(), 1 + totalDevils++);
        }
    }
    
    
    function whitelistMint(uint _times) payable public canWhitelistMint {
        require(whiteListMintCount[msg.sender] - _times >= 0, "Over mint limit for address.");
        require(totalDevils + _times <= totalCount, "Mint amount will exceed total collection amount.");
        require(msg.value == _times * price, "Incorrect transaction value.");
        payable(owner()).transfer(msg.value);
        whiteListMintCount[_msgSender()] -= _times;
        emit MintDevils(_msgSender(), totalDevils+1, _times);
        for(uint256 i=0; i< _times; i++){
            _mint(_msgSender(), 1 + totalDevils++);
        }
    }
    
    
    function adminMintGiveaways(address _addr) public onlyOwner {
        require(totalDevils + 1 <= totalCount, "Mint amount will exceed total collection amount.");
        emit MintDevils(_addr, totalDevils+1, 1);
        _mint(_addr, 1 + totalDevils++);
    } 
    
    
    function addToWhitelist(address _addr, uint numberOfMints) public onlyOwner {
        whiteList[_addr] = true;
        whiteListMintCount[_addr] = numberOfMints;
        addressRegistryCount++;
    }
    
    function addToWhitelistBulk(address[] memory _addr,uint[] memory _numberOfMints) public onlyOwner {
        for(uint256 i = 0; i < _addr.length; i++){
            whiteList[_addr[i]] = true;
            whiteListMintCount[_addr[i]] = _numberOfMints[i];
        }
    }
    
    //Check address is in whiteList 
    function isAddressInWhitelist(address _addr) public view virtual returns(bool) {
            return whiteList[_addr] == true;
    }
    
}
function isAddressInWhitelist(address _addr) public view virtual returns(bool) {
        return whiteList[_addr] == true;
}

//Check address is in whiteList 