// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// the bare-minimum fields for per-protocol metadata on a given aspect
public protocol ProtocolInterface: Codable {}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

class Request: Metadata {
    /// the parameter inputs to the operation
    let parameters: [ParameterType]?

    /// a filtered list of parameters that is (assumably) the actual method signature parameters
    let signatureParameters: [ParameterType]?

    // MARK: Codable

    enum CodingKeys: String, CodingKey {
        case parameters, signatureParameters
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.parameters = try? container.decode([ParameterType]?.self, forKey: .parameters)
        self.signatureParameters = try? container.decode([ParameterType]?.self, forKey: .signatureParameters)
        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        if parameters != nil { try? container.encode(parameters, forKey: .parameters) }
        if signatureParameters != nil { try? container.encode(signatureParameters, forKey: .signatureParameters) }
        try super.encode(to: encoder)
    }

    /// Lookup a parameter by name.
    func parameter(for name: String) -> ParameterType? {
        return parameters?.first(named: name)
    }
}

extension Request {
    /// Retrieves a single body-encoded parameter, if there is one. Fails if there is more than one.
    var bodyParam: ParameterType? {
        // Look for body parameters from signature parameters first. If none is found, look up in parameters.
        var bodyParams = findBodyParams(parameters: signatureParameters)
        if bodyParams.count == 0 {
            bodyParams = findBodyParams(parameters: parameters)
        }

        // current logic only supports a single request per operation
        assert(bodyParams.count <= 1, "Unexpectedly found more than 1 body parameters in request... \(name)")
        return bodyParams.first
    }

    func findBodyParams(parameters: [ParameterType]?) -> [ParameterType] {
        var bodyParams = [ParameterType]()
        for param in parameters ?? [] {
            if case let ParameterType.virtual(virtParam) = param {
                let originalParam = ParameterType.regular(virtParam.originalParameter)
                if !bodyParams.contains(originalParam) {
                    bodyParams.append(originalParam)
                }
            }
            if let httpParam = param.protocol.http as? HttpParameter,
                httpParam.in == .body {
                bodyParams.append(param)
            }
        }
        return bodyParams
    }

    /// Return a unique list of all `ParameterType` objects.
    var allParams: [ParameterType] {
        let paramList = (signatureParameters ?? []) + (parameters ?? [])
        var params = [ParameterType]()
        for param in paramList {
            if !params.contains(param) {
                params.append(param)
            }
        }
        return params
    }

    /// Gets the Swift name for the body-encoded parameter, if there is one. Fails if there is more than one.
    func bodyParamName(for operation: Operation) -> String? {
        guard bodyParam != nil, !(bodyParam!.schema is ConstantSchema) else { return nil }

        let operationNameComps = operation.name.splitAndJoinAcronyms
        var bodyParamNameComps = Array(operationNameComps[1 ..< operationNameComps.count])
        for (index, comp) in bodyParamNameComps.enumerated() where index != 0 {
            bodyParamNameComps[index] = comp.capitalized
        }
        let finalName = bodyParamNameComps.joined()
        return finalName.isEmpty ? nil : finalName
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

class Response: Metadata {}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

class Schema: Codable, LanguageShortcut {
    /// Per-language information for Schema
    public var language: Languages

    /// The schema type
    let type: AllSchemaTypes

    /// A short description
    let summary: String?

    /// Example information
    let example: String?

    /// If the value isn't sent on the wire, the service will assume this
    let defaultValue: String?

    /// Per-serialization information for this Schema
    let serialization: SerializationFormats?

    /// API versions that this applies to. Undefined means all versions
    let apiVersions: [ApiVersion]?

    /// Deprecation information -- ie, when this aspect doesn't apply and why
    let deprecated: Deprecation?

    /// Where did this aspect come from (jsonpath or 'modelerfour:<something>')
    let origin: String?

    /// External Documentation Links
    let externalDocs: ExternalDocumentation?

    /// Per-protocol information for this aspect
    let `protocol`: Protocols

    let properties: [PropertyType]?

    /// Additional metadata extensions dictionary
    let extensions: [String: AnyCodable]?

    enum CodingKeys: String, CodingKey {
        case language
        case type
        case summary
        case example
        case defaultValue
        case serialization
        case apiVersions
        case deprecated
        case origin
        case externalDocs
        case `protocol`
        case properties
        case extensions
    }

    // swiftlint:disable cyclomatic_complexity
    func swiftType(parentName: String? = nil) -> String {
        var swiftType: String
        switch type {
        case .any:
            swiftType = "AnyObject"
        case .string,
             .uuid:
            swiftType = "String"
        case .boolean:
            swiftType = "Bool"
        case .array:
            guard let arraySchema = self as? ArraySchema else {
                fatalError("Type mismatch. Expected array type but got \(self)")
            }
            let elementSwiftType = arraySchema.elementType.swiftType(parentName: parentName)
            swiftType = (arraySchema.nullableItems ?? false) ? "[\(elementSwiftType)?]" : "[\(elementSwiftType)]"
        case .number:
            guard let numberSchema = self as? NumberSchema else {
                fatalError("Type mismatch. Expected number type but got \(self)")
            }
            swiftType = numberSchema.swiftType()
        case .dateTime:
            if let dateSchema = self as? DateTimeSchema {
                switch dateSchema.format {
                case .dateTime:
                    swiftType = "Iso8601Date"
                case .dateTimeRfc1123:
                    swiftType = "Rfc1123Date"
                }
            } else {
                fatalError("Type .dateTime but not schema `DateTimeSchema`")
            }
        case .date:
            swiftType = "SimpleDate"
        case .unixTime:
            swiftType = "UnixTime"
        case .byteArray:
            if let byteArrayScheme = self as? ByteArraySchema,
                byteArrayScheme.format == .base64url {
                swiftType = "String"
            } else {
                swiftType = "Data"
            }
        case .integer:
            swiftType = "Int"
        case .time:
            swiftType = "SimpleTime"
        case .choice,
             .object,
             .sealedChoice,
             .group:
            let rawName: String
            // use the containing object's visibility, if provided
            let visibility = Manager.shared.args!.generateAsInternal.visibility(for: parentName ?? name)
            if visibility == "public" {
                rawName = Manager.shared.args!.generateAsInternal.name(for: name) ?? name
            } else {
                rawName = Manager.shared.args!.generateAsInternal.alias(for: name) ?? name
            }
            swiftType = rawName.isReservedType ? rawName + "Type" : rawName
        case .dictionary:
            guard let dictionarySchema = self as? DictionarySchema else {
                fatalError("Type mismatch. Expected dictionary type but got \(self)")
            }
            swiftType = "[String:\(dictionarySchema.elementType.swiftType(parentName: parentName))?]"
        case .constant:
            guard let constant = self as? ConstantSchema else {
                fatalError("Type mismatch. Expected constant type but got \(self)")
            }
            swiftType = constant.valueType.swiftType()
        case .duration:
            swiftType = "Iso8601Duration"
        case .binary:
            swiftType = "Data"
        case .uri:
            swiftType = "URL"
        default:
            fatalError("Type \(type) not implemented")
        }
        // return optional ? "\(swiftType)?" : swiftType
        return swiftType
    }

    var modelName: String {
        let rawName = Manager.shared.args!.generateAsInternal.aliasOrName(for: name)
        return rawName.isReservedType ? rawName + "Type" : rawName
    }

    var bodyParamStrategy: BodyParamStrategy {
        if self is ConstantSchema {
            return .constant
        }

        switch type {
        case .unixTime:
            return .unixTime
        case .byteArray:
            if let byteSchema = self as? ByteArraySchema,
                byteSchema.format == .base64url {
                return .data
            }
            return .byteArray
        case .array:
            if let arraySchema = self as? ArraySchema,
                arraySchema.elementType.type == .date || arraySchema.elementType.type == .dateTime {
                return arraySchema.elementType.bodyParamStrategy
            } else {
                return .plain
            }
        case .time:
            return .time
        case .number:
            return (swiftType() == "Decimal") ? .decimal : .data
        default:
            return .plain
        }
    }

    static func decode<Key>(
        withContainer container: KeyedDecodingContainer<Key>,
        useKey keyName: String = "schema"
    ) throws -> Schema? where Key: CodingKey {
        var schema: Schema?
        guard let keyEnum = Key(stringValue: keyName) else {
            fatalError("Unable to find key enum.")
        }
        do {
            let schemaContainer = try container.nestedContainer(keyedBy: Schema.CodingKeys.self, forKey: keyEnum)
            let type = try schemaContainer.decode(AllSchemaTypes.self, forKey: Schema.CodingKeys.type)
            switch type {
            case .array:
                schema = try container.decode(ArraySchema.self, forKey: keyEnum)
            case .dictionary:
                schema = try container.decode(DictionarySchema.self, forKey: keyEnum)
            case .object:
                schema = try container.decode(ObjectSchema.self, forKey: keyEnum)
            case .number, .integer:
                schema = try container.decode(NumberSchema.self, forKey: keyEnum)
            case .choice:
                schema = try container.decode(ChoiceSchema.self, forKey: keyEnum)
            case .dateTime:
                schema = try container.decode(DateTimeSchema.self, forKey: keyEnum)
            case .string:
                schema = try container.decode(StringSchema.self, forKey: keyEnum)
            case .constant:
                schema = try container.decode(ConstantSchema.self, forKey: keyEnum)
            case .byteArray:
                schema = try container.decode(ByteArraySchema.self, forKey: keyEnum)
            case .sealedChoice:
                schema = try container.decode(SealedChoiceSchema.self, forKey: keyEnum)
            default:
                schema = try container.decode(Schema.self, forKey: keyEnum)
            }
            return schema
        } catch {
            guard "\(error)".contains("but found Unresolved instead") else {
                throw error
            }
            return try? container.decode(Schema.self, forKey: keyEnum)
        }
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a response that should be deserialized into a result of type(schema)
class SchemaResponse: Response {
    /// the content returned by the service for a given operation
    let schema: Schema

    /// indicates whether the response can be 'null'
    let nullable: Bool?

    enum CodingKeys: String, CodingKey {
        case schema, nullable
    }

    // MARK: Codable

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.schema = try Schema.decode(withContainer: container)!
        self.nullable = try? container.decode(Bool.self, forKey: .nullable)

        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(schema, forKey: .schema)
        if nullable != nil { try container.encode(nullable, forKey: .nullable) }

        try super.encode(to: encoder)
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

class SchemaUsage: Codable {
    /// contexts in which the schema is used
    let usage: [SchemaContext]

    /// Known media types in which this schema can be serialized
    let serializationFormats: [KnownMediaType]
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema that represents a choice of several values (ie, an 'enum')
class SealedChoiceSchema: ValueSchema, EnumerableSchema {
    /// the primitive type for the choices
    let choiceType: PrimitiveSchema

    /// the possible choices for in the set
    let choices: [ChoiceValue]

    enum CodingKeys: String, CodingKey {
        case choiceType, choices
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        choiceType = try container.decode(PrimitiveSchema.self, forKey: .choiceType)
        choices = try container.decode([ChoiceValue].self, forKey: .choices)
        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(choiceType, forKey: .choiceType)
        try container.encode(choices, forKey: .choices)
        try super.encode(to: encoder)
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema that represents a value dependent on another (not overridable)
class SealedConditionalSchema: ValueSchema {
    /// the primitive type for the conditional
    let conditionalType: PrimitiveSchema

    /// the possible conditional values
    let conditions: [ConditionalValue]

    /// the source value that drives the target value
    let sourceValue: [Value]

    enum CodingKeys: String, CodingKey {
        case conditionalType, conditions, sourceValue
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        conditionalType = try container.decode(PrimitiveSchema.self, forKey: .conditionalType)
        conditions = try container.decode([ConditionalValue].self, forKey: .conditions)
        sourceValue = try container.decode([Value].self, forKey: .sourceValue)
        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(conditionalType, forKey: .conditionalType)
        try container.encode(conditions, forKey: .conditions)
        try container.encode(sourceValue, forKey: .sourceValue)
        try super.encode(to: encoder)
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

class SerializationFormat: Codable {
    let extensions: [String: AnyCodable]?

    enum CodingKeys: String, CodingKey {
        case extensions
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        extensions = try? container.decode([String: AnyCodable].self, forKey: .extensions)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        if extensions != nil { try container.encode(extensions, forKey: .extensions) }
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema that represents a string value
class StringSchema: PrimitiveSchema {
    /// the maximum length of the string
    let maxLength: Int?

    /// the minimum length of the string
    let minLength: Int?

    /// a regular expression that the string must be validated against
    let pattern: String?

    // MARK: Codable

    enum CodingKeys: String, CodingKey {
        case maxLength, minLength, pattern
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        maxLength = try? container.decode(Int.self, forKey: .maxLength)
        minLength = try? container.decode(Int.self, forKey: .minLength)
        pattern = try? container.decode(String.self, forKey: .pattern)

        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        if maxLength != nil { try container.encode(maxLength, forKey: .maxLength) }
        if minLength != nil { try container.encode(minLength, forKey: .minLength) }
        if pattern != nil { try container.encode(pattern, forKey: .pattern) }

        try super.encode(to: encoder)
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema types that are non-object or complex types
typealias TimeSchema = PrimitiveSchema


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema that represents a UnixTime value
typealias UnixTimeSchema = PrimitiveSchema


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema that represents a Uri value
class UriSchema: PrimitiveSchema {
    /// the maximum length of the string
    let maxLength: Int?

    /// the minimum length of the string
    let minLength: Int?

    /// a regular expression that the string must be validated against
    let pattern: String?

    enum CodingKeys: String, CodingKey {
        case maxLength, minLength, pattern
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        maxLength = try? container.decode(Int?.self, forKey: .maxLength)
        minLength = try? container.decode(Int?.self, forKey: .minLength)
        pattern = try? container.decode(String?.self, forKey: .pattern)
        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        if maxLength != nil { try? container.encode(maxLength, forKey: .maxLength) }
        if minLength != nil { try? container.encode(minLength, forKey: .minLength) }
        if pattern != nil { try? container.encode(pattern, forKey: .pattern) }
        try super.encode(to: encoder)
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema that represents a Uuid value
typealias UuidSchema = PrimitiveSchema


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// Common base interface for properties, parameters and the like.
class Value: Codable, LanguageShortcut {
    /// the schema of this Value
    public var schema: Schema?

    // these properties we can set
    private var internalRequired: Bool?

    /// if the value is marked 'required'.
    public var required: Bool {
        return internalRequired ?? false
    }

    /// can null be passed in instead
    let nullable: Bool?

    /// the value that the remote will assume if this value is not present
    let assumedValue: String?

    /// the value that the client should provide if the consumer doesn't provide one
    let clientDefaultValue: String?

    /// a short description
    let summary: String?

    /// API versions that this applies to. Undefined means all versions
    let apiVersions: [ApiVersion]?

    /// deprecation information -- ie, when this aspect doesn't apply and why
    let deprecated: Deprecation?

    /// Where did this aspect come from (jsonpath or 'modelerfour:<something>')
    let origin: String?

    /// External Documentation Links
    let externalDocs: ExternalDocumentation?

    /// Per-language information for this aspect
    public var language: Languages

    /// Per-protocol information for this aspect
    let `protocol`: Protocols

    /// additional metadata extensions dictionary
    let extensions: [String: AnyCodable]?

    enum CodingKeys: String, CodingKey {
        case schema
        case required
        case nullable
        case assumedValue
        case clientDefaultValue
        case summary
        case apiVersions
        case deprecated
        case origin
        case externalDocs
        case language
        case `protocol`
        case extensions
    }

    // MARK: Codable

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        self.schema = try Schema.decode(withContainer: container)
        self.internalRequired = try? container.decode(Bool.self, forKey: .required)
        self.nullable = try? container.decode(Bool.self, forKey: .nullable)
        self.assumedValue = try? container.decode(String.self, forKey: .assumedValue)
        self.clientDefaultValue = try? container.decode(String.self, forKey: .clientDefaultValue)
        self.summary = try? container.decode(String.self, forKey: .summary)
        self.apiVersions = try? container.decode([ApiVersion].self, forKey: .apiVersions)
        self.deprecated = try? container.decode(Deprecation.self, forKey: .deprecated)
        self.origin = try? container.decode(String.self, forKey: .origin)
        self.externalDocs = try? container.decode(ExternalDocumentation.self, forKey: .externalDocs)
        self.language = try container.decode(Languages.self, forKey: .language)
        self.protocol = try container.decode(Protocols.self, forKey: .protocol)
        self.extensions = try? container.decode([String: AnyCodable].self, forKey: .extensions)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)

        if schema != nil { try container.encode(schema, forKey: .schema) }
        if internalRequired != nil { try container.encode(internalRequired, forKey: .required) }
        if nullable != nil { try container.encode(nullable, forKey: .nullable) }
        if assumedValue != nil { try container.encode(assumedValue, forKey: .assumedValue) }
        if clientDefaultValue != nil { try container.encode(clientDefaultValue, forKey: .clientDefaultValue) }
        if summary != nil { try container.encode(summary, forKey: .summary) }
        if apiVersions != nil { try container.encode(apiVersions, forKey: .apiVersions) }
        if deprecated != nil { try container.encode(deprecated, forKey: .deprecated) }
        if origin != nil { try container.encode(origin, forKey: .origin) }
        if externalDocs != nil { try container.encode(externalDocs, forKey: .externalDocs) }
        try container.encode(language, forKey: .language)
        try container.encode(`protocol`, forKey: .protocol)
        if extensions != nil { try container.encode(extensions, forKey: .extensions) }
    }

    var isSkipUrlEncoding: Bool {
        var skipUrlEncoding = false
        if let value = extensions?["x-ms-skip-url-encoding"]?.value as? Bool {
            skipUrlEncoding = value
        }
        return skipUrlEncoding
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// a schema types that are non-object or complex types
typealias ValueSchema = Schema


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// A definition of an discrete input for an operation
class VirtualParameter: Parameter {
    /// the original body parameter that this parameter is in effect replacing
    let originalParameter: Parameter

    /// if this parameter is for a nested property, this is the path of properties it takes to get there
    let pathToProperty: [PropertyType]

    /// the target property this virtual parameter represents
    let targetProperty: Property

    // MARK: Codable

    enum CodingKeys: String, CodingKey {
        case originalParameter, pathToProperty, targetProperty
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        originalParameter = try container.decode(Parameter.self, forKey: .originalParameter)
        pathToProperty = try container.decode([PropertyType].self, forKey: .pathToProperty)
        targetProperty = try container.decode(Property.self, forKey: .targetProperty)

        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(originalParameter, forKey: .originalParameter)
        try container.encode(pathToProperty, forKey: .pathToProperty)
        try container.encode(targetProperty, forKey: .targetProperty)

        try super.encode(to: encoder)
    }

    override internal func belongsInSignature(model _: CodeModel? = nil) -> Bool {
        // We track body params in a special way, so always omit them generally from the signature.
        // If they belong in the signature, they will be added in a way to ensure they come first.
        guard paramLocation != .body else { return false }

        // Default logic
        let inMethod = implementation == .method
        let notConstant = schema!.type != .constant
        let notGrouped = groupedBy == nil
        return inMethod && notConstant && notGrouped
    }

    override internal func belongsInOptions() -> Bool {
        let inMethod = implementation == .method
        let notConstant = schema!.type != .constant
        let notFlattened = flattened != true
        let notGrouped = groupedBy == nil
        return inMethod && notConstant && notFlattened && notGrouped
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

class XmlSerializationFormat: SerializationFormat {
    let name: String?

    let namespace: String?

    let prefix: String?

    let attribute: Bool

    let wrapped: Bool

    enum CodingKeys: String, CodingKey {
        case name, namespace, prefix, attribute, wrapped
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try? container.decode(String?.self, forKey: .name)
        namespace = try? container.decode(String?.self, forKey: .namespace)
        prefix = try? container.decode(String?.self, forKey: .prefix)
        attribute = try container.decode(Bool.self, forKey: .attribute)
        wrapped = try container.decode(Bool.self, forKey: .wrapped)
        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        if name != nil { try? container.encode(name, forKey: .name) }
        if namespace != nil { try? container.encode(namespace, forKey: .namespace) }
        if prefix != nil { try? container.encode(prefix, forKey: .prefix) }
        try container.encode(attribute, forKey: .attribute)
        try container.encode(wrapped, forKey: .wrapped)
        try super.encode(to: encoder)
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// an XOR relationship between several schemas
class XorSchema: Schema {
    /// the set of schemas that this must be one and only one of.
    let oneOf: [Schema]

    enum CodingKeys: String, CodingKey {
        case oneOf
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        oneOf = try container.decode([Schema].self, forKey: .oneOf)
        try super.init(from: decoder)
    }

    override public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(oneOf, forKey: .oneOf)
        try super.encode(to: encoder)
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// all schema types
enum AllSchemaTypes: String, Codable {
    case any
    case array
    case binary
    case boolean
    case byteArray = "byte-array"
    case char
    case choice
    case conditional
    case constant
    case credential
    case date
    case dateTime = "date-time"
    case dictionary
    case duration
    case flag
    case group
    case integer
    case not
    case number
    case object
    case odataQuery = "odata-query"
    case or
    case sealedChoice = "sealed-choice"
    case sealedConditional = "sealed-conditional"
    case string
    case time
    case unixTime = "unixtime"
    case uri
    case uuid
    case xor
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum CompoundSchemaTypes: String, Codable {
    case or
    case xor
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum HttpMethod: String, Codable {
    case delete
    case get
    case head
    case options
    case patch
    case post
    case put
    case trace
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum ImplementationLocation: String, Codable {
    case client = "Client"
    case context = "Context"
    case method = "Method"
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum KnownMediaType: String, Codable {
    case binary
    case form
    case json
    case multipart
    case text
    case unknown
    case xml
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum ObjectSchemaTypes: String, Codable {
    case dictionary
    case object
    case or
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// the location that this parameter is placed in the http request
enum ParameterLocation: String, Codable {
    case body
    case cookie
    case header
    case none
    case path
    case query
    case uri
    case virtual
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum PathEncodingStyle: String, Codable {
    case label
    case matrix
    case simple
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum PrimitiveSchemaTypes: String, Codable {
    case boolean
    case char
    case credential
    case date
    case dateTime = "date-time"
    case duration
    case integer
    case number
    case string
    case time
    case unixTime = "unixtime"
    case uri
    case uuid
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum QueryEncodingStyle: String, Codable {
    case deepObject
    case form
    case pipeDelimited
    case spaceDelimited
    case tabDelimited
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum SchemaContext: String, Codable {
    case exception
    case input
    case output
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// Possible schema types that indicate the type of schema.
enum SchemaType: String, Codable {
    case any
    case array
    case binary
    case boolean
    case byteArray = "byte-array"
    case char
    case choice
    case conditional
    case constant
    case credential
    case date
    case dateTime = "date-time"
    case dictionary
    case duration
    case flag
    case group
    case integer
    case not
    case number
    case object
    case odataQuery = "odata-query"
    case or
    case sealedChoice = "sealed-choice"
    case sealedConditional = "sealed-conditional"
    case string
    case time
    case unixTime = "unixtime"
    case unknown
    case uri
    case uuid
    case xor
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// The Serialization Style used for the parameter. Describes how the parameter value will be serialized depending on the type of the parameter value
enum SerializationStyle: String, Codable {
    case binary
    case deepObject
    case form
    case json
    case label
    case matrix
    case pipeDelimited
    case simple
    case spaceDelimited
    case tabDelimited
    case xml
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum StatusCode: String, Codable {
    case code100 = "100"
    case code101 = "101"
    case code102 = "102"
    case code103 = "103"
    case code200 = "200"
    case code201 = "201"
    case code202 = "202"
    case code203 = "203"
    case code204 = "204"
    case code205 = "205"
    case code206 = "206"
    case code207 = "207"
    case code208 = "208"
    case code226 = "226"
    case code300 = "300"
    case code301 = "301"
    case code302 = "302"
    case code303 = "303"
    case code304 = "304"
    case code305 = "305"
    case code306 = "306"
    case code307 = "307"
    case code308 = "308"
    case code400 = "400"
    case code401 = "401"
    case code402 = "402"
    case code403 = "403"
    case code404 = "404"
    case code405 = "405"
    case code406 = "406"
    case code407 = "407"
    case code408 = "408"
    case code409 = "409"
    case code410 = "410"
    case code411 = "411"
    case code412 = "412"
    case code413 = "413"
    case code414 = "414"
    case code415 = "415"
    case code416 = "416"
    case code417 = "417"
    case code418 = "418"
    case code421 = "421"
    case code422 = "422"
    case code423 = "423"
    case code424 = "424"
    case code425 = "425"
    case code426 = "426"
    case code428 = "428"
    case code429 = "429"
    case code431 = "431"
    case code451 = "451"
    case code500 = "500"
    case code501 = "501"
    case code502 = "502"
    case code503 = "503"
    case code504 = "504"
    case code505 = "505"
    case code506 = "506"
    case code507 = "507"
    case code508 = "508"
    case code510 = "510"
    case code511 = "511"
    case `default`
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum ValueSchemaTypes: String, Codable {
    case array
    case boolean
    case byteArray = "byte-array"
    case char
    case choice
    case conditional
    case credential
    case date
    case dateTime = "date-time"
    case duration
    case flag
    case integer
    case number
    case sealedChoice = "sealed-choice"
    case sealedConditional = "sealed-conditional"
    case string
    case time
    case unixTime = "unixtime"
    case uri
    case uuid
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

//  Original code found:
//  https://stackoverflow.com/a/48582964/2918468

import Foundation

protocol ExtensionStringDecodeKeys {
    var stringDecodedKeys: [String] { get }
}

public struct AnyCodable: Decodable, Encodable, Equatable {
    var value: Any

    struct CodingKeys: CodingKey {
        var stringValue: String
        var intValue: Int?
        init?(intValue: Int) {
            self.stringValue = "\(intValue)"
            self.intValue = intValue
        }

        init?(stringValue: String) { self.stringValue = stringValue }
    }

    // A sets of extensions key should be always decode as String type
    static var extensionStringDecodedKey: CodingUserInfoKey {
        return CodingUserInfoKey(rawValue: "stringDecoded")!
    }

    init(value: Any) {
        self.value = value
    }

    private func decodeDictionary(withDecoder decoder: Decoder) throws -> [String: Any] {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        var result = [String: Any]()
        try container.allKeys.forEach { (key) throws in
            result[key.stringValue] = try container.decode(AnyCodable.self, forKey: key).value
        }
        return result
    }

    private func decodeArray(withDecoder decoder: Decoder) throws -> [Any] {
        var container = try decoder.unkeyedContainer()
        var result = [Any]()
        while !container.isAtEnd {
            result.append(try container.decode(AnyCodable.self).value)
        }
        return result
    }

    private func decodeSimple(withDecoder decoder: Decoder) throws -> Any {
        let container = try decoder.singleValueContainer()
        let currentCodingKey = container.codingPath[container.codingPath.count - 1]

        let extensionKeys = decoder.userInfo[AnyCodable.extensionStringDecodedKey] as? ExtensionStringDecodeKeys
        let stringDecodedKeys = extensionKeys?.stringDecodedKeys

        // if the current coding key is part of the stringDecodedKeys, always decode as String. This is because
        // the values of these properties are always digits, they will be deocded as Int instead of string by default
        let shouldDecodedAsString = stringDecodedKeys?.contains(currentCodingKey.stringValue) ?? false

        if shouldDecodedAsString {
            if let stringVal = try? container.decode(String.self) {
                return stringVal
            } else {
                throw DecodingError.dataCorruptedError(
                    in: container,
                    debugDescription: "the container contains nothing serializable"
                )
            }
        } else if let intVal = try? container.decode(Int.self) {
            if let stringVal = try? container.decode(String.self) {
                // If the decode int value is only partial of the string value, use string value instead
                if String(intVal) == stringVal {
                    return intVal
                } else {
                    return stringVal
                }
            } else {
                return intVal
            }
        } else if let doubleVal = try? container.decode(Double.self) {
            return doubleVal
        } else if let boolVal = try? container.decode(Bool.self) {
            return boolVal
        } else if let stringVal = try? container.decode(String.self) {
            return stringVal
        } else {
            throw DecodingError.dataCorruptedError(
                in: container,
                debugDescription: "the container contains nothing serializable"
            )
        }
    }

    public init(from decoder: Decoder) throws {
        self.value = "" as Any
        let dictVal = try? decodeDictionary(withDecoder: decoder)
        let arrayVal = try? decodeArray(withDecoder: decoder)
        let simpleVal = try? decodeSimple(withDecoder: decoder)
        guard let value = dictVal ?? arrayVal ?? simpleVal else {
            throw DecodingError.dataCorrupted(
                DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not serialise")
            )
        }
        self.value = value
    }

    public func encode(to encoder: Encoder) throws {
        if let array = value as? [Any] {
            var container = encoder.unkeyedContainer()
            for value in array {
                let decodable = AnyCodable(value: value)
                try container.encode(decodable)
            }
        } else if let dictionary = value as? [String: Any] {
            var container = encoder.container(keyedBy: CodingKeys.self)
            for (key, value) in dictionary {
                let codingKey = CodingKeys(stringValue: key)!
                let decodable = AnyCodable(value: value)
                try container.encode(decodable, forKey: codingKey)
            }
        } else {
            var container = encoder.singleValueContainer()
            if let intVal = value as? Int {
                try container.encode(intVal)
            } else if let doubleVal = value as? Double {
                try container.encode(doubleVal)
            } else if let boolVal = value as? Bool {
                try container.encode(boolVal)
            } else if let stringVal = value as? String {
                try container.encode(stringVal)
            } else {
                throw EncodingError.invalidValue(
                    value,
                    EncodingError.Context(codingPath: [], debugDescription: "The value is not encodable")
                )
            }
        }
    }

    public static func == (_: AnyCodable, _: AnyCodable) -> Bool {
        // TODO: Complete implementation
        return false
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

enum ApiVersionRange: String, Codable {
    case plus = "+"
    case minus = "-"
}

// Since API version formats range from Azure ARM API date style (2018-01-01) to semver (1.2.3) and virtually
// any other text, this value tends to be an opaque string with the possibility of a modifier to indicate that it
// is a range.
// options:
// - prepend a dash or append a plus to indicate a range (ie, '2018-01-01+' or '-2019-01-01', or '1.0+' )
// - semver-range style (ie, '^1.0.0' or '~1.0.0' )
class ApiVersion: Codable {
    /// The actual API version string used in the API
    let version: String

    let range: ApiVersionRange?

    enum CodingKeys: String, CodingKey {
        case version, range
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        version = try container.decode(String.self, forKey: .version)
        range = try? container.decode(ApiVersionRange?.self, forKey: .range)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(version, forKey: .version)
        if range != nil { try? container.encode(range, forKey: .range) }
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

// enum StringOrNumberOrBoolean: String, Codable {
//    case string(String)
//    case int(Int)
//    case bool(Bool)
// }

/// an individual choice in a ChoiceSchema
class ChoiceValue: Codable, LanguageShortcut {
    /// per-language information for this value
    public var language: Languages

    /// the actual value
    // TODO: Resolve question about enum
    let value: String // StringOrNumberOrBoolean

    /// Additional metadata extensions dictionary
    let extensions: [String: AnyCodable]?

    enum CodingKeys: String, CodingKey {
        case language, value, extensions
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        language = try container.decode(Languages.self, forKey: .language)
        value = try container.decode(String.self, forKey: .value)
        extensions = try? container.decode([String: AnyCodable].self, forKey: .extensions)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(language, forKey: .language)
        try container.encode(value, forKey: .value)
        if extensions != nil { try container.encode(extensions, forKey: .extensions) }
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// an individual value in a ConditionalSchema
class ConditionalValue: Codable, LanguageShortcut {
    /// per-language information for this value
    public var language: Languages

    /// the actual value
    // TODO: Resolve issue with enum
    let target: String // StringOrNumberOrBoolean

    /// the source value
    // TODO: Resolve issue with enum
    let source: String // StringOrNumberOrBoolean

    /// Additional metadata extensions dictionary
    let extensions: [String: AnyCodable]?

    enum CodingKeys: String, CodingKey {
        case language, target, source, extensions
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        language = try container.decode(Languages.self, forKey: .language)
        target = try container.decode(String.self, forKey: .target)
        source = try container.decode(String.self, forKey: .source)
        extensions = try? container.decode([String: AnyCodable].self, forKey: .extensions)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(language, forKey: .language)
        try container.encode(target, forKey: .target)
        try container.encode(source, forKey: .source)
        if extensions != nil { try container.encode(extensions, forKey: .extensions) }
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// Contact information
class Contact: Codable {
    /// contact name
    let name: String?

    /// a URI
    let url: String?

    /// contact email
    let email: String?

    /// additional metadata extensions dictionary
    let extensions: [String: AnyCodable]?

    enum CodingKeys: String, CodingKey {
        case name, url, email, extensions
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        name = try? container.decode(String?.self, forKey: .name)
        url = try? container.decode(String?.self, forKey: .url)
        email = try? container.decode(String?.self, forKey: .email)
        extensions = try? container.decode([String: AnyCodable].self, forKey: .extensions)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        if name != nil { try? container.encode(name, forKey: .name) }
        if url != nil { try? container.encode(url, forKey: .url) }
        if email != nil { try? container.encode(email, forKey: .email) }
        if extensions != nil { try container.encode(extensions, forKey: .extensions) }
    }
}


// --------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the ""Software""), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
// --------------------------------------------------------------------------

import Foundation

/// Represents  deprecation information for a given aspect
class Deprecation: Codable {
    /// The reason why this aspect
    let message: String

    /// The api versions that this deprecation is applicable to.
    let apiVersions: [ApiVersion]
    enum CodingKeys: String, CodingKey {
        case message, apiVersions
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        message = try container.decode(String.self, forKey: .message)
        apiVersions = try container.decode([ApiVersion].self, forKey: .apiVersions)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(message, forKey: .message)
        try container.encode(apiVersions, forKey: .apiVersions)
    }
}