# Path: m2core/common/permissions.py
# class PermissionsEnum(metaclass=PermissionsEnumMeta):
#     AUTHORIZED = Permission('authorized')
# 
#     @classproperty
#     def ALL(cls):
#         cache_var_name = '__all_cache'
#         cached_perms = getattr(cls, cache_var_name, None)
#         if cached_perms is None:
#             setattr(cls, cache_var_name, set())
#             cached_perms = getattr(cls, cache_var_name)
#             for attr_name in dir(cls):
#                 if not attr_name.startswith('_') and attr_name != 'ALL':
#                     attr = getattr(cls, attr_name)
#                     if type(attr) is Permission:
#                         cached_perms.add(attr)
#         return cached_perms
# 
#     @classproperty
#     def SKIP(cls):
#         return lambda p: True
# 
#     @classproperty
#     def all_platform_permissions(cls):
#         sub_classes = PermissionsEnum.registry
#         all_perms = set()
#         for c in sub_classes:
#             all_perms |= c.ALL
# 
#         return all_perms
# 
# Path: m2core/utils/url_parser.py
# class UrlParser:
#     """
#     Great class for making url masks, generating validators for url parameters, url attribute descriptions.
#     Here are examples of different url masks which you can comfortably use:
# 
#     /users/:{id} -> :id - attribute, any type
#     /users/:{id:int} -> :id - int attribute, any length
#     /users/:{id:int(2)} -> :id - int attribute, length is 2 numbers
#     /users/:{id:float} -> :id - float attribute
#     /users/:{id:float(3)} -> :id - float attribute, length is 3 numbers including `,`
#     /users/:{id:float(2,5)} -> :id - float attribute, length is between 2 and 5 numbers including `,`
#     /users/:{id:string} -> :id - string, any length, without `/` symbol
#     /users/:{id:string(2)} -> :id - string,  length is 2 symbols, without `/` symbol
#     /users/:{id:bool} -> :id - bool flag, accepts only `0` or `1`
#     /users/:{id:int(0,[0-100])} -> :id - int, any length (0), but value must be between `0` and `100`
#     /users/:{id:float(0,[0-100])} -> :id - float, any length (0), but value must be between `0` and `100`
#     /users/:{id:string(0,[string1;string2;string3])} -> :id - string, any length (0), but value must be in list
#                                         of values: ('string1', 'string2', 'string3')
#     """
# 
#     def __init__(self, url: str):
#         self.original_url = url
#         self.url_attributes = []
#         self._full_match = ''
#         self.__parse()
# 
#     def __parse(self):
#         # check for `:{}`
#         m = re.finditer(r':{(?P<attr_name>\w+)(?:(?::(?P<attr_type>|int|float|string|bool))'
#                         r'(?:\((?P<type_params>[^)]+)\))?)?}', self.original_url)
#         for match in m:
#             attr = UrlParserAttr(match.group('attr_name'), match.group('attr_type'), match.group('type_params'))
#             self.url_attributes.append({'instance': attr, 'full_match': match.group(0)})
# 
#     def tornado_url(self):
#         result = self.original_url
#         for attr in self.url_attributes:
#             result = result.replace(attr['full_match'], attr['instance'].replacement(), 1)
#         return result
# 
#     def params(self):
#         result = dict()
#         for param in self.url_attributes:
#             result[param['instance'].name()] = param['instance'].params()
#         return result
# 
#     def validator_schema(self):
#         result = dict()
#         for attr in self.url_attributes:
#             result.update(attr['instance'].validator())
#         return Schema(result)
# 
#     def __repr__(self):
#         return self.original_url


from collections import defaultdict
from tornado.web import RequestHandler
from typing import Type
from m2core.common.permissions import PermissionsEnum
from m2core.utils.url_parser import UrlParser


class Rules(defaultdict):
    def validator(self, human_route: str=None):
        return self[human_route]['validator']

    def docs(self, human_route: str=None, method: str=None):
        return self[human_route]['docs'].get(method.upper())

    def permissions(self, human_route: str=None, method: str=None):
        return self[human_route]['permissions'].get(method.upper())

    def group(self, human_route: str=None):
        return self[human_route]['group']

    def add_meta(self, human_route, handler_cls: Type[RequestHandler], rule_group: str, method_permissions: dict) \
            -> UrlParser:
        # add documentation per each method in SUPPORTED_METHODS
        for method in handler_cls.__dict__:
            method_upper = method.upper()
            if method_upper in handler_cls.SUPPORTED_METHODS:
                self[human_route]['docs'][method_upper] = handler_cls.__dict__[method].__doc__
                # also add permissions per each method. default - skip check
                permissions = PermissionsEnum.SKIP
                for m, p in method_permissions.items():
                    if m.upper() == method_upper:
                        permissions = p
                        break
                self[human_route]['permissions'][method_upper] = permissions
        self[human_route]['group'] = rule_group

# Path: m2core/common/permissions.py
# class PermissionsEnum(metaclass=PermissionsEnumMeta):
#     AUTHORIZED = Permission('authorized')
# 
#     @classproperty
#     def ALL(cls):
#         cache_var_name = '__all_cache'
#         cached_perms = getattr(cls, cache_var_name, None)
#         if cached_perms is None:
#             setattr(cls, cache_var_name, set())
#             cached_perms = getattr(cls, cache_var_name)
#             for attr_name in dir(cls):
#                 if not attr_name.startswith('_') and attr_name != 'ALL':
#                     attr = getattr(cls, attr_name)
#                     if type(attr) is Permission:
#                         cached_perms.add(attr)
#         return cached_perms
# 
#     @classproperty
#     def SKIP(cls):
#         return lambda p: True
# 
#     @classproperty
#     def all_platform_permissions(cls):
#         sub_classes = PermissionsEnum.registry
#         all_perms = set()
#         for c in sub_classes:
#             all_perms |= c.ALL
# 
#         return all_perms
# 
# Path: m2core/utils/url_parser.py
# class UrlParser:
#     """
#     Great class for making url masks, generating validators for url parameters, url attribute descriptions.
#     Here are examples of different url masks which you can comfortably use:
# 
#     /users/:{id} -> :id - attribute, any type
#     /users/:{id:int} -> :id - int attribute, any length
#     /users/:{id:int(2)} -> :id - int attribute, length is 2 numbers
#     /users/:{id:float} -> :id - float attribute
#     /users/:{id:float(3)} -> :id - float attribute, length is 3 numbers including `,`
#     /users/:{id:float(2,5)} -> :id - float attribute, length is between 2 and 5 numbers including `,`
#     /users/:{id:string} -> :id - string, any length, without `/` symbol
#     /users/:{id:string(2)} -> :id - string,  length is 2 symbols, without `/` symbol
#     /users/:{id:bool} -> :id - bool flag, accepts only `0` or `1`
#     /users/:{id:int(0,[0-100])} -> :id - int, any length (0), but value must be between `0` and `100`
#     /users/:{id:float(0,[0-100])} -> :id - float, any length (0), but value must be between `0` and `100`
#     /users/:{id:string(0,[string1;string2;string3])} -> :id - string, any length (0), but value must be in list
#                                         of values: ('string1', 'string2', 'string3')
#     """
# 
#     def __init__(self, url: str):
#         self.original_url = url
#         self.url_attributes = []
#         self._full_match = ''
#         self.__parse()
# 
#     def __parse(self):
#         # check for `:{}`
#         m = re.finditer(r':{(?P<attr_name>\w+)(?:(?::(?P<attr_type>|int|float|string|bool))'
#                         r'(?:\((?P<type_params>[^)]+)\))?)?}', self.original_url)
#         for match in m:
#             attr = UrlParserAttr(match.group('attr_name'), match.group('attr_type'), match.group('type_params'))
#             self.url_attributes.append({'instance': attr, 'full_match': match.group(0)})
# 
#     def tornado_url(self):
#         result = self.original_url
#         for attr in self.url_attributes:
#             result = result.replace(attr['full_match'], attr['instance'].replacement(), 1)
#         return result
# 
#     def params(self):
#         result = dict()
#         for param in self.url_attributes:
#             result[param['instance'].name()] = param['instance'].params()
#         return result
# 
#     def validator_schema(self):
#         result = dict()
#         for attr in self.url_attributes:
#             result.update(attr['instance'].validator())
#         return Schema(result)
# 
#     def __repr__(self):
#         return self.original_url


# Path: m2core/common/rules.py
from collections import defaultdict
from tornado.web import RequestHandler
from typing import Type
from m2core.common.permissions import PermissionsEnum
from m2core.utils.url_parser import UrlParser



class Rules(defaultdict):
    def validator(self, human_route: str=None):
        return self[human_route]['validator']

    def docs(self, human_route: str=None, method: str=None):
        return self[human_route]['docs'].get(method.upper())

    def permissions(self, human_route: str=None, method: str=None):
        return self[human_route]['permissions'].get(method.upper())

    def group(self, human_route: str=None):
        return self[human_route]['group']

    def add_meta(self, human_route, handler_cls: Type[RequestHandler], rule_group: str, method_permissions: dict) \
            -> UrlParser:
        # add documentation per each method in SUPPORTED_METHODS
        for method in handler_cls.__dict__:
            method_upper = method.upper()
            if method_upper in handler_cls.SUPPORTED_METHODS:
                self[human_route]['docs'][method_upper] = handler_cls.__dict__[method].__doc__
                # also add permissions per each method. default - skip check
                permissions = PermissionsEnum.SKIP
                for m, p in method_permissions.items():
                    if m.upper() == method_upper:
                        permissions = p
                        break
                self[human_route]['permissions'][method_upper] = permissions
        self[human_route]['group'] = rule_group

        url_parser = UrlParser(human_route)