// --------------------------------------------------------------------------
//
// 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

// swiftlint:disable cyclomatic_complexity

/// View Model for an operation.
/// Example:
///     // a simple endpoint
///     public func simpleEndpoint(param: String? = nil, completionHandler: @escaping HTTPResultHandler<ReturnType>) { ... }
struct OperationViewModel {
    /// Name of the operation
    let name: String

    /// Comment association with the operation
    let comment: ViewModelComment

    let signatureComment: ViewModelComment

    let params: OperationParameters

    let returnType: ReturnTypeViewModel

    let clientMethodOptions: ClientMethodOptionsViewModel

    let pipelineContext: PipelineContextViewModel

    let request: RequestViewModel
    let responses: [ResponseViewModel]
    let exceptions: [ExceptionResponseViewModel]

    let defaultException: ExceptionResponseViewModel?
    let defaultExceptionHasBody: Bool
    let needHttpResponseData: Bool
    let validation: [String: Validation]
    let hasValidation: Bool

    init(from operation: Operation, with model: CodeModel, groupName: String) {
        guard let request = operation.request else { fatalError("Request not found for operation \(operation.name).") }
        self.request = RequestViewModel(from: request, with: operation)

        self.name = operationName(for: operation)
        self.comment = ViewModelComment(from: operation.description)

        let params = operation.allParams

        var responses = [ResponseViewModel]()
        for response in operation.responses ?? [] {
            responses.append(ResponseViewModel(from: response, with: operation))
        }

        var exceptions = [ExceptionResponseViewModel]()
        var defaultException: ExceptionResponseViewModel?
        for exception in operation.exceptions ?? [] {
            let viewModel = ExceptionResponseViewModel(from: exception)
            if viewModel.hasDefaultException {
                defaultException = viewModel
            } else {
                exceptions.append(viewModel)
            }
        }

        // Build up allowable status codes that can be returned from the service.
        var statusCodes = [String]()
        for response in responses {
            statusCodes += response.statusCodes
        }
        for exception in exceptions {
            statusCodes += exception.statusCodes
        }

        // Configure PipelineContext
        self.pipelineContext = PipelineContextViewModel(allowedStatusCodes: statusCodes)

        self.responses = responses
        self.exceptions = exceptions
        self.defaultException = defaultException
        let defaultExceptionHasBody = (defaultException != nil) && defaultException?.type != "Void"

        let returnType = ReturnTypeViewModel(from: self.responses)

        // create help struct to manage required and optional params in
        // headers/query/path, etc.
        self.params = OperationParameters(parameters: params, operation: operation, model: model)

        var signatureComments: [String] = []
        if let bodyParam = self.params.body {
            if !bodyParam.flattened,
                bodyParam.strategy != BodyParamStrategy.constant.rawValue {
                signatureComments.append("   - \(bodyParam.param.name) : \(bodyParam.param.comment.withoutPrefix)")
            }
        }
        for param in params.inSignature(model: model) where param.description != "" {
            signatureComments.append("   - \(param.name) : \(param.description)")
        }
        self.signatureComment = ViewModelComment(from: signatureComments.joined(separator: "\n"))

        self.clientMethodOptions = ClientMethodOptionsViewModel(
            from: operation,
            with: model,
            parameters: params.inOptions,
            groupName: groupName
        )

        self.returnType = returnType
        self.defaultExceptionHasBody = defaultExceptionHasBody
        self.needHttpResponseData = exceptions.count > 1 || (returnType.type != "Void") || defaultExceptionHasBody
        var validations = [String: Validation]()
        for param in params {
            // determine the appropriate prefix
            var prefix = param.located(in: .body) ? self.params.body!.param.name : param.variableName
            if !param.required {
                prefix = "\(prefix)?"
            }
            if let objectSchema = param.schema as? ObjectSchema {
                if let objectValidation = Validation.from(objectSchema: objectSchema, withPrefix: prefix) {
                    validations.merge(objectValidation) { current, _ in current }
                }
            } else {
                if let validation = Validation(with: param.schema, path: param.variableName) {
                    validations[param.variableName] = validation
                }
            }
        }
        self.validation = validations
        self.hasValidation = !validations.isEmpty
    }
}

private func filterParams(for params: [ParameterType]?, with allowed: [ParameterLocation]) -> [ParameterType] {
    let optionsParams = params?.filter { param in
        if let httpParam = param.protocol.http as? HttpParameter {
            return allowed.contains(httpParam.in)
        } else {
            return false
        }
    }
    return optionsParams ?? []
}

private func operationName(for operation: Operation) -> String {
    let swaggerName = operation.name
    var operationName = swaggerName
    var nameComps = swaggerName.splitAndJoinAcronyms

    // use `list` name if `x-ms-pageable` is set
    if operation.extensions?["x-ms-pageable"]?.value as? [String: String] != nil {
        nameComps[0] = "list"
    }

    for (index, comp) in nameComps.enumerated() {
        nameComps[index] = index == 0 ? comp.lowercased() : comp.capitalized
    }
    operationName = nameComps.joined()

    // Strip off the body param name, if there is one and the parameter is not flattened.
    // (ex: `createCat(...)` becomes `create(cat:...)`
    if let bodyParamName = operation.request?.bodyParamName(for: operation) {
        let suffix = bodyParamName.prefix(1).uppercased() + bodyParamName.dropFirst()
        if operationName.hasSuffix(suffix), !(operation.request?.bodyParam?.flattened ?? false) {
            operationName = String(operationName.dropLast(suffix.count))
        }
    }
    return operationName
}


// --------------------------------------------------------------------------
//
// 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

/// View Model for an the Package.swift file.
struct PackageFileViewModel {
    let name: String
    let namespace: String
    let version: String

    init(from model: CodeModel) {
        let args = Manager.shared.args
        self.name = args?.packageName ?? model.packageName
        self.namespace = args?.namespace ?? ""
        self.version = args?.packageVersion ?? ""
    }
}


// --------------------------------------------------------------------------
//
// 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

/// View Model for an operation parameter.
/// /// Operation description.
/// /// - Parameters:
/// ///  {name}: {comment}
/// public func method(
///   {name}: {type}{defaultValue},
/// ) {
///    // Construct URL
///    let urlTemplate = ""
///    let params = RequestParameters(
///        (.{location}, {serializedName}, {pathOrValue}, .{encode})
///    )
struct ParameterViewModel {
    /// Name of the parameter
    var name: String

    /// The name or key that should be sent over the wire
    var serializedName: String

    /// The value or variable path to the value of the parameter
    var pathOrValue: String

    /// Swift type annotation, including optionality, if applicable
    var type: String

    /// Swift type annotation used for constructing models
    let modelName: String

    /// Describes whether the field is optional
    var optional: Bool

    /// Default value for the parameter
    var defaultValue: ViewModelDefault

    /// Comment value for the parameter
    var comment: ViewModelComment

    /// Where the parameter goes in terms of the request
    var location: String

    /// Whether to URL encode the parameter or not
    let encode: String

    /// Whether the parameter should be exploded or not. Only applicable for query parameters
    let explode: Bool

    // MARK: Initializers

    init(
        name: String,
        serializedName: String,
        pathOrValue: String,
        type: String,
        optional: Bool,
        defaultValue: ViewModelDefault,
        comment: ViewModelComment,
        location: String,
        encode: String,
        explode: Bool
    ) {
        self.name = name
        self.serializedName = serializedName
        self.pathOrValue = pathOrValue
        self.type = type
        self.modelName = type.hasSuffix("?") ? String(type.dropLast()) : type
        self.optional = optional
        self.defaultValue = defaultValue
        self.comment = comment
        self.location = location
        self.encode = encode
        self.explode = explode
    }

    init(from param: ParameterType, with operation: Operation? = nil) {
        let optional = !param.required
        let swiftType = param.schema.swiftType()
        self.init(
            name: param.variableName,
            serializedName: param.serializedName ?? param.name,
            pathOrValue: "",
            type: optional ? "\(swiftType)?" : swiftType,
            optional: optional,
            defaultValue: ViewModelDefault(from: param.clientDefaultValue, isString: true, isOptional: optional),
            comment: ViewModelComment(from: param.description),
            location: param.paramLocation?.rawValue ?? "???",
            encode: param.value.isSkipUrlEncoding ? "skipEncoding" : "encode",
            explode: param.explode
        )
        // Update the `valueOrPath` parameter
        if param.implementation == .client {
            if ["$host", "endpoint"].contains(name) {
                self.pathOrValue = "client.endpoint.absoluteString"
            } else if ["apiversion", "x-ms-version"].contains(name.lowercased()) {
                self.pathOrValue = "client.options.apiVersion"
            } else {
                self.pathOrValue = "client.\(name)"
            }
        } else if let constantSchema = param.schema as? ConstantSchema {
            update(withConstantSchema: constantSchema)
        } else if let signatureParameter = operation?.signatureParameter(for: param.name) {
            update(withSignatureParameter: signatureParameter)
        } else if let groupedBy = param.groupedBy?.name,
            let operationName = operation?.name {
            // FIXME: Revisit this and see if it can be simplified
            // if groupBy name matches with naming convention of x-ms-parameter-grouping with postfix "Options",
            // the parameter should be in the Options object. But if parameter location is in Path, it  should
            // always be in signature
            if groupedBy.lowercased().hasSuffix("\(operationName)Options".lowercased()) {
                if param.paramLocation == .path {
                    self.pathOrValue = "\(param.name)"
                } else {
                    self.pathOrValue = "options?.\(param.name)"
                }
            } else {
                self.pathOrValue = "\(groupedBy).\(param.name)"
            }
        } else if let op = operation, param.paramLocation == .body {
            let bodyParamName = op.request?.bodyParamName(for: op)
            update(withBodySignatureParameter: param, andBodyParamName: bodyParamName)
        } else {
            // Scenario guarantees a compile error if it is actually used in code. Assert could trigger
            // failure here even if this would never find its way into code.
            self.pathOrValue = "???"
        }
    }

    private mutating func update(withSignatureParameter param: ParameterType) {
        assert(!(param.serializedName?.isEmpty ?? true))
        var pathOrValue = ""
        switch param.schema.type {
        case .byteArray:
            if let byteSchema = param.schema as? ByteArraySchema,
                byteSchema.format == .base64url {
                pathOrValue = "\(name).base64EncodedString(trimmingEquals: true)"
            } else {
                pathOrValue = name
            }
        case .array:
            if param.explode {
                // explode parameters are inflated in the stencil file
                pathOrValue = name
            } else {
                var element = "$0"
                if let arraySchema = param.schema as? ArraySchema,
                    arraySchema.nullableItems ?? false {
                    element = "$0 ?? \"\""
                }
                let mod = param.belongsInOptions() ? "?" : ""
                pathOrValue = "\(name)\(mod).map {\(element)}.joined(separator: \"\(param.delimiter)\") "
            }
        default:
            pathOrValue = name
        }
        self.pathOrValue = param.belongsInOptions() ? "options?.\(pathOrValue)" : "\(pathOrValue)"
    }

    private mutating func update(withConstantSchema constant: ConstantSchema) {
        let constantValue = constant.value.value
        switch constant.valueType.type {
        case .number:
            let swiftType = constant.valueType.swiftType()
            pathOrValue = "\(swiftType)(\(constantValue))"
        case .byteArray:
            if let byteArraySchema = constant.valueType as? ByteArraySchema,
                byteArraySchema.format == .base64url {
                assertionFailure("Unhandled case: base64url byteArray")
            } else {
                pathOrValue = "\"\(constantValue)\""
            }
        case .boolean:
            pathOrValue = "\(constantValue)"
        default:
            pathOrValue = "\"\(constantValue)\""
        }
    }

    private mutating func update(withBodySignatureParameter param: ParameterType, andBodyParamName name: String?) {
        let key = name ?? param.name
        pathOrValue = param.belongsInOptions() ? "options?.\(key)" : "\(key)"
    }

    static func < (lhs: ParameterViewModel, rhs: ParameterViewModel) -> Bool {
        return lhs.name.caseInsensitiveCompare(rhs.name) == .orderedAscending
    }
}


// --------------------------------------------------------------------------
//
// 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

/// View Model for generating the `PipelineContext` object in code.
struct PipelineContextViewModel {
    /// String value for allowed status codes (ex: "[200, 202])
    var allowedStatusCodes: String

    // MARK: Initializers

    init(allowedStatusCodes: [String]) {
        self.allowedStatusCodes = "[" + allowedStatusCodes.joined(separator: ", ") + "]"
    }
}


// --------------------------------------------------------------------------
//
// 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

/// View Model for a model property.
/// Example:
///     // a simple property
///     let simple: String = "default"
struct PropertyViewModel {
    let name: String
    let serializedName: String
    let comment: ViewModelComment
    let type: String
    // default value of the proeprty
    let defaultValue: ViewModelDefault
    // default value of the property in the init(). Valid values are either nil (for optional property) or "" (i.e. not specfied for required property in init() method.)
    let initDefaultValue: String
    let optional: Bool
    let className: String

    /// Initialize a `PropertyViewModel` directly
    init(
        name: String,
        type: String,
        serializedName: String? = nil,
        comment: String? = nil,
        defaultValue: String? = nil,
        initDefaultValue: String? = nil,
        optional: Bool = false,
        className: String? = nil
    ) {
        self.name = name
        self.type = type
        self.serializedName = serializedName ?? name
        self.comment = ViewModelComment(from: comment)
        self.defaultValue = ViewModelDefault(from: defaultValue, isString: true, isOptional: optional)
        self.initDefaultValue = initDefaultValue ?? ""
        self.optional = optional
        self.className = className ?? type
    }

    /// Initialize from Value type (such as Property or Parameter)
    init(from schema: Value, parentName: String? = nil) {
        // The `name` field is preferred.
        let name = schema.name
        assert(!name.isEmpty)
        self.name = name
        self.serializedName = schema.serializedName ?? name
        self.comment = ViewModelComment(from: schema.description)
        self.className = schema.schema!.swiftType(parentName: parentName)
        self.optional = !schema.required
        self.type = optional ? "\(className)?" : className
        self.defaultValue = ViewModelDefault(from: schema.clientDefaultValue, isString: true, isOptional: optional)
        self.initDefaultValue = optional ? "= nil" : ""
    }

    init(from schema: PropertyType, parentName: String? = nil) {
        switch schema {
        case let .regular(reg):
            self.init(from: reg, parentName: parentName)
        case let .grouped(group):
            self.init(from: group, parentName: parentName)
        }
    }
}


// --------------------------------------------------------------------------
//
// 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

/// Container for various README URLs.
struct ReadmeUrls {
    let source: String
    let api: String
    let product: String
    let samples: String
    let impressions: String
}

/// View Model for the README.md file.
struct ReadmeFileViewModel {
    let title: String
    let description: String
    let extendedDescription: String
    let urls: ReadmeUrls

    init(from model: CodeModel) {
        self.title = model.info.title
        self.description = model.info.description ?? ""
        self.extendedDescription = "TODO: Where?"
        self.urls = ReadmeUrls(
            source: "TODO: Find source URL",
            api: "TODO: Find API docs URL",
            product: "TODO: Find product documenation URL",
            samples: "TODO: Find samples URL",
            impressions: "TODO: Find impressions URL"
        )
    }
}


// --------------------------------------------------------------------------
//
// 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 RequestBodyType: String {
    /// Service requires some kind of serialized object
    case body
    /// Service requires no request body
    case noBody
    /// Service requires a serialzed JSON merge-patch body
    case patchBody
}

/// View Model for the method request creation.
struct RequestViewModel {
    /// The URI portion of the request
    let uri: String?

    /// The path portion of the request
    let path: String

    /// The method name for the request (GET, PUT, etc)
    let method: String

    /// The body parameter associated with this request, if any
    let bodyParam: BodyParamViewModel?

    /// Identifies the correct snippet to use when rendering the view model
    let strategy: String

    init(from request: Request, with operation: Operation) {
        // load HttpRequest properties
        let httpRequest = request.protocol.http as? HttpRequest
        self.uri = httpRequest?.uri
        self.path = httpRequest?.path ?? ""
        self.method = httpRequest?.method.rawValue ?? ""

        // create a body param model, if the request has one
        if let bodyParam = request.bodyParam {
            self.bodyParam = BodyParamViewModel(from: bodyParam, with: operation)
        } else {
            self.bodyParam = nil
        }

        // Determine which kind of request body snippet to render
        let plainPatchContentTypes = ["application/json", "application/merge-patch+json"]
        if method == "patch" {
            if let contentTypeParameter = request.parameter(for: "contentType"),
                let constantSchema = contentTypeParameter.schema as? ConstantSchema,
                plainPatchContentTypes.contains(constantSchema.value.value) {
                self.strategy = RequestBodyType.body.rawValue
            } else {
                self.strategy = RequestBodyType.patchBody.rawValue
            }
        } else {
            self.strategy = bodyParam != nil ? RequestBodyType.body.rawValue : RequestBodyType.noBody.rawValue
        }
    }
}


// --------------------------------------------------------------------------
//
// 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 ResponseBodyType: String {
    /// Returns a deserialized object (most common)
    case plainBody
    /// Service returns a pageable response
    case pagedBody
    /// Service returns no response data, only a status code
    case noBody
    /// Service returns a String
    case stringBody
    /// Service returns an Int
    case intBody
    /// Service returns a unixTime body
    case unixTimeBody
    /// Service returns a byteArray body
    case byteArrayBody

    static func strategy(for input: String, and schema: Schema) -> ResponseBodyType {
        let type = schema.type
        if input == "String" {
            return .stringBody
        } else if input.starts(with: "Int") {
            return .intBody
        } else if input == "Date" {
            switch type {
            case .unixTime:
                return .unixTimeBody
            default:
                return .plainBody
            }
        } else if type == .byteArray {
            return .byteArrayBody
        } else {
            return .plainBody
        }
    }
}

/// View Model for method response handling.
struct ResponseViewModel {
    /// List of allowed response status codes
    let statusCodes: [String]

    /// Swift type annotation, including optionality, if applicable
    let type: String

    /// Identifies the correct snippet to use when rendering the view model
    let strategy: String

    /// The `PagingNames` struct to use when generating paged objects
    let pagingNames: Language.PagingNames?

    /// The type name that belongs inside the `PagedCollection` generic
    let pagedElementType: String?

    /// If `true` the response is nullable
    let isNullable: Bool

    init(from response: Response, with operation: Operation) {
        let httpResponse = response.protocol.http as? HttpResponse
        var statusCodes = [String]()
        httpResponse?.statusCodes.forEach { statusCodes.append($0.rawValue) }

        self.statusCodes = statusCodes

        // check if the request body schema type is object, store the object type of the response body
        let schemaResponse = response as? SchemaResponse

        self.isNullable = schemaResponse?.nullable ?? false
        if let pagingMetadata = operation.extensions?["x-ms-pageable"]?.value as? [String: String],
            let pagingNames = Language.PagingNames(from: pagingMetadata) {
            var arrayElements = (schemaResponse?.schema.properties ?? []).compactMap { $0.schema as? ArraySchema }
            if arrayElements.isEmpty {
                let objectElements = (schemaResponse?.schema.properties ?? []).compactMap { $0.schema as? ObjectSchema }
                for object in objectElements {
                    let objectArrays = (object.properties ?? []).compactMap { $0.schema as? ArraySchema }
                    arrayElements += objectArrays
                }
            }

            // FIXME: This assumption no longer holds for storage and should be revisited
            guard arrayElements.count == 1
            else { fatalError("Did not find exactly one array type for paged collection.") }
            self.strategy = ResponseBodyType.pagedBody.rawValue
            self.pagingNames = pagingNames
            self.pagedElementType = arrayElements.first!.elementType.name

            if var elementType = pagedElementType, self.pagingNames != nil {
                elementType = Manager.shared.args!.generateAsInternal.aliasOrName(for: elementType)
                self.type = "PagedCollection<\(elementType)>"
            } else {
                self.type = schemaResponse?.schema.swiftType() ?? "Void"
            }
        } else {
            self.pagingNames = nil
            self.pagedElementType = nil
            if let type = schemaResponse?.schema.swiftType(),
                let schema = schemaResponse?.schema {
                self.strategy = ResponseBodyType.strategy(for: type, and: schema).rawValue
                self.type = type
            } else {
                self.strategy = ResponseBodyType.noBody.rawValue
                self.type = "Void"
            }
        }
    }
}


// --------------------------------------------------------------------------
//
// 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

/// View Model for method return type.
/// Example:
///     ... -> ReturnTypeName
struct ReturnTypeViewModel {
    /// The swift type name to return
    let type: String

    /// A flag to indicate in the generated code whether to return nil or void in the NoBody response stencil
    /// If the Return type of the function is nilable, we need to return nil. If the return type is Void, we return ()
    let returnNil: Bool

    init(from responses: [ResponseViewModel]?) {
        var types = Set<String>()
        var strategies = Set<String>()
        var hasNullableResponse = false
        for response in responses ?? [] {
            if response.strategy != RequestBodyType.noBody.rawValue {
                types.insert(response.type)
            }
            strategies.insert(response.strategy)
            hasNullableResponse = hasNullableResponse || response.isNullable
        }

        // Only supprt at most 1 body or pageBody return type now.
        let withBodyStrategies = strategies.filter { $0 != RequestBodyType.noBody.rawValue }
        assert(withBodyStrategies.count <= 1)

        let hasNoBodyStrategies = strategies.contains { $0 == RequestBodyType.noBody.rawValue }

        // since we only support 1 body/pagePage response, only need to take the first item in types
        if var type = types.first {
            type = Manager.shared.args!.generateAsInternal.aliasOrName(for: type)
            self.type = (hasNoBodyStrategies || hasNullableResponse) ? "\(type)?" : type
            self.returnNil = hasNoBodyStrategies
        } else {
            self.type = "Void"
            self.returnNil = 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

/// View Model for the service client file.
struct ServiceClientFileViewModel {
    let name: String
    let comment: ViewModelComment
    let visibility: String
    let operationGroups: [OperationGroupViewModel]
    let optionsName: String
    let protocols: String
    let paging: Language.PagingNames?
    let globalParameters: [ParameterViewModel]
    // A dictionary of all the named operation group. Key is the group name , Value is the operation group view model.
    let namedOperationGroups: [String: OperationGroupViewModel]
    // A key,Value pairs of all the named operation group for stencil template engine
    let namedOperationGroupShortcuts: [PropertyViewModel]
    let host: String

    init(from model: CodeModel) {
        let baseName = "\(model.packageName)Client"
        self.optionsName = Manager.shared.args!.generateAsInternal.aliasOrName(for: "\(baseName)Options")
        self.name = Manager.shared.args!.generateAsInternal.aliasOrName(for: baseName)
        self.visibility = Manager.shared.args!.generateAsInternal.visibility(for: name)
        self.comment = ViewModelComment(from: model.description)
        var operationGroups = [OperationGroupViewModel]()
        var namedOperationGroups = [String: OperationGroupViewModel]()
        var namedOperationGroupShortcuts = [PropertyViewModel]()
        for group in model.operationGroups {
            let viewModel = OperationGroupViewModel(from: group, with: model)
            if viewModel.name.isEmpty {
                operationGroups.append(viewModel)
            } else {
                namedOperationGroups[viewModel.name] = viewModel
            }
        }
        self.operationGroups = operationGroups
        self.namedOperationGroups = namedOperationGroups

        self.paging = model.pagingNames
        self.protocols = paging != nil ? "PipelineClient, PageableClient" : "PipelineClient"

        (self.globalParameters, self.host) = resolveGlobalParameters(from: model)

        for key in namedOperationGroups.keys.sorted() {
            namedOperationGroupShortcuts.append(PropertyViewModel(name: key.lowercasedFirst, type: key))
        }
        self.namedOperationGroupShortcuts = namedOperationGroupShortcuts
    }
}

func resolveGlobalParameters(from model: CodeModel) -> ([ParameterViewModel], String) {
    var globalParameters = [ParameterViewModel]()
    var host: String?
    var hostString: String
    for globalParameter in model.globalParameters ?? [] {
        if globalParameter.name == "$host" {
            host = globalParameter.value.clientDefaultValue
            // `endpoint` and `apiVersion` have different logic in generated code. Do not add them to the list of global parameters
        } else if !["endpoint", "apiVersion"].contains(globalParameter.variableName) {
            globalParameters.append(ParameterViewModel(from: globalParameter))
        }
    }

    if let hostValue = host {
        hostString = "\"\(hostValue)\""
    } else {
        hostString = ""
    }

    return (globalParameters, hostString)
}


// --------------------------------------------------------------------------
//
// 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

struct Validation {
    /// The parameter path
    let path: String

    /// whether property is optional or not
    let optional: Bool

    /// original parameter type
    let paramType: String

    /// indicates whether max length validation is specified
    let hasMaxLength: Bool

    /// the maximum length of the string
    let maxLength: Int?

    /// indicates whether min length validation is specified
    let hasMinLength: Bool

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

    /// indicates whether pattern validation is specified
    let hasPattern: Bool

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

    /// indicates whether multipleOf validation is specified
    let hasMultipleOf: Bool

    /// if present, the number must be an exact multiple of this value
    let multipleOf: Int?

    /// indicates whether maximum validation is specified
    let hasMaximum: Bool

    /// if present, the value must be lower than or equal to this (unless exclusiveMaximum is true)
    let maximum: Int?

    /// if present, the value must be lower than maximum
    let exclusiveMaximum: Bool?

    /// indicates whether minimum validation is specified
    let hasMinimum: Bool

    /// if present, the value must be highter than or equal to this (unless exclusiveMinimum is true)
    let minimum: Int?

    /// if present, the value must be higher than minimum
    let exclusiveMinimum: Bool?

    /// indicates whether max items validation is specified
    let hasMaxItems: Bool

    /// maximum number of elements in the array
    let maxItems: Int?

    /// indicates whether min items validation is specified
    let hasMinItems: Bool

    /// minimum number of elements in the array
    let minItems: Int?

    /// indicates whether uniqueItems validation is specified
    let hasUniqueItems: Bool

    /// if the elements in the array should be unique
    let uniqueItems: Bool?

    init?(
        path: String,
        paramType: String,
        maxLength: Int? = nil,
        minLength: Int? = nil,
        pattern: String? = nil,
        multipleOf: Int? = nil,
        maximum: Int? = nil,
        exclusiveMaximum: Bool? = nil,
        minimum: Int? = nil,
        exclusiveMinimum: Bool? = nil,
        maxItems: Int? = nil,
        minItems: Int? = nil,
        uniqueItems: Bool? = nil
    ) {
        var hasValidation = false
        for item in [
            maxLength,
            minLength,
            pattern,
            multipleOf,
            maximum,
            exclusiveMaximum,
            minimum,
            exclusiveMinimum,
            maxItems,
            minItems,
            uniqueItems
        ] as [Any?] where item != nil {
            hasValidation = true
            break
        }
        guard hasValidation else { return nil }
        self.path = path
        self.paramType = paramType
        self.optional = path.contains("?")

        self.maxLength = maxLength
        self.hasMaxLength = maxLength != nil

        self.minLength = minLength
        self.hasMinLength = minLength != nil

        self.pattern = pattern
        self.hasPattern = pattern != nil

        self.multipleOf = multipleOf
        self.hasMultipleOf = multipleOf != nil

        self.maximum = maximum
        self.exclusiveMaximum = exclusiveMaximum
        self.hasMaximum = maximum != nil

        self.minimum = minimum
        self.exclusiveMinimum = exclusiveMinimum
        self.hasMinimum = minimum != nil

        self.maxItems = maxItems
        self.hasMaxItems = maxItems != nil

        self.minItems = minItems
        self.hasMinItems = minItems != nil

        self.uniqueItems = uniqueItems
        self.hasUniqueItems = uniqueItems != nil
    }

    init?(with schema: StringSchema, path: String) {
        self.init(
            path: path,
            paramType: schema.swiftType(),
            maxLength: schema.maxLength,
            minLength: schema.minLength,
            pattern: schema.pattern
        )
    }

    init?(with schema: NumberSchema, path: String) {
        self.init(
            path: path,
            paramType: schema.swiftType(),
            multipleOf: schema.multipleOf,
            maximum: schema.maximum,
            exclusiveMaximum: schema.exclusiveMaximum,
            minimum: schema.minimum,
            exclusiveMinimum: schema.exclusiveMinimum
        )
    }

    init?(with schema: ArraySchema, path: String) {
        self.init(
            path: path,
            paramType: schema.swiftType(),
            maxItems: schema.maxItems,
            minItems: schema.minItems,
            uniqueItems: schema.uniqueItems
        )
    }

    init?(with schema: Schema, path: String) {
        if let stringSchema = schema as? StringSchema {
            self.init(with: stringSchema, path: path)
        } else if let numberSchema = schema as? NumberSchema {
            self.init(with: numberSchema, path: path)
        } else if let arraySchema = schema as? ArraySchema {
            self.init(with: arraySchema, path: path)
        } else if let constSchema = schema as? ConstantSchema {
            self.init(with: constSchema.valueType, path: path)
        } else {
            return nil
        }
    }

    public static func from(
        objectSchema schema: ObjectSchema,
        withPrefix prefix: String
    ) -> [String: Validation]? {
        var validations = [String: Validation]()
        for property in schema.properties ?? [] {
            let path = prefix.isEmpty ? property.name : "\(prefix).\(property.name)"
            if let objectSchema = property.schema as? ObjectSchema {
                var newPrefix = prefix.isEmpty ? property.name : "\(prefix).\(property.name)"
                if !property.required {
                    newPrefix = "\(newPrefix)?"
                }
                if let objectValidations = Validation.from(objectSchema: objectSchema, withPrefix: newPrefix) {
                    validations.merge(objectValidations) { _, latest in latest }
                }
            } else if let validation = Validation(with: property.schema, path: path) {
                validations[path] = validation
            }
        }
        return validations.isEmpty ? nil : validations
    }
}


// --------------------------------------------------------------------------
//
// 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

/// formatted version of comment
struct ViewModelComment: CustomStringConvertible {
    var withoutPrefix: String
    var description: String

    init(from descVal: String?) {
        guard let desc = descVal,
            desc.trimmingCharacters(in: .whitespacesAndNewlines) != "" else {
            self.description = ""
            self.withoutPrefix = ""
            return
        }
        // ensure multi-line comments are each commented
        let lines = desc.split(whereSeparator: \.isNewline).map { "/// \($0)" }
        description = lines.joined(separator: "\n")
        /// save a version without the leading /// for use in doc comments.
        withoutPrefix = String(description.dropFirst("/// ".count))
    }
}

/// formatted version of a default value
struct ViewModelDefault: CustomStringConvertible {
    var description: String

    init(from defaultValue: String?, isString: Bool, isOptional: Bool) {
        self.description = isOptional ? " = nil" : ""
        guard let val = defaultValue else { return }
        guard val.trimmingCharacters(in: .whitespacesAndNewlines) != "" else { return }
        self.description = isString ? " = \"\(val)\"" : " = \(val)"
    }
}


// --------------------------------------------------------------------------
//
// 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

struct VirtualParam {
    var name: String
    var type: String
    var defaultValue: String
    var path: String

    init(from param: VirtualParameter) {
        self.name = param.name
        var path = param.targetProperty.name
        if let groupBy = param.groupedBy?.name {
            path = "\(groupBy).\(path)"
        }
        self.path = path
        let optional = !param.required
        let swiftType = param.schema!.swiftType()
        self.type = optional ? "\(swiftType)?" : swiftType
        self.defaultValue = param.required ? "" : " = nil"
    }
}


// swift-tools-version:5.1
//  The swift-tools-version declares the minimum version of Swift required to build this package.
//
// --------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for
// license information.
//
// Code generated by Microsoft (R) AutoRest Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
// --------------------------------------------------------------------------

import PackageDescription

let package = Package(
    name: "AutoRestSwaggerBatArray",
    platforms: [
        .macOS(.v10_15), .iOS(.v12), .tvOS(.v12)
    ],
    products: [
        .library(name: "AutoRestSwaggerBatArray", type: .static, targets: ["AutoRestSwaggerBatArray"])
    ],
    dependencies: [
        .package(
            url: "https://github.com/Azure/SwiftPM-AzureCore.git",
            .branch("dev/AzureCore")
        )
    ],
    targets: [
        // Build targets
        .target(
            name: "AutoRestSwaggerBatArray",
            dependencies: ["AzureCore"],
            path: "Source"
        )
    ],
    swiftLanguageVersions: [.v5]
)


// --------------------------------------------------------------------------
//
// 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

// TODO: Custom Code Here