package {{package}};

{{#imports}}import {{import}};
{{/imports}}

import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.Http;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.inject.Inject;
import java.io.File;
{{^handleExceptions}}
import java.io.IOException;
{{/handleExceptions}}
import openapitools.OpenAPIUtils;
import com.fasterxml.jackson.core.type.TypeReference;
{{#supportAsync}}

import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
{{/supportAsync}}

{{#useBeanValidation}}
import javax.validation.constraints.*;
import play.Configuration;
{{/useBeanValidation}}

{{#wrapCalls}}
import openapitools.OpenAPIUtils.ApiAction;
{{/wrapCalls}}

{{>generatedAnnotation}}
{{#operations}}
public class {{classname}}Controller extends Controller {

    {{^controllerOnly}}
    private final {{classname}}ControllerImp{{#useInterfaces}}Interface{{/useInterfaces}} imp;
    {{/controllerOnly}}
    private final ObjectMapper mapper;
    {{#useBeanValidation}}
    private final Configuration configuration;
    {{/useBeanValidation}}

    @Inject
    private {{classname}}Controller({{#useBeanValidation}}Configuration configuration{{^controllerOnly}}, {{/controllerOnly}}{{/useBeanValidation}}{{^controllerOnly}}{{classname}}ControllerImp{{#useInterfaces}}Interface{{/useInterfaces}} imp{{/controllerOnly}}) {
        {{^controllerOnly}}
        this.imp = imp;
        {{/controllerOnly}}
        mapper = new ObjectMapper();
        {{#useBeanValidation}}
        this.configuration = configuration;
        {{/useBeanValidation}}
    }

{{#operation}}

    {{#wrapCalls}}@ApiAction{{/wrapCalls}}
    public {{#supportAsync}}CompletionStage<{{/supportAsync}}Result{{#supportAsync}}>{{/supportAsync}} {{operationId}}({{#pathParams}}{{>pathParams}}{{#hasMore}},{{/hasMore}}{{/pathParams}}) {{^handleExceptions}}{{#bodyParams}}throws IOException{{/bodyParams}}{{/handleExceptions}}{{#handleExceptions}}throws Exception{{/handleExceptions}} {
        {{#bodyParams}}
        {{^collectionFormat}}
        JsonNode node{{paramName}} = request().body().asJson();
        {{{dataType}}} {{paramName}};
        if (node{{paramName}} != null) {
            {{paramName}} = mapper.readValue(node{{paramName}}.toString(), {{#isContainer}}new TypeReference<{{{dataType}}}>(){}{{/isContainer}}{{^isContainer}}{{{dataType}}}.class{{/isContainer}});
            {{#useBeanValidation}}
            if (configuration.getBoolean("useInputBeanValidation")) {
                {{#isListContainer}}
                for ({{{items.baseType}}} curItem : {{paramName}}) {
                    OpenAPIUtils.validate(curItem);
                }
                {{/isListContainer}}
                {{#isMapContainer}}
                for (Map.Entry<String, {{{items.baseType}}}> entry : {{paramName}}.entrySet()) {
                    OpenAPIUtils.validate(entry.getValue());
                }
                {{/isMapContainer}}
                {{^isContainer}}
                OpenAPIUtils.validate({{paramName}});
                {{/isContainer}}
            }
            {{/useBeanValidation}}
        } else {
            {{#required}}
            throw new IllegalArgumentException("'{{baseName}}' parameter is required");
            {{/required}}
            {{^required}}
            {{paramName}} = null;
            {{/required}}
        }
        {{/collectionFormat}}
        {{/bodyParams}}
        {{#queryParams}}
        {{#collectionFormat}}
        String[] {{paramName}}Array = request().queryString().get("{{baseName}}");
        {{#required}}
        if ({{paramName}}Array == null) {
            throw new IllegalArgumentException("'{{baseName}}' parameter is required");
        }
        {{/required}}
        List<String> {{paramName}}List = OpenAPIUtils.parametersToList("{{collectionFormat}}", {{paramName}}Array);
        {{{dataType}}} {{paramName}} = new Array{{{dataType}}}();
        for (String curParam : {{paramName}}List) {
            if (!curParam.isEmpty()) {
                //noinspection UseBulkOperation
                {{paramName}}.add({{>itemConversionBegin}}curParam{{>itemConversionEnd}});
            }
        }
        {{/collectionFormat}}
        {{^collectionFormat}}
        String value{{paramName}} = request().getQueryString("{{baseName}}");
        {{{dataType}}} {{paramName}};
        if (value{{paramName}} != null) {
            {{paramName}} = {{>conversionBegin}}value{{paramName}}{{>conversionEnd}};
        } else {
            {{#required}}
            throw new IllegalArgumentException("'{{baseName}}' parameter is required");
            {{/required}}
            {{^required}}
            {{paramName}} = {{>paramDefaultValue}};
            {{/required}}
        }
        {{/collectionFormat}}
        {{/queryParams}}
        {{#formParams}}
        {{#isFile}}
        {{{dataType}}} {{paramName}} = request().body().asMultipartFormData().getFile("{{baseName}}");
        {{#required}}
        if (({{paramName}} == null || ((File) {{paramName}}.getFile()).length() == 0)) {
            throw new IllegalArgumentException("'{{baseName}}' file cannot be empty");
        }
        {{/required}}
        {{/isFile}}
        {{^isFile}}
        {{#collectionFormat}}
        String[] {{paramName}}Array = request().body().asMultipartFormData().asFormUrlEncoded().get("{{baseName}}");
        {{#required}}
        if ({{paramName}}Array == null) {
            throw new IllegalArgumentException("'{{baseName}}' parameter is required");
        }
        {{/required}}
        List<String> {{paramName}}List = OpenAPIUtils.parametersToList("{{collectionFormat}}", {{paramName}}Array);
        {{{dataType}}} {{paramName}} = new Array{{{dataType}}}();
        for (String curParam : {{paramName}}List) {
            if (!curParam.isEmpty()) {
                //noinspection UseBulkOperation
                {{paramName}}.add({{>itemConversionBegin}}curParam{{>itemConversionEnd}});
            }
        }
        {{/collectionFormat}}
        {{^collectionFormat}}
        String value{{paramName}} = (request().body().asMultipartFormData().asFormUrlEncoded().get("{{baseName}}"))[0];
        {{{dataType}}} {{paramName}};
        if (value{{paramName}} != null) {
            {{paramName}} = {{>conversionBegin}}value{{paramName}}{{>conversionEnd}};
        } else {
            {{#required}}
            throw new IllegalArgumentException("'{{baseName}}' parameter is required");
            {{/required}}
            {{^required}}
            {{paramName}} = {{>paramDefaultValue}};
            {{/required}}
        }
        {{/collectionFormat}}
        {{/isFile}}
        {{/formParams}}
        {{#headerParams}}
        {{#collectionFormat}}
        String[] {{paramName}}Array = request().headers().get("{{baseName}}");
        {{#required}}
        if ({{paramName}}Array == null) {
            throw new IllegalArgumentException("'{{baseName}}' parameter is required");
        }
        {{/required}}
        List<String> {{paramName}}List = OpenAPIUtils.parametersToList("{{collectionFormat}}", {{paramName}}Array);
        {{{dataType}}} {{paramName}} = new Array{{{dataType}}}();
        for (String curParam : {{paramName}}List) {
            if (!curParam.isEmpty()) {
                //noinspection UseBulkOperation
                {{paramName}}.add({{>itemConversionBegin}}curParam{{>itemConversionEnd}});
            }
        }
        {{/collectionFormat}}
        {{^collectionFormat}}
        String value{{paramName}} = request().getHeader("{{baseName}}");
        {{{dataType}}} {{paramName}};
        if (value{{paramName}} != null) {
            {{paramName}} = {{>conversionBegin}}value{{paramName}}{{>conversionEnd}};
        } else {
            {{#required}}
            throw new IllegalArgumentException("'{{baseName}}' parameter is required");
            {{/required}}
            {{^required}}
            {{paramName}} = {{>paramDefaultValue}};
            {{/required}}
        }
        {{/collectionFormat}}
        {{/headerParams}}
        {{^controllerOnly}}
        {{^returnType}}
        {{#supportAsync}}
        return CompletableFuture.supplyAsync(() -> {
        {{/supportAsync}}
        {{/returnType}}
        {{#returnType}}{{#supportAsync}}CompletionStage<{{>returnTypesNoVoid}}> stage = {{/supportAsync}}{{^supportAsync}}{{>returnTypesNoVoid}} obj = {{/supportAsync}}{{/returnType}}{{^returnType}}{{#supportAsync}}    {{/supportAsync}}{{/returnType}}imp.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}{{#supportAsync}}.thenApply(obj -> { {{/supportAsync}}{{/returnType}}{{^supportAsync}};{{/supportAsync}}
        {{#returnType}}
        {{^isResponseFile}}
        {{^returnTypeIsPrimitive}}
        {{#useBeanValidation}}
        {{^supportAsync}}
        if (configuration.getBoolean("useOutputBeanValidation")) {
            {{#isListContainer}}
            for ({{{returnType}}} curItem : obj) {
                OpenAPIUtils.validate(curItem);
            }
            {{/isListContainer}}
            {{#isMapContainer}}
            for (Map.Entry<String, {{{returnType}}}> entry : obj.entrySet()) {
                OpenAPIUtils.validate(entry.getValue());
            }
            {{/isMapContainer}}
            {{^returnContainer}}
            OpenAPIUtils.validate(obj);
            {{/returnContainer}}
        }
        {{/supportAsync}}
        {{#supportAsync}}
            if (configuration.getBoolean("useOutputBeanValidation")) {
                {{#isListContainer}}
                for ({{{returnType}}} curItem : obj) {
                    OpenAPIUtils.validate(curItem);
                }
                {{/isListContainer}}
                {{#isMapContainer}}
                for (Map.Entry<String, {{{returnType}}}> entry : obj.entrySet()) {
                    OpenAPIUtils.validate(entry.getValue());
                }
                {{/isMapContainer}}
                {{^returnContainer}}
                OpenAPIUtils.validate(obj);
                {{/returnContainer}}
            }
        {{/supportAsync}}
        {{/useBeanValidation}}
        {{/returnTypeIsPrimitive}}
        {{/isResponseFile}}
        {{#supportAsync}}
            return obj;
        });
        {{/supportAsync}}
        {{/returnType}}
        {{#returnType}}
        {{#supportAsync}}
        stage.thenApply(obj -> {
        {{/supportAsync}}
        {{^isResponseFile}}
        {{#supportAsync}}    {{/supportAsync}}JsonNode result = mapper.valueToTree(obj);
        {{#supportAsync}}    {{/supportAsync}}return ok(result);
        {{/isResponseFile}}
        {{#isResponseFile}}
        {{#supportAsync}}    {{/supportAsync}}return ok(obj);
        {{/isResponseFile}}
        {{/returnType}}
        {{^returnType}}
        {{#supportAsync}}    {{/supportAsync}}return ok();
        {{/returnType}}
        {{#supportAsync}}
        });
        {{/supportAsync}}
        {{/controllerOnly}}
        {{#controllerOnly}}
        return ok();
        {{/controllerOnly}}
    }
{{/operation}}
}
{{/operations}}
