 import Foundation
 
 /**
-A set of logically connected RESTful resources, grouped under a base URL.
-
-You will typically create a separate subclass of `Service` for each REST API you use.
+  A set of logically connected RESTful resources, grouped under a base URL.
+
+  You will typically create a separate subclass of `Service` for each REST API you use.
 */
 @objc(BOSService)
 public class Service: NSObject

                .replaceString("\\*",       "[^/:?]*")
                + "($|\\?)")
        
        debugLog(.Configuration, ["URL pattern", urlPattern, "compiles to regex", pattern.pattern])
        
        configure(
            { pattern.matches($0.absoluteString) },
            description: description ?? urlPattern,
            configurer: configurer)
        }
    
    /**
      Accepts an arbitrary URL matching predicate if the wildcards in the `urlPattern` flavor of `configure()`
      aren’t robust enough.
    */
    public final func configure(
            urlMatcher: NSURL -> Bool,
            description: String? = nil,
            configurer: Configuration.Builder -> Void)
        {
        let entry = ConfigurationEntry(
            description: "config \(nextConfigID) [" + (description ?? "custom") + "]",
            urlMatcher: urlMatcher,
            configurer: configurer)
        configurationEntries.append(entry)
        debugLog(.Configuration, ["Added", entry])
        }
    
    /**
      A convenience to add a one-off content transformer. Useful for transformers that create model objects. Example:
      
          $0.config.addContentTransformer { MyModel(json: $0) }
    */
    public final func configureTransformer<I,O>(
            urlPattern: String,
            description: String? = nil,
            contentTransform: ResponseContentTransformer<I,O>.Processor)
        {
        configure(urlPattern, description: description ?? "\(urlPattern) : \(I.self) → \(O.self)")
            {
            $0.config.responseTransformers.add(
                ResponseContentTransformer(processor: contentTransform))
            }
        }
    
    private var configID = 0
    private var nextConfigID: Int { return configID++ }
    
    /**
      Signals that all resources need to recompute their configuration next time they need it.
      
      Because the `configure(...)` methods accept an arbitrary closure, it is possible that the results of
      that closure could change over time. However, resources cache their configuration after it is computed. Therefore,
      if you do anything that would change the result of a configuration closure, you must call
      `invalidateConfiguration()` in order for the changes to take effect.
      
      _《insert your functional programming purist rant here if you so desire》_

      Note that you do _not_ need to call this method after calling any of the `configure(...)` methods.
      You only need to call it if one of the previously passed closures will now behave differently.
    
      For example, to make a header track the value of a modifiable property:

          var flavor: String {
            didSet { invalidateConfiguration() }
          }

          init() {
            super.init(base: "https://api.github.com")
            configure​ {
              $0.config.headers["Flavor-of-the-month"] = self.flavor  // NB: use weak self if service isn’t a singleton
            }
          }
    
      Note that this method does _not_ immediately recompute all existing configurations. This is an inexpensive call.
      Configurations are computed lazily, and the (still relatively low) performance impact of recomputation is spread
      over subsequent resource interactions.
    */
    public final func invalidateConfiguration()
        {
        if anyConfigSinceLastInvalidation
            { debugLog(.Configuration, ["Configurations need to be recomputed"]) }
        anyConfigSinceLastInvalidation = false
        
        configVersion++
        }

    private var anyConfigSinceLastInvalidation = false
    
    internal func configurationForResource(resource: Resource) -> Configuration
        {
        anyConfigSinceLastInvalidation = true
        debugLog(.Configuration, ["Computing configuration for", resource])
        let builder = Configuration.Builder()
        for entry in configurationEntries
            where entry.urlMatcher(resource.url)
            {
            debugLog(.Configuration, ["Applying", entry, "to", resource])
            entry.configurer(builder)
            }
        return builder.config
        }
    
    private struct ConfigurationEntry: CustomStringConvertible
        {
        let description: String
        let urlMatcher: NSURL -> Bool
        let configurer: Configuration.Builder -> Void
        }
    
    // MARK: Wiping state
    
    /**
      Wipes the state of this service’s resources. Typically used to handle logout.
      
      Applies to resources matching the predicate, or all resources by default.
    */
    public final func wipeResources(predicate: Resource -> Bool =  { _ in true })
        {
        resourceCache.flushUnused()
        for resource in resourceCache.values
            {
            if predicate(resource)
                { resource.wipe() }
            }
        }

    /**
      Wipes the state of a subset of this service’s resources, matching based on URLs (instead of `Resource` instances).
      
      Useful for making shared predicates that you can pass to both `configure(_:)` and this method.
    */
    public final func wipeResourcesMatchingURL(predicate: NSURL -> Bool)
        {
        wipeResources { (res: Resource) in predicate(res.url) }
        }
    }


        }
    
    /**
      Applies configuration to resources matching the given pattern. You can pass a `String` or `Resource` for the
      `pattern` argument, or provide your own implementation of `ConfigurationPatternConvertible`.
    
      Examples:
      
          configure("/items")    { $0.config.expirationTime = 5 }
          configure("/items/​*")  { $0.config.headers["Funkiness"] = "Very" }
          configure("/admin/​**") { $0.config.headers["Auth-token"] = token }
          
          let user = resource("/user/current")
          configure(user) { $0.config.persistentCache = userProfileCache }
    
      If you need more fine-grained URL matching, use the predicate flavor of this method.
      
      - SeeAlso: `configure(description:configurer:)` for global config
      - SeeAlso: `invalidateConfiguration()`
    */
    public final func configure(
            pattern: ConfigurationPatternConvertible,
            description: String? = nil,
            configurer: Configuration.Builder -> Void)
        {
        configure(
            pattern.configurationPattern(self),
            description: description ?? pattern.configurationPatternDescription,
            configurer: configurer)
        }
    
    /**
      Accepts an arbitrary URL matching predicate if the wildcards in the `urlPattern` flavor of `configure()`
      aren’t robust enough.
    */
    public final func configure(
            configurationPattern: NSURL -> Bool,
            description: String? = nil,
            configurer: Configuration.Builder -> Void)
        {
        let entry = ConfigurationEntry(
            description: "config \(nextConfigID) [" + (description ?? "custom") + "]",
            configurationPattern: configurationPattern,
            configurer: configurer)
        configurationEntries.append(entry)
        debugLog(.Configuration, ["Added", entry])
        }
    
    /**
      A convenience to add a one-off content transformer. Useful for transformers that create model objects. Example:
      
          $0.config.addContentTransformer { MyModel(json: $0) }
    */
    public final func configureTransformer<I,O>(
            pattern: ConfigurationPatternConvertible,
            description: String? = nil,
            contentTransform: ResponseContentTransformer<I,O>.Processor)
        {
        configure(pattern, description: description ?? "\(pattern.configurationPatternDescription) : \(I.self) → \(O.self)")
            {
            $0.config.responseTransformers.add(
                ResponseContentTransformer(processor: contentTransform))
            }
        }
    
    private var configID = 0
    private var nextConfigID: Int { return configID++ }
    
    /**
      Signals that all resources need to recompute their configuration next time they need it.
      
      Because the `configure(...)` methods accept an arbitrary closure, it is possible that the results of
      that closure could change over time. However, resources cache their configuration after it is computed. Therefore,
      if you do anything that would change the result of a configuration closure, you must call
      `invalidateConfiguration()` in order for the changes to take effect.
      
      _《insert your functional programming purist rant here if you so desire》_

      Note that you do _not_ need to call this method after calling any of the `configure(...)` methods.
      You only need to call it if one of the previously passed closures will now behave differently.
    
      For example, to make a header track the value of a modifiable property:

          var flavor: String {
            didSet { invalidateConfiguration() }
          }

          init() {
            super.init(base: "https://api.github.com")
            configure​ {
              $0.config.headers["Flavor-of-the-month"] = self.flavor  // NB: use weak self if service isn’t a singleton
            }
          }
    
      Note that this method does _not_ immediately recompute all existing configurations. This is an inexpensive call.
      Configurations are computed lazily, and the (still relatively low) performance impact of recomputation is spread
      over subsequent resource interactions.
    */
    public final func invalidateConfiguration()
        {
        if anyConfigSinceLastInvalidation
            { debugLog(.Configuration, ["Configurations need to be recomputed"]) }
        anyConfigSinceLastInvalidation = false
        
        configVersion++
        }

    private var anyConfigSinceLastInvalidation = false
    
    internal func configurationForResource(resource: Resource) -> Configuration
        {
        anyConfigSinceLastInvalidation = true
        debugLog(.Configuration, ["Computing configuration for", resource])
        let builder = Configuration.Builder()
        for entry in configurationEntries
            where entry.configurationPattern(resource.url)
            {
            debugLog(.Configuration, ["Applying", entry, "to", resource])
            entry.configurer(builder)
            }
        return builder.config
        }
    
    private struct ConfigurationEntry: CustomStringConvertible
        {
        let description: String
        let configurationPattern: NSURL -> Bool
        let configurer: Configuration.Builder -> Void
        }
    
    // MARK: Wiping state
    
    /**
      Wipes the state of this service’s resources. Typically used to handle logout.
      
      Applies to resources matching the predicate, or all resources by default.
    */
    public final func wipeResources(predicate: Resource -> Bool =  { _ in true })
        {
        resourceCache.flushUnused()
        for resource in resourceCache.values
            {
            if predicate(resource)
                { resource.wipe() }
            }
        }

    /**
      Wipes the state of a subset of this service’s resources, matching based on URLs (instead of `Resource` instances).
      
      Useful for making shared predicates that you can pass to both `configure(...)` and this method.
    */
    public final func wipeResourcesMatchingURL(predicate: NSURL -> Bool)
        {
        wipeResources { (res: Resource) in predicate(res.url) }
        }
    }


/**
  A type that can serve as a URL matcher for service configuration.
  
  Siesta provides implementations of this protocol for `String` (for glob-based matching) and `Resource` (to configure
  one specific resource).
  
  - SeeAlso: `Service.configure(_:description:configurer:)`
  - SeeAlso: `String.configurationPattern(_:)`
  - SeeAlso: `Resource.configurationPattern(_:)`
*/
public protocol ConfigurationPatternConvertible
    {
    /// Turns the receiver into a predicate that matches URLs.
    func configurationPattern(service: Service) -> NSURL -> Bool
    
    /// A logging-friendly description of the receiver when it acts as a URL pattern.
    var configurationPatternDescription: String { get }
    }

/**
  Support for passing URL patterns with wildcards to `Service.configure(...)`.
*/
extension String: ConfigurationPatternConvertible
    {
    /**
      Matches URLs using shell-like wildcards / globs.
    
      The `urlPattern` is interpreted relative to the service’s base URL unless it begins with a protocol (e.g. `http:`).
      If it is relative, the leading slash is optional.
