contract BasicSecurityToken is ERC20BurnableWithFinish, ERC20Mintable, Frozenlist, Whitelist {

    /// @dev This emits when funds are reassigned
    event FundsReassigned(address from, address to, uint256 amount);

    /// @dev This emits when funds are revoked
    event FundsRevoked(address from, uint256 amount);

    bytes4 internal constant InterfaceId_BasicSecurityToken = 0x4d1e390c;
    /**
    * 0x4d1e390c ===
    *   bytes4(keccak256('revoke(address)')) ^
    *   bytes4(keccak256('reassign(address,address)')) ^
    *   bytes4(keccak256('frozenlist(address)'))
    */

    constructor(string memory name, string memory symbol, bool enableWhitelist)
    Ownable()
    ERC20(name, symbol)
    Whitelist(enableWhitelist) {
        require(bytes(name).length > 0, "name is empty");
        require(bytes(symbol).length > 0, "symbol is empty");

        _registerInterface(InterfaceId_BasicSecurityToken);
        _setupRole(DEFAULT_ADMIN_ROLE, owner());
        addIssuer(owner());
        if(enableWhitelist) {
            addAddressToWhitelist(owner());
        }
    }

    function decimals() public view virtual override returns (uint8) {
        return 0;
    }

    //Public functions (place the view and pure functions last)
    function mint(address account, uint256 amount) override public onlyOwner onlyIfNotFrozen(account) onlyIfWhitelisted(account) {
        super.mint(account, amount);
    }

    function transfer(address recipient, uint256 amount) override public onlyIfNotFrozen(_msgSender()) onlyIfNotFrozen(recipient) onlyIfWhitelisted(recipient) returns (bool) {
        require(super.transfer(recipient, amount), "Transfer failed");

        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) override public onlyIfNotFrozen(sender) onlyIfNotFrozen(recipient) onlyIfWhitelisted(recipient) returns (bool) {
        require(super.transferFrom(sender, recipient, amount), "Transfer failed");

        return true;
    }

    function reassign(address from, address to) public onlyIssuer {
        uint256 fundsReassigned = balanceOf(from);
        _transfer(from, to, fundsReassigned);

        emit FundsReassigned(from, to, fundsReassigned);
    }

    function reassign(address from, address to, uint256 amount) public onlyIssuer {
        _transfer(from, to, amount);

        emit FundsReassigned(from, to, amount);
    }

    function revoke(address from) public onlyIssuer {
        uint256 fundsRevoked = balanceOf(from);
        _transfer(from, _msgSender(), fundsRevoked);

        emit FundsRevoked(from, fundsRevoked);
    }

    function revoke(address from, uint256 amount) public onlyIssuer {
        _transfer(from, _msgSender(), amount);

        emit FundsRevoked(from, amount);
    }

    function transferOwnership(address _newOwner) override public onlyOwner {
        if(isIssuer(owner())) {
            if(whitelistEnabled) {
                removeAddressFromWhitelist(owner());
                addAddressToWhitelist(_newOwner);
            }
            transferIssuer(_newOwner);
        }
        _setupRole(DEFAULT_ADMIN_ROLE, _newOwner);
        renounceRole(DEFAULT_ADMIN_ROLE, owner());
        super.transferOwnership(_newOwner);
    }

    function renounceOwnership() override public onlyOwner {        
        if(whitelistEnabled) {
            removeAddressFromWhitelist(owner());
        }
        removeIssuer(owner());
        renounceRole(DEFAULT_ADMIN_ROLE, owner());
        super.renounceOwnership();
    }
    //Private functions

}
function mint(address account, uint256 amount) override public onlyOwner onlyIfNotFrozen(account) onlyIfWhitelisted(account) {
    super.mint(account, amount);
}

//Public functions (place the view and pure functions last)