/*
 *
 *  Copyright 2015-2019 the original author or authors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

package springfox.documentation.swagger2.mappers;


import io.swagger.models.ArrayModel;
import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
import io.swagger.models.RefModel;
import io.swagger.models.parameters.BodyParameter;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.FileProperty;
import io.swagger.models.properties.Property;
import org.mapstruct.Mapper;
import springfox.documentation.schema.Example;
import springfox.documentation.schema.ModelReference;

import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;

import static springfox.documentation.schema.Types.*;
import static springfox.documentation.swagger2.mappers.EnumMapper.*;
import static springfox.documentation.swagger2.mappers.Properties.*;

@Mapper
public class ParameterMapper {

  private static final VendorExtensionsMapper vendorMapper = new VendorExtensionsMapper();

  public Parameter mapParameter(springfox.documentation.service.Parameter source) {
    Parameter bodyParameter = bodyParameter(source);
    return SerializableParameterFactories.create(source).orElse(bodyParameter);
  }

  private Parameter bodyParameter(springfox.documentation.service.Parameter source) {
    BodyParameter parameter = new BodyParameter()
        .description(source.getDescription())
        .name(source.getName())
        .schema(fromModelRef(source.getModelRef()));
    parameter.setIn(source.getParamType());
    parameter.setAccess(source.getParamAccess());
    parameter.setPattern(source.getPattern());
    parameter.setRequired(source.isRequired());
    parameter.getVendorExtensions().putAll(vendorMapper.mapExtensions(source.getVendorExtentions()));
    for (Entry<String, List<Example>> each : source.getExamples().entrySet()) {
      Optional<Example> example = each.getValue().stream().findFirst();
      if (example.isPresent() && example.get().getValue() != null) {
        parameter.addExample(each.getKey(), String.valueOf(example.get().getValue()));
      }
    }

    //TODO: swagger-core Body parameter does not have an enum property
    return parameter;
  }

  Model fromModelRef(ModelReference modelRef) {
    if (modelRef.isCollection()) {
      if (modelRef.getItemType().equals("byte")) {
        ModelImpl baseModel = new ModelImpl();
        baseModel.setType("string");
        baseModel.setFormat("byte");
        return maybeAddAllowableValuesToParameter(baseModel, modelRef.getAllowableValues());
      } else if (modelRef.getItemType().equals("file")) {
        ArrayModel files = new ArrayModel();
        files.items(new FileProperty());
        return files;
      }
      ModelReference itemModel = modelRef.itemModel().get();
      return new ArrayModel()
          .items(maybeAddAllowableValues(itemTypeProperty(itemModel), itemModel.getAllowableValues()));
    }
    if (modelRef.isMap()) {
      ModelImpl baseModel = new ModelImpl();
      ModelReference itemModel = modelRef.itemModel().get();
      baseModel.additionalProperties(
          maybeAddAllowableValues(
              itemTypeProperty(itemModel),
              itemModel.getAllowableValues()));
      return baseModel;
    }
    if (isBaseType(modelRef.getType())) {
      Property property = property(modelRef.getType());
      ModelImpl baseModel = new ModelImpl();
      baseModel.setType(property.getType());
      baseModel.setFormat(property.getFormat());
      return maybeAddAllowableValuesToParameter(baseModel, modelRef.getAllowableValues());

    }
    return new RefModel(modelRef.getType());
  }
}

@@ -871,32 +871,83 @@
 .BodyParameter;%0A
+import io.swagger.models.parameters.FormParameter;%0A
 import io.swagge
@@ -969,32 +969,32 @@
 ters.Parameter;%0A
-
 import io.swagge
@@ -1698,37 +1698,185 @@
 %7B%0A    Parameter 
-bodyP
+parameter;%0A    switch (source.getParamType()) %7B%0A      case %22formData%22:%0A        parameter = formParameter(source);%0A        break;%0A      default:%0A        p
 arameter = bodyP
@@ -1889,24 +1889,45 @@
 er(source);%0A
+        break;%0A    %7D%0A
     return S
@@ -1982,22 +1982,986 @@
 lse(
-bodyParameter)
+parameter);%0A  %7D%0A%0A  private Parameter formParameter(springfox.documentation.service.Parameter source) %7B%0A    FormParameter parameter = new FormParameter()%0A            .description(source.getDescription())%0A            .type(source.getModelRef().getType())%0A            .name(source.getName());%0A    parameter.setIn(source.getParamType());%0A    parameter.setAccess(source.getParamAccess());%0A    parameter.setPattern(source.getPattern());%0A    parameter.setRequired(source.isRequired());%0A    parameter.getVendorExtensions().putAll(vendorMapper.mapExtensions(source.getVendorExtentions()));%0A    for (Entry%3CString, List%3CExample%3E%3E each : source.getExamples().entrySet()) %7B%0A      Optional%3CExample%3E example = each.getValue().stream().findFirst();%0A      if (example.isPresent() && example.get().getValue() != null) %7B%0A        // Form parameters only support a single example%0A        parameter.example(String.valueOf(example.get().getValue()));%0A        break;%0A      %7D%0A    %7D%0A%0A    return parameter
 ;%0A  

Create a FormParameter model object instead of BodyParameter for fields that are part of a multipart form (in=formData).