import re
from collections import namedtuple
from .exceptions import NotFound, InvalidUsage

Route = namedtuple('Route', ['handler', 'methods', 'pattern', 'parameters'])
Parameter = namedtuple('Parameter', ['name', 'cast'])

REGEX_TYPES = {
    'string': (None, r'[^/]+'),
    'int': (int, r'\d+'),
    'number': (float, r'[0-9\\.]+'),
    'alpha': (None, r'[A-Za-z]+'),
}


class Router:
    """
    Router supports basic routing with parameters and method checks
    Usage:
        @sanic.route('/my/url/<my_parameter>', methods=['GET', 'POST', ...])
        def my_route(request, my_parameter):
            do stuff...

    Parameters will be passed as keyword arguments to the request handling
    function provided Parameters can also have a type by appending :type to
    the <parameter>.  If no type is provided, a string is expected.  A regular
    expression can also be passed in as the type

    TODO:
        This probably needs optimization for larger sets of routes,
        since it checks every route until it finds a match which is bad and
        I should feel bad
    """
    routes = None

    def __init__(self):
        self.routes = []

    def add(self, uri, methods, handler):
        """
        Adds a handler to the route list
        :param uri: Path to match
        :param methods: Array of accepted method names.
        If none are provided, any method is allowed
        :param handler: Request handler function.
        When executed, it should provide a response object.
        :return: Nothing
        """

        # Dict for faster lookups of if method allowed
        methods_dict = None
        if methods:
            methods_dict = {method: True for method in methods}

        parameters = []

        def add_parameter(match):
            # We could receive NAME or NAME:PATTERN
            parameter_name = match.group(1)
            parameter_pattern = 'string'
            if ':' in parameter_name:
                parameter_name, parameter_pattern = parameter_name.split(':', 1)

            default = (None, parameter_pattern)
            # Pull from pre-configured types
            parameter_type, parameter_pattern = REGEX_TYPES.get(parameter_pattern, default)
            parameters.append(Parameter(name=parameter_name, cast=parameter_type))
            return '({})'.format(parameter_pattern)

        pattern_string = re.sub(r'<(.+?)>', add_parameter, uri)
        pattern = re.compile(r'^{}$'.format(pattern_string))

        route = Route(
            handler=handler, methods=methods_dict, pattern=pattern,
            parameters=parameters)
        self.routes.append(route)

    def get(self, request):
        """
        Gets a request handler based on the URL of the request, or raises an
        error
        :param request: Request object
        :return: handler, arguments, keyword arguments
        """

        route = None
        args = []
        kwargs = {}
        for _route in self.routes:
            match = _route.pattern.match(request.url)
            if match:
                for index, parameter in enumerate(_route.parameters, start=1):
                    value = match.group(index)
                    if parameter.cast:
                        kwargs[parameter.name] = parameter.cast(value)
                    else:
                        kwargs[parameter.name] = value
                route = _route
                break

        if route:
            if route.methods and request.method not in route.methods:
                raise InvalidUsage(
                    'Method {} not allowed for URL {}'.format(
                        request.method, request.url), status_code=405)
            return route.handler, args, kwargs
        else:
            raise NotFound('Requested URL {} not found'.format(request.url))

@@ -245,28 +245,27 @@
  'string': (
-None
+str
 , r'%5B%5E/%5D+'),
@@ -342,20 +342,19 @@
 lpha': (
-None
+str
 , r'%5BA-Z
@@ -2043,20 +2043,19 @@
 ault = (
-None
+str
 , parame
@@ -2856,33 +2856,32 @@
 nts%0A        %22%22%22%0A
-%0A
         route = 
@@ -2889,46 +2889,8 @@
 one%0A
-        args = %5B%5D%0A        kwargs = %7B%7D%0A
     
@@ -2897,17 +2897,16 @@
     for 
-_
 route in
@@ -2939,17 +2939,16 @@
 match = 
-_
 route.pa
@@ -3014,70 +3014,13 @@
     
-for index, parameter in enumerate(_route.parameters, start=1):
+break
 %0A   
@@ -3016,32 +3016,38 @@
   break%0A        
+else:%0A
             valu
@@ -3046,302 +3046,74 @@
     
-value = match.group(index)%0A                    if parameter.cast:%0A                        kwargs%5Bparameter.name%5D = parameter.cast(value)%0A                    else:%0A                        kwargs%5Bparameter.name%5D = value%0A                route = _route%0A                break%0A%0A        if route:%0A    
+raise NotFound('Requested URL %7B%7D not found'.format(request.url))%0A%0A
     
@@ -3182,28 +3182,24 @@
             
-    
 raise Invali
@@ -3206,20 +3206,16 @@
 dUsage(%0A
-    
         
@@ -3285,20 +3285,16 @@
         
- 
-   
 request.
@@ -3332,24 +3332,25 @@
 de=405)%0A
+%0A
         
     retu
@@ -3345,134 +3345,133 @@
     
-    return route.handler, args, kwargs%0A        else:%0A            raise NotFound('Requested URL %7B%7D not found'.format(request.url))
+kwargs = %7Bp.name: p.cast(value) for value, p in zip(match.groups(1), route.parameters)%7D%0A        return route.handler, %5B%5D, kwargs
 %0A

Refactor get