/**
 *Submitted for verification at Etherscan.io on 2021-04-27
*/

// Sources flattened with hardhat v2.2.0 https://hardhat.org
// File @openzeppelin/contracts/utils/introspection/IERC165.sol@v4.0.0

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}


// File contracts/IQLF.sol


pragma solidity >= 0.8.0;

abstract contract IQLF is IERC165 {
    /**
     * @dev Returns if the given address is qualified, implemented on demand.
     */
    function ifQualified (address account) virtual external view returns (bool);

    /**
     * @dev Logs if the given address is qualified, implemented on demand.
     */
    function logQualified (address account, uint256 ito_start_time) virtual external returns (bool);

    /**
     * @dev Ensure that custom contract implements `ifQualified` amd `logQualified` correctly.
     */
    function supportsInterface(bytes4 interfaceId) virtual external override pure returns (bool) {
        return interfaceId == this.supportsInterface.selector ||
        interfaceId == (this.ifQualified.selector ^ this.logQualified.selector);
    }

    /**
     * @dev Emit when `ifQualified` is called to decide if the given `address`
     * is `qualified` according to the preset rule by the contract creator and
     * the current block `number` and the current block `timestamp`.
     */
    event Qualification(address account, bool qualified, uint256 blockNumber, uint256 timestamp);
}


// File contracts/qualification.sol
//import "@openzeppelin/contracts/access/Ownable.sol";


/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}


contract EVA_QLF is IQLF, Ownable {
    string private name;
    uint256 private creation_time;
    uint256 start_time;
    mapping(address => bool) white_list;

    constructor (string memory _name, uint256 _start_time) {
        name = _name;
        creation_time = block.timestamp;
        start_time = _start_time;
    }

    function get_name() public view returns (string memory) {
        return name;
    }

    function get_creation_time() public view returns (uint256) {
        return creation_time;
    }

    function get_start_time() public view returns (uint256) {
        return start_time;
    }

    function set_start_time(uint256 _start_time) public onlyOwner {
        start_time = _start_time;
    }

    function add_address(address account) public onlyOwner returns(bool){
        white_list[account] = true;
        return true;
    }

    function del_address(address account) public onlyOwner returns(bool){
        delete(white_list[account]);
        return true;
    }

    function add_whitelist(address[] calldata addrs) external onlyOwner {
        for (uint256 i = 0; i < addrs.length; i++) {
            white_list[addrs[i]] = true;
        }
    }

    function remove_whitelist(address[] calldata addrs) external onlyOwner {
        for (uint256 i = 0; i < addrs.length; i++) {
            delete white_list[addrs[i]];
        }
    }

    function ifQualified(address addr) public view override returns (bool qualified) {
        if(white_list[addr]){
            return true;
        }
        return false;
    }

    function logQualified(address account, uint256 ito_start_time) public override returns (bool qualified) {
        if (start_time > block.timestamp || ito_start_time > block.timestamp) {
            emit Qualification(account, false, block.number, block.timestamp);
            return false;
        }

        if (white_list[account]) {
            emit Qualification(account, true, block.number, block.timestamp);
            return true;
        }
        emit Qualification(account, false, block.number, block.timestamp);
        return false;
    }

    function supportsInterface(bytes4 interfaceId) external override pure returns (bool) {
        return interfaceId == this.supportsInterface.selector ||
        interfaceId == (this.ifQualified.selector ^ this.logQualified.selector) ||
        interfaceId == this.get_start_time.selector;
    }
}