 
 import Foundation
 
-public typealias Parameters = [String: String]
-
-protocol Routable {
-    associatedtype Handler
+public struct Route {
     
-    var pattern: String { get set }
-    var dynamicSegments: [String] { get set }
-    var queue: dispatch_queue_t { get set }
-    var handler: Handler { get set }
+    public typealias Parameters = [String: String]
+    public typealias RouteHandler = (String, Parameters, Completed) -> Void
+    public typealias Completed = () -> Void
+    public typealias ProxyHandler = (String, Parameters, Next) -> Void
+    public typealias Next = (String?, Parameters?) -> Void
     
-    init(pattern: String, dynamicSegments: [String], queue: dispatch_queue_t, handler: Handler)
-    static func register(pattern: String, queue: dispatch_queue_t, handler: Handler) -> Self
-    func matches(route: String, inout parameters: Parameters) -> Bool
-}
-
-extension Routable {
-    static func register(pattern: String, queue: dispatch_queue_t, handler: Handler) -> Self {
+    private enum HandlerType {
+        case Route(RouteHandler)
+        case Proxy(ProxyHandler)
+    }
+    
+    private let pattern: String
+    private let dynamicSegments: [String]
+    private let queue: dispatch_queue_t
+    private let handler: HandlerType
+    private var isProxy: Bool {
+        if case HandlerType.Proxy(_) = handler {
+            return true
+        }
+        return false
+    }
+    
+    private init(_ pattern: String, queue: dispatch_queue_t, handler: HandlerType) {
         var pattern = pattern
         var dynamicSegments = [String]()
-        while let range = pattern.rangeOfString(":[a-zA-Z0-9-_]+", options: [.RegularExpressionSearch, .CaseInsensitiveSearch]) {
-            dynamicSegments.append(pattern.substringWithRange(range).stringByReplacingOccurrencesOfString(":", withString: ""))
+        let options: NSStringCompareOptions = [.RegularExpressionSearch, .CaseInsensitiveSearch]
+        while let range = pattern.rangeOfString(":[a-zA-Z0-9-_]+", options: options) {
+            let segment = pattern
+                .substringWithRange(range.startIndex.advancedBy(1)..<range.endIndex)
+            dynamicSegments.append(segment)
             pattern.replaceRange(range, with: "([^/]+)")
         }
         
-        return self.init(pattern: pattern, dynamicSegments: dynamicSegments, queue: queue, handler: handler)
+        self.pattern = pattern
+        self.dynamicSegments = dynamicSegments
+        self.queue = queue
+        self.handler = handler
     }
     
-    func matches(route: String, inout parameters: Parameters) -> Bool {
-        guard let matches = (try? NSRegularExpression(pattern: pattern, options: .CaseInsensitive))
-            .flatMap({ $0.matchesInString(route, options: [], range: NSMakeRange(0, route.characters.count)) })?
-            .first else {
-                return false
-        }
-        
+    private func matches(route: String) -> NSTextCheckingResult? {
+        return (try? NSRegularExpression(pattern: pattern, options: .CaseInsensitive))
+            .flatMap {
+                $0.matchesInString(route, options: [], range: NSMakeRange(0, route.characters.count))
+            }?.first
+    }
+    
+    private func parameters(route: String, matches: NSTextCheckingResult) -> Parameters {
+        var parameters = Parameters()
         if dynamicSegments.count > 0 && dynamicSegments.count == matches.numberOfRanges - 1 {
             [Int](1 ..< matches.numberOfRanges).forEach { (index) in
                 parameters[dynamicSegments[index-1]] = (route as NSString).substringWithRange(matches.rangeAtIndex(index))
             }
         }
-        
-        return true
+        return parameters
     }
-}
-
-public struct Route: Routable {
-    public typealias MapHandler = (String, Parameters, Completed) -> Void
-    public typealias Completed = () -> Void
     
-    var pattern: String
-    var dynamicSegments: [String]
-    var queue: dispatch_queue_t
-    var handler: MapHandler
-    
-    init(pattern: String, dynamicSegments: [String], queue: dispatch_queue_t, handler: MapHandler) {
-        self.pattern = pattern
-        self.dynamicSegments = dynamicSegments
-        self.queue = queue
-        self.handler = handler
-    }
-}
-
-public struct Proxy: Routable {
-    public typealias ProxyHandler = (String, Parameters, Next) -> Void
-    public typealias Next = (String?, Parameters?) -> Void
-    
-    var pattern: String
-    var dynamicSegments: [String]
-    var queue: dispatch_queue_t
-    var handler: ProxyHandler
-    
-    init(pattern: String, dynamicSegments: [String], queue: dispatch_queue_t, handler: ProxyHandler) {
-        self.pattern = pattern
-        self.dynamicSegments = dynamicSegments
-        self.queue = queue
-        self.handler = handler
-    }
 }
 
 public final class Routing {
+    
     private var routes: [Route] = [Route]()
-    private var proxies: [Proxy] = [Proxy]()
     private var accessQueue = dispatch_queue_create("Routing Access Queue", DISPATCH_QUEUE_SERIAL)
     private var routingQueue = dispatch_queue_create("Routing Queue", DISPATCH_QUEUE_SERIAL)
     

    
    public func map(pattern: String,
                    queue: dispatch_queue_t = dispatch_get_main_queue(),
                    handler: Route.MapHandler) -> Void {
        dispatch_async(accessQueue) {
            self.routes.insert(Route.register(pattern, queue: queue, handler: handler), atIndex: 0)
        }
    }
    
    public func proxy(pattern: String,
                      queue: dispatch_queue_t = dispatch_get_main_queue(),
                      handler: Proxy.ProxyHandler) -> Void {
        dispatch_async(accessQueue) {
            self.proxies.insert(Proxy.register(pattern, queue: queue, handler: handler), atIndex: 0)
        }
    }
    

                            break
                        }
                    }
                }
                
                for route in _routes where !route.isProxy && route.matches(matchedString) != nil {
                    dispatch_async(route.queue) {
                        if case let .Route(handler) = route.handler {
                            handler(matchedString, parameters) {
                                dispatch_semaphore_signal(semaphore)
                            }
                        }
                    }
                    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
                }
            }
        }
        return true
    }
    
}
