<commit_before>//
//  APIService.swift
//  Services
//
//  Created by <NAME> on 10/07/2017.
//  Copyright © 2017 devandsev. All rights reserved.
//

import Foundation
import ObjectMapper

class APIService {
    
    static let shared: APIService = APIService()
    
    private let httpService = HTTPService.shared
    private let logger = LoggerService.shared
    
    let baseUrl: String = "https://api.thetvdb.com"
    
    var authToken: String? {
        didSet {
            guard let authToken = authToken,
            !authToken.isEmpty else {
                httpService.headers.removeValue(forKey: "Authorization")
                return
            }
            httpService.headers["Authorization"] = "Bearer \(authToken)"
        }
    }
    
    // MARK: - Public
    
    func send<T>(request: APIRequest, schema: T.Type, completion: @escaping (T?, APIError?) -> Void) where T: ImmutableMappable {
        
        let fullUrl = baseUrl + request.url
        httpService.request(url: fullUrl, method: request.method, parameters: request.parameters) { result in
            
            if let serializedError = self.error(from: result) {
                
                let failure: (APIError) -> Void = { error in
                    self.logger.log(error: error)
                    completion(nil, error)
                }
                
                guard request.retriesLeft > 0 else {
                    failure(serializedError)
                    return
                }
                
                SessionService.shared.updateIfNeeded(error: serializedError, success: {
                    self.send(request: request, schema: schema, completion: completion)
                }, failure: { error in
                    failure(serializedError)
                })
                
                return
            }
            
            switch result {
                
            case .failure(let error):
                self.logger.log(error: error)
                completion(nil, .httpError(error: error))
                
            case .success(let json, let code):
                let (possibleJson, formatError) = self.checkThatItsDictionary(json: json)
                
                guard let dicJson = possibleJson else {
                    self.logger.log(error: formatError)
                    completion(nil, formatError)
                    return
                }
                
                do {
                    let object = try Mapper<T>().map(JSON: dicJson)
                    completion(object, nil)
                } catch let error as MapError {
                    let apiError: APIError = .internalError(message: "API: ObjectMapper error: \(error.description)")
                    self.logger.log(error: apiError)
                    completion(nil, apiError)
                } catch {
                    let apiError: APIError = .internalError(message: "API: Couldn't map JSON to an object")
                    self.logger.log(error: apiError)
                    completion(nil, apiError)
                }
            }
        }
    }
    
    func send<T>(request: APIRequest, arrayOf: T.Type, completion: @escaping ([T], APIError?) -> Void) where T: ImmutableMappable {
        
        let fullUrl = baseUrl + request.url
        httpService.request(url: fullUrl, method: request.method, parameters: request.parameters) { result in
            
            if let serializedError = self.error(from: result) {

                let failure: (APIError) -> Void = { error in
                    self.logger.log(error: error)
                    completion([], error)
                }
                
                guard request.retriesLeft > 0 else {
                    failure(serializedError)
                    return
                }
                
                SessionService.shared.updateIfNeeded(error: serializedError, success: {
                    self.send(request: request, arrayOf: arrayOf, completion: completion)
                }, failure: { error in
                    failure(serializedError)
                })
                
                return
            }
            
            switch result {
                
            case .failure(let error):
                self.logger.log(error: error)
                completion([], .httpError(error: error))
                
            case .success(let json, let code):
                let (possibleJson, formatError) = self.checkThatItsArray(json: json)
                
                guard let arrJson = possibleJson else {
                    self.logger.log(error: formatError)
                    completion([], formatError)<commit_msg>Fix Request retries counter not being decremented<commit_after>//
//  APIService.swift
//  Services
//
//  Created by <NAME> on 10/07/2017.
//  Copyright © 2017 devandsev. All rights reserved.
//

import Foundation
import ObjectMapper

class APIService {
    
    static let shared: APIService = APIService()
    
    private let httpService = HTTPService.shared
    private let logger = LoggerService.shared
    
    let baseUrl: String = "https://api.thetvdb.com"
    
    var authToken: String? {
        didSet {
            guard let authToken = authToken,
            !authToken.isEmpty else {
                httpService.headers.removeValue(forKey: "Authorization")
                return
            }
            httpService.headers["Authorization"] = "Bearer \(authToken)"
        }
    }
    
    // MARK: - Public
    
    func send<T>(request: APIRequest, schema: T.Type, completion: @escaping (T?, APIError?) -> Void) where T: ImmutableMappable {
        
        let fullUrl = baseUrl + request.url
        httpService.request(url: fullUrl, method: request.method, parameters: request.parameters) { result in
            
            if let serializedError = self.error(from: result) {
                
                let failure: (APIError) -> Void = { error in
                    self.logger.log(error: error)
                    completion(nil, error)
                }
                
                guard request.retriesLeft > 0 else {
                    failure(serializedError)
                    return
                }
                
                var request = request
                request.retriesLeft -= 1
                
                SessionService.shared.updateIfNeeded(error: serializedError, success: {
                    self.send(request: request, schema: schema, completion: completion)
                }, failure: { error in
                    failure(serializedError)
                })
                
                return
            }
            
            switch result {
                
            case .failure(let error):
                self.logger.log(error: error)
                completion(nil, .httpError(error: error))
                
            case .success(let json, let code):
                let (possibleJson, formatError) = self.checkThatItsDictionary(json: json)
                
                guard let dicJson = possibleJson else {
                    self.logger.log(error: formatError)
                    completion(nil, formatError)
                    return
                }
                
                do {
                    let object = try Mapper<T>().map(JSON: dicJson)
                    completion(object, nil)
                } catch let error as MapError {
                    let apiError: APIError = .internalError(message: "API: ObjectMapper error: \(error.description)")
                    self.logger.log(error: apiError)
                    completion(nil, apiError)
                } catch {
                    let apiError: APIError = .internalError(message: "API: Couldn't map JSON to an object")
                    self.logger.log(error: apiError)
                    completion(nil, apiError)
                }
            }
        }
    }
    
    func send<T>(request: APIRequest, arrayOf: T.Type, completion: @escaping ([T], APIError?) -> Void) where T: ImmutableMappable {
        
        let fullUrl = baseUrl + request.url
        httpService.request(url: fullUrl, method: request.method, parameters: request.parameters) { result in
            
            if let serializedError = self.error(from: result) {

                let failure: (APIError) -> Void = { error in
                    self.logger.log(error: error)
                    completion([], error)
                }
                
                guard request.retriesLeft > 0 else {
                    failure(serializedError)
                    return
                }
                
                var request = request
                request.retriesLeft -= 1
                
                SessionService.shared.updateIfNeeded(error: serializedError, success: {
                    self.send(request: request, arrayOf: arrayOf, completion: completion)
                }, failure: { error in
                    failure(serializedError)
                })
                
                return
            }
            
            switch result {
                
            case .failure(let error):
                self.logger.log(error: error)
                completion([], .httpError(error: error))
                
            case .success(let json, let code):
                let (possibleJson, formatError) = self.checkThatItsArray(json: json)
                
                guard let arrJson = possibleJson else {
                    self.logger.log(error: formatError)
                    completion([], formatError)
{'fraction_non_alphanumeric': 0.08333333333333333, 'fraction_numerical': 0.003101736972704715, 'mean_word_length': 1.275464596565514, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 23, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, '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': '3739058', 'n_tokens_mistral': 2386, 'n_tokens_neox': 2217, 'n_words': 567}