<commit_before>//
//  NetworkUserReportableError.swift
//  Swiftlier
//
//  Created by <NAME> on 4/24/16.
//  Copyright © 2016 Drewag LLC. All rights reserved.
//

import Foundation

public class NetworkResponseErrorReason: AnyErrorReason {
    public enum Kind {
        case unauthorized
        case forbidden
        case noInternet
        case notFound
        case gone
        case untrusted
        case invalid
        case unknown
        case badGateway
    }

    public let kind: Kind
    public let customMessage: String?

    public init(kind: Kind, customMessage: String? = nil) {
        self.customMessage = customMessage
        self.kind = kind
    }

    public var because: String {
        if let customMessage = customMessage {
            return customMessage
        }

        switch self.kind {
        case .gone:
            return "this app is out of date. Please update to the latest version."
        case .invalid:
            return "the request was invalid"
        case .noInternet:
            return "you are not connected to the internet"
        case .notFound:
            return "the requested endpoint could not be found"
        case .unauthorized, .forbidden:
            return "you are not authorized"
        case .unknown:
            return "there was an unknown error"
        case .untrusted:
            return "the web server can no longer be trusted. Please update to the latest version of this app."
        case .badGateway:
            return "the web server appears to be down"
        }
    }
}

open class NetworkError: ReportableError {
    public let status: HTTPStatus

    enum NetworkCodingKeys: String, CodingKey {
        case status
    }

    public init(from source: ErrorGenerating.Type, by: ErrorPerpitrator, doing: String, because: AnyErrorReason, status: HTTPStatus) {
        self.status = status
        super.init(from: source, by: by, doing: doing, because: because)
    }

    public init(from error: ReportableError, status: HTTPStatus) {
        self.status = status
        super.init(from: error.source, by: error.perpetrator, doing: error.doing, because: error.reason)
    }

    open override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: NetworkCodingKeys.self)
        try container.encode(self.status.rawValue, forKey: .status)
    }
}

extension ErrorGenerating {
    public static func error(_ doing: String, from response: URLResponse?, and data: Data?) -> NetworkError? {
        guard let response = response as? HTTPURLResponse else {
            return nil
        }
        return self.error(doing, from: data, status: HTTPStatus(rawValue: response.statusCode))
    }

    public static func error(_ doing: String, from data: Data?, status: HTTPStatus) -> NetworkError? {
        let parsed = self.parseErrorBody(from: data)
        let customMessage = parsed?.because
        let perpitrator = parsed?.perpitrator ?? .system
        switch status.rawValue {
        case 404:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .notFound, customMessage: nil), by: perpitrator), status: status)
        case 401:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .unauthorized, customMessage: nil), by: perpitrator), status: status)
        case 403:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .forbidden, customMessage: nil), by: perpitrator), status: status)
        case 410:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .gone, customMessage: nil), by: perpitrator), status: status)
        case 502:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .badGateway, customMessage: nil), by: perpitrator), status: status)
        case let x where x >= 400 && x < 500:
            return self.error(doing, fromNetworkData: data, status: status)
                ?? NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .invalid, customMessage: customMessage), by: perpitrator), status: status)
        case let x where x >= 500 && x < 600:<commit_msg>[BF] Show custom error messages on standard response codes<commit_after>//
//  NetworkUserReportableError.swift
//  Swiftlier
//
//  Created by <NAME> on 4/24/16.
//  Copyright © 2016 Drewag LLC. All rights reserved.
//

import Foundation

public class NetworkResponseErrorReason: AnyErrorReason {
    public enum Kind {
        case unauthorized
        case forbidden
        case noInternet
        case notFound
        case gone
        case untrusted
        case invalid
        case unknown
        case badGateway
    }

    public let kind: Kind
    public let customMessage: String?

    public init(kind: Kind, customMessage: String? = nil) {
        self.customMessage = customMessage
        self.kind = kind
    }

    public var because: String {
        if let customMessage = customMessage, !customMessage.isEmpty {
            return customMessage
        }

        switch self.kind {
        case .gone:
            return "this app is out of date. Please update to the latest version."
        case .invalid:
            return "the request was invalid"
        case .noInternet:
            return "you are not connected to the internet"
        case .notFound:
            return "the requested endpoint could not be found"
        case .unauthorized, .forbidden:
            return "you are not authorized"
        case .unknown:
            return "there was an unknown error"
        case .untrusted:
            return "the web server can no longer be trusted. Please update to the latest version of this app."
        case .badGateway:
            return "the web server appears to be down"
        }
    }
}

open class NetworkError: ReportableError {
    public let status: HTTPStatus

    enum NetworkCodingKeys: String, CodingKey {
        case status
    }

    public init(from source: ErrorGenerating.Type, by: ErrorPerpitrator, doing: String, because: AnyErrorReason, status: HTTPStatus) {
        self.status = status
        super.init(from: source, by: by, doing: doing, because: because)
    }

    public init(from error: ReportableError, status: HTTPStatus) {
        self.status = status
        super.init(from: error.source, by: error.perpetrator, doing: error.doing, because: error.reason)
    }

    open override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: NetworkCodingKeys.self)
        try container.encode(self.status.rawValue, forKey: .status)
    }
}

extension ErrorGenerating {
    public static func error(_ doing: String, from response: URLResponse?, and data: Data?) -> NetworkError? {
        guard let response = response as? HTTPURLResponse else {
            return nil
        }
        return self.error(doing, from: data, status: HTTPStatus(rawValue: response.statusCode))
    }

    public static func error(_ doing: String, from data: Data?, status: HTTPStatus) -> NetworkError? {
        let parsed = self.parseErrorBody(from: data)
        let customMessage = parsed?.because
        let perpitrator = parsed?.perpitrator ?? .system
        switch status.rawValue {
        case 404:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .notFound, customMessage: customMessage), by: perpitrator), status: status)
        case 401:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .unauthorized, customMessage: customMessage), by: perpitrator), status: status)
        case 403:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .forbidden, customMessage: customMessage), by: perpitrator), status: status)
        case 410:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .gone, customMessage: customMessage), by: perpitrator), status: status)
        case 502:
            return NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .badGateway, customMessage: customMessage), by: perpitrator), status: status)
        case let x where x >= 400 && x < 500:
            return self.error(doing, fromNetworkData: data, status: status)
                ?? NetworkError(from: self.error(doing, because: NetworkResponseErrorReason(kind: .invalid, customMessage: customMessage), by: perpitrator), status: status)
        case let x where x >= 500 && x < 600:
{'fraction_non_alphanumeric': 0.08437321121923297, 'fraction_numerical': 0.00824270177447052, 'mean_word_length': 2.6721311475409837, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, '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': '7473544', 'n_tokens_mistral': 2376, 'n_tokens_neox': 2232, 'n_words': 788}