contract AccessControl {
    string public constant RoleOwner = "owner";

    struct RoleEntry {
        address addr;
        bool enable;
    }
    struct Role {
        string name;
        mapping (address => RoleEntry) userMap;
        address[] userArray;
    }
    mapping (string =>  Role) roles;
    string[] public roleNames;

    event RoleAdd(address indexed user, string name);
    event RoleRemove(address indexed user, string name);

    constructor() public {
        _roleAdd(RoleOwner, msg.sender);
    }

    function _roleAdd(string _name, address _user) private {
        if ((bytes(_name).length == 0) || (_user == address(0))) {
            return;
        }

        Role storage role = roles[_name];
        if (bytes(role.name).length == 0) {
            role.name = _name;
            roleNames.push(_name);
        }

        RoleEntry storage entry = role.userMap[_user];
        if (entry.addr == address(0)) {
            entry.addr = _user;
            role.userArray.push(_user);
        }
        entry.enable = true;
        emit RoleAdd(_user, _name);
    }

    /**
    * @dev add a role to a user
    * @param _name the name of the role
    * @param _user address of user
    */
    function roleAdd(string _name, address _user) public onlyOwner {
        _roleAdd(_name, _user);
    }

    /**
    * @dev remove a role from a user
    * @param _name the name of the role
    * @param _user address of user
    */
    function roleRemove(string _name, address _user) public onlyOwner {
        roles[_name].userMap[_user].enable = false;
        emit RoleRemove(_user, _name);
    }

    /**
    * @dev check if user has this role
    * @param _name the name of the role
    * @param _user address of user
    * @return bool
    */
    function _roleHas(string _name, address _user) internal view returns (bool){
        return roles[_name].userMap[_user].enable;
    }

    /**
    * @dev reverts if addr does not have role
    * @param _name the name of the role
    * @param _user address of user
    * // reverts
    */
    function roleCheck(string _name, address _user) public view {
        require(_roleHas(_name, _user));
    }

    /**
    * @dev determine if addr has role
    * @param _name the name of the role
    * @param _user address of user
    * @return bool
    */
    function roleHas(string _name, address _user) public view returns (bool) {
        return _roleHas(_name, _user);
    }

    function roleUsers(string _name) public view returns (address[] memory addrs) {
        Role storage role = roles[_name];
        if (role.userArray.length == 0) {
            return;
        }

        uint256 len = 0;
        for (uint256 j = 0; j < role.userArray.length; j++) {
            RoleEntry storage entry = role.userMap[role.userArray[j]];
            if (entry.enable) {
                len++;
            }
        }
        addrs = new address[](len);
        uint256 index = 0;
        for (j = 0; j < role.userArray.length; j++) {
            entry = role.userMap[role.userArray[j]];
            if (entry.enable) {
                addrs[index++] = entry.addr;
            }
        }
    }

    /**
    * @dev modifier to scope access to a single role (uses msg.sender as addr)
    * @param _role the name of the role
    * // reverts
    */
    modifier onlyRole(string _role) {
        roleCheck(_role, msg.sender);
        _;
    }

    modifier onlyOwner() {
        roleCheck(RoleOwner, msg.sender);
        _;
    }
}
function _roleHas(string _name, address _user) internal view returns (bool){
    return roles[_name].userMap[_user].enable;
}

/**
 * @dev check if user has this role
 * @param _name the name of the role
 * @param _user address of user
 * @return bool
 */