// File: contracts/whitelist.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./WhIn.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract whitelistChecker is WhIn {
    
    using Counters for Counters.Counter;

    mapping(address => bool) public whitelisted;
    address private Owner;
    bool public paused;
    uint256 public whitelistAmount = 3000;
    Counters.Counter amount;

    constructor() {
        Owner = msg.sender;
        whitelisted[msg.sender] = true;
    }

    modifier OnlyOwner {
        require(msg.sender == Owner, "You are not the owner of the contract.");
        _;
    }

    modifier PauseCheck {
        require(paused == false, "Whitelisting is currently paused");
        _;
    }

    function addWhitelist() public PauseCheck {
        require(whitelisted[msg.sender] == false, "User is already present in the whitelist.");
        require(amount.current() < whitelistAmount, "Whitelist limit has been hit.");
        whitelisted[msg.sender] = true;
        amount.increment();
        emit WhitelistChange(msg.sender, true);
    }

    function checkWhitelist(address account) public view override returns(bool) {
        return whitelisted[account];
    }

    function checkWhitelistCounter() public view returns(uint256) {
        return amount.current();
    }

    function removeWhitelist(address _who) public OnlyOwner {
        whitelisted[_who] = false;
        amount.decrement();
        emit WhitelistChange(_who, false);
    }

    function setWhitelistAmount(uint256 _whitelistAmount) public OnlyOwner {
        whitelistAmount = _whitelistAmount;
    }


    function whitelistArray(address[] memory _who, bool _status) public OnlyOwner {
        if (_status == true) {
            require((_who.length - 1) + amount.current() < 3, "Whitelist limit has been hit.");
        }
        for (uint256 i = 0; i < _who.length;) {
            whitelisted[_who[i]] = _status;
            if (_status == true) {
                amount.increment();
            } else {
                amount.decrement();
            }
            emit WhitelistChange(_who[i], _status);
            i += 1;
        }
    }

    function pauseContract(bool _status) public OnlyOwner {
        paused = _status;
    }

    function changeOwner(address _who) public OnlyOwner {
        Owner = _who;
    }
}
// File: contracts/WhIn.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface WhIn {
    function checkWhitelist(address account) external view returns (bool);
    event WhitelistChange(address indexed account, bool indexed status);
}
// File: @openzeppelin/contracts/utils/Counters.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}