package {{package}};

import {{invokerPackage}}.ApiCallback;
import {{invokerPackage}}.ApiClient;
import {{invokerPackage}}.ApiException;
import {{invokerPackage}}.ApiResponse;
import {{invokerPackage}}.Configuration;
import {{invokerPackage}}.Pair;
import {{invokerPackage}}.ProgressRequestBody;
import {{invokerPackage}}.ProgressResponseBody;

import com.google.gson.reflect.TypeToken;

import com.squareup.okhttp.Call;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.Response;

import java.io.IOException;

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

import java.lang.reflect.Type;
{{^fullJavaUtil}}
import java.util.*;
{{/fullJavaUtil}}

{{#operations}}
public class {{classname}} {
  private ApiClient {{localVariablePrefix}}apiClient;

  public {{classname}}() {
    this(Configuration.getDefaultApiClient());
  }

  public {{classname}}(ApiClient apiClient) {
    this.{{localVariablePrefix}}apiClient = apiClient;
  }

  public ApiClient getApiClient() {
    return {{localVariablePrefix}}apiClient;
  }

  public void setApiClient(ApiClient apiClient) {
    this.{{localVariablePrefix}}apiClient = apiClient;
  }

  {{#operation}}
  /* Build call for {{operationId}} */
  private Call {{operationId}}Call({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException {
    Object {{localVariablePrefix}}postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}};
    {{#allParams}}{{#required}}
    // verify the required parameter '{{paramName}}' is set
    if ({{paramName}} == null) {
       throw new ApiException("Missing the required parameter '{{paramName}}' when calling {{operationId}}(Async)");
    }
    {{/required}}{{/allParams}}

    // create path and map variables
    String {{localVariablePrefix}}path = "{{path}}".replaceAll("\\{format\\}","json"){{#pathParams}}
      .replaceAll("\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}apiClient.escapeString({{{paramName}}}.toString())){{/pathParams}};

    {{javaUtilPrefix}}List<Pair> {{localVariablePrefix}}queryParams = new {{javaUtilPrefix}}ArrayList<Pair>();{{#queryParams}}
    if ({{paramName}} != null)
      {{localVariablePrefix}}queryParams.addAll({{localVariablePrefix}}apiClient.parameterToPairs("{{#collectionFormat}}{{{collectionFormat}}}{{/collectionFormat}}", "{{baseName}}", {{paramName}}));{{/queryParams}}

    {{javaUtilPrefix}}Map<String, String> {{localVariablePrefix}}headerParams = new {{javaUtilPrefix}}HashMap<String, String>();{{#headerParams}}
    if ({{paramName}} != null)
      {{localVariablePrefix}}headerParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}}));{{/headerParams}}

    {{javaUtilPrefix}}Map<String, Object> {{localVariablePrefix}}formParams = new {{javaUtilPrefix}}HashMap<String, Object>();{{#formParams}}
    if ({{paramName}} != null)
      {{localVariablePrefix}}formParams.put("{{baseName}}", {{paramName}});{{/formParams}}

    final String[] {{localVariablePrefix}}accepts = {
      {{#produces}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}}
    };
    final String {{localVariablePrefix}}accept = {{localVariablePrefix}}apiClient.selectHeaderAccept({{localVariablePrefix}}accepts);
    if ({{localVariablePrefix}}accept != null) {{localVariablePrefix}}headerParams.put("Accept", {{localVariablePrefix}}accept);

    final String[] {{localVariablePrefix}}contentTypes = {
      {{#consumes}}"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}
    };
    final String {{localVariablePrefix}}contentType = {{localVariablePrefix}}apiClient.selectHeaderContentType({{localVariablePrefix}}contentTypes);
    {{localVariablePrefix}}headerParams.put("Content-Type", {{localVariablePrefix}}contentType);

    if(progressListener != null) {
      apiClient.getHttpClient().networkInterceptors().add(new Interceptor() {
      @Override
      public Response intercept(Interceptor.Chain chain) throws IOException {
        Response originalResponse = chain.proceed(chain.request());
        return originalResponse.newBuilder()
                .body(new ProgressResponseBody(originalResponse.body(), progressListener))
                .build();
        }
      });
    }

    String[] {{localVariablePrefix}}authNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} };
    return {{localVariablePrefix}}apiClient.buildCall({{localVariablePrefix}}path, "{{httpMethod}}", {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}authNames, progressRequestListener);
  }

  /**
   * {{summary}}
   * {{notes}}{{#allParams}}
   * @param {{paramName}} {{description}}{{/allParams}}{{#returnType}}
   * @return {{{returnType}}}{{/returnType}}
   * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
   */
  public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException {
    {{#returnType}}ApiResponse<{{{returnType}}}> {{localVariablePrefix}}resp = {{/returnType}}{{operationId}}WithHttpInfo({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});{{#returnType}}
    return {{localVariablePrefix}}resp.getData();{{/returnType}}
  }

  /**
   * {{summary}}
   * {{notes}}{{#allParams}}
   * @param {{paramName}} {{description}}{{/allParams}}
   * @return ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>
   * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body
   */
  public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#allParams}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) throws ApiException {
    Call {{localVariablePrefix}}call = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}null, null);
    {{#returnType}}Type {{localVariablePrefix}}returnType = new TypeToken<{{{returnType}}}>(){}.getType();
    return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call, {{localVariablePrefix}}returnType);{{/returnType}}{{^returnType}}return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call);{{/returnType}}
  }

  /**
   * {{summary}} (asynchronously)
   * {{notes}}{{#allParams}}
   * @param {{paramName}} {{description}}{{/allParams}}
   * @param callback The callback to be executed when the API call finishes
   * @return The request call
   * @throws ApiException If fail to process the API call, e.g. serializing the request body object
   */
  public Call {{operationId}}Async({{#allParams}}{{{dataType}}} {{paramName}}, {{/allParams}}final ApiCallback<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{localVariablePrefix}}callback) throws ApiException {

    ProgressResponseBody.ProgressListener progressListener = null;
    ProgressRequestBody.ProgressRequestListener progressRequestListener = null;

    if (callback != null) {
      progressListener = new ProgressResponseBody.ProgressListener() {
        @Override
        public void update(long bytesRead, long contentLength, boolean done) {
          callback.onDownloadProgress(bytesRead, contentLength, done);
        } 
      };

      progressRequestListener = new ProgressRequestBody.ProgressRequestListener() {
        @Override
        public void onRequestProgress(long bytesWritten, long contentLength, boolean done) {
          callback.onUploadProgress(bytesWritten, contentLength, done);
        }
      };
    }

    Call {{localVariablePrefix}}call = {{operationId}}Call({{#allParams}}{{paramName}}, {{/allParams}}progressListener, progressRequestListener);
    {{#returnType}}Type {{localVariablePrefix}}returnType = new TypeToken<{{{returnType}}}>(){}.getType();
    {{localVariablePrefix}}apiClient.executeAsync({{localVariablePrefix}}call, {{localVariablePrefix}}returnType, {{localVariablePrefix}}callback);{{/returnType}}{{^returnType}}{{localVariablePrefix}}apiClient.executeAsync({{localVariablePrefix}}call, {{localVariablePrefix}}callback);{{/returnType}}
    return {{localVariablePrefix}}call;
  }
  {{/operation}}
}
{{/operations}}
