<commit_before>/**
 * Copyright IBM Corporation 2016
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/


import KituraSys
import LoggerAPI

import Foundation

// MARK: RouterElement

class RouterElement {

    ///
    /// The regular expression matcher
    ///
    static var keyRegex: NSRegularExpression? = nil

    ///
    /// The regular expression matcher
    ///
    static var nonKeyRegex: NSRegularExpression? = nil

    ///
    /// Status of regex initialization
    ///
    private static var regexInit: Int = 0

    ///
    /// The routing method (get, post, put, delete)
    ///
    let method: RouterMethod

    ///
    /// The regular expression pattern
    ///
    private let pattern: String?

    ///
    /// The regular expression
    ///
    private var regex: NSRegularExpression?

    ///
    /// The list of keys
    ///
    private var keys:[String]?

    ///
    /// The middleware to use
    ///
    private var middleware: RouterMiddleware

    ///
    /// initializes a RouterElement
    ///
    /// - Parameter method: the RouterMethod
    /// - Parameter pattern: the String pattern to use
    /// - Parameter middleware: the RouterMiddleware used to handle
    ///
    /// - Returns: a RouterElement instance
    ///
    init(method: RouterMethod, pattern: String?, middleware: RouterMiddleware) {

        self.method = method
        self.pattern = pattern
        self.regex = nil
        self.keys = nil
        self.middleware = middleware

        SysUtils.doOnce(&RouterElement.regexInit) {
            do {
                RouterElement.keyRegex = try NSRegularExpression(pattern: "(.*)?(?:\\:(\\w+)(?:\\(((?:\\\\.|[^()])+)\\))?(?:([+*?])?))", options: [])
                RouterElement.nonKeyRegex = try NSRegularExpression(pattern: "(.*)?(?:(?:\\(((?:\\\\.|[^()])+)\\))(?:([+*?])?))", options: [])
            }
            catch {
                Log.error("Failed to create regular expressions used to parse Route patterns")
            }
        }

        // Needs to be after the initialization of the static Regex's
        (regex, keys) = buildRegexFromPattern(pattern)

    }

    ///
    /// Convenience initializer
    ///
    convenience init(method: RouterMethod, pattern: String? , handler: RouterHandler) {

        self.init(method: method, pattern: pattern, middleware: RouterMiddlewareGenerator(handler: handler))
    }

    ///
    /// Process
    ///
    /// - Parameter httpMethod: the method
    /// - Parameter urlPath: the path
    /// - Parameter request: the request
    /// - Parameter response: the response
    ///
    func process(urlPath: String, request: RouterRequest, response: RouterResponse, next: () -> Void) {

        if response.error == nil || method == .Error {
            if response.error != nil || method == .All || method == request.method {
                // Either response error exists and method is error, or method matches
                if  let regex = regex  {
                    if  let match = regex.firstMatchInString(urlPath, options: [], range: NSMakeRange(0, urlPath.characters.count))  {
                        request.route = pattern
                        updateRequestParams(urlPath, match: match, request: request)
                        processHelper(request, response: response, next: next)
                    } else {
                        next()
                    }
                }
                else {
                    request.route = pattern
                    request.params = [:]
                    processHelper(request, response: response, next: next)
                } 
            } else {
                next()
            }
        } else {
            next()
        }
    }
    
    ///
    /// Process the helper
    ///
    /// - Parameter request: the request
    /// - Parameter response: the router response 
    /// - Parameter next: the closure for the next execution block
    ///
    private func processHelper(request: RouterRequest, response: RouterResponse, next: () -> Void) {
        middleware.handle(request, response: response) { () in
            request.params = [:]
            next()
        }
    }

    ///
    /// Builds a regular expression from a String pattern
    ///
    /// - Parameter pattern: Optional string
    ///
    /// - Returns:
    ///<commit_msg>IBM-Swift/Kitura#188 added variadic route handlers support<commit_after>/**
 * Copyright IBM Corporation 2016
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/


import KituraSys
import LoggerAPI

import Foundation

// MARK: RouterElement

class RouterElement {

    ///
    /// The regular expression matcher
    ///
    static var keyRegex: NSRegularExpression? = nil

    ///
    /// The regular expression matcher
    ///
    static var nonKeyRegex: NSRegularExpression? = nil

    ///
    /// Status of regex initialization
    ///
    private static var regexInit: Int = 0

    ///
    /// The routing method (get, post, put, delete)
    ///
    let method: RouterMethod

    ///
    /// The regular expression pattern
    ///
    private let pattern: String?

    ///
    /// The regular expression
    ///
    private var regex: NSRegularExpression?

    ///
    /// The list of keys
    ///
    private var keys:[String]?

    ///
    /// The middleware to use
    ///
    private let middlewares: [RouterMiddleware]

    ///
    /// initializes a RouterElement
    ///
    /// - Parameter method: the RouterMethod
    /// - Parameter pattern: the String pattern to use
    /// - Parameter middleware: the RouterMiddleware used to handle
    ///
    /// - Returns: a RouterElement instance
    ///
    private init(method: RouterMethod, pattern: String?, middleware: [RouterMiddleware]) {

        self.method = method
        self.pattern = pattern
        self.regex = nil
        self.keys = nil
        self.middlewares = middleware

        SysUtils.doOnce(&RouterElement.regexInit) {
            do {
                RouterElement.keyRegex = try NSRegularExpression(pattern: "(.*)?(?:\\:(\\w+)(?:\\(((?:\\\\.|[^()])+)\\))?(?:([+*?])?))", options: [])
                RouterElement.nonKeyRegex = try NSRegularExpression(pattern: "(.*)?(?:(?:\\(((?:\\\\.|[^()])+)\\))(?:([+*?])?))", options: [])
            }
            catch {
                Log.error("Failed to create regular expressions used to parse Route patterns")
            }
        }

        // Needs to be after the initialization of the static Regex's
        (regex, keys) = buildRegexFromPattern(pattern)

    }

    ///
    /// Convenience initializer
    ///
    convenience init(method: RouterMethod, pattern: String? , handler: RouterHandler...) {

        self.init(method: method, pattern: pattern, middleware: handler.map{RouterMiddlewareGenerator(handler: $0)})
    }

    ///
    /// Convenience initializer
    ///
    convenience init(method: RouterMethod, pattern: String? , middleware: RouterMiddleware...) {

        self.init(method: method, pattern: pattern, middleware: middleware)
    }

    ///
    /// Process
    ///
    /// - Parameter httpMethod: the method
    /// - Parameter urlPath: the path
    /// - Parameter request: the request
    /// - Parameter response: the response
    ///
    func process(urlPath: String, request: RouterRequest, response: RouterResponse, next: () -> Void) {

        if response.error == nil || method == .Error {
            if response.error != nil || method == .All || method == request.method {
                // Either response error exists and method is error, or method matches
                if  let regex = regex  {
                    if  let match = regex.firstMatchInString(urlPath, options: [], range: NSMakeRange(0, urlPath.characters.count))  {
                        request.route = pattern
                        updateRequestParams(urlPath, match: match, request: request)
                        processHelper(request, response: response, next: next)
                    } else {
                        next()
                    }
                }
                else {
                    request.route = pattern
                    request.params = [:]
                    processHelper(request, response: response, next: next)
                } 
            } else {
                next()
            }
        } else {
            next()
        }
    }
    
    ///
    /// Process the helper
    ///
    /// - Parameter request: the request
    /// - Parameter response: the router response 
    /// - Parameter next: the closure for the next execution block
    ///
    private func processHelper(request: RouterRequest, response: RouterResponse, next: () -> Void) {
        for middleware in middlewares {
            middleware.handle(request, response: response) { () in
                request.params = [:]
                next()
            }
        }
    }

    ///
    /// Builds a regular expression from a String pattern
    ///
    /// - Parameter pattern: Optional string
    ///
    /// - Returns:
    ///
{'fraction_non_alphanumeric': 0.12431517083374838, 'fraction_numerical': 0.002390676362187469, 'mean_word_length': 1.7819340537545025, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5917061', 'n_tokens_mistral': 2635, 'n_tokens_neox': 2500, 'n_words': 803}