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

package com.microsoft.azure.cognitiveservices.language.luis.authoring.implementation;

import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.ListPhraseListsOptionalParameter;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.ListFeaturesOptionalParameter;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.UpdatePhraseListOptionalParameter;
import retrofit2.Retrofit;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.Features;
import com.google.common.base.Joiner;
import com.google.common.reflect.TypeToken;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.ErrorResponseException;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.FeaturesResponseObject;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.ModelFeatureInformation;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.OperationStatus;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.PhraselistCreateObject;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.PhraseListFeatureInfo;
import com.microsoft.azure.cognitiveservices.language.luis.authoring.models.PhraselistUpdateObject;
import com.microsoft.rest.ServiceCallback;
import com.microsoft.rest.ServiceFuture;
import com.microsoft.rest.ServiceResponse;
import com.microsoft.rest.Validator;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import okhttp3.ResponseBody;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.HTTP;
import retrofit2.http.Path;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Query;
import retrofit2.Response;
import rx.functions.Func1;
import rx.Observable;

/**
 * An instance of this class provides access to all the operations defined
 * in Features.
 */
public class FeaturesImpl implements Features {
    /** The Retrofit service to perform REST calls. */
    private FeaturesService service;
    /** The service client containing this operation class. */
    private LUISAuthoringClientImpl client;

    /**
     * Initializes an instance of FeaturesImpl.
     *
     * @param retrofit the Retrofit instance built from a Retrofit Builder.
     * @param client the instance of the service client containing this operation class.
     */
    public FeaturesImpl(Retrofit retrofit, LUISAuthoringClientImpl client) {
        this.service = retrofit.create(FeaturesService.class);
        this.client = client;
    }

    /**
     * The interface defining all the services for Features to be
     * used by Retrofit to perform actually REST calls.
     */
    interface FeaturesService {
        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features addPhraseList" })
        @POST("apps/{appId}/versions/{versionId}/phraselists")
        Observable<Response<ResponseBody>> addPhraseList(@Path("appId") UUID appId, @Path("versionId") String versionId, @Body PhraselistCreateObject phraselistCreateObject, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features listPhraseLists" })
        @GET("apps/{appId}/versions/{versionId}/phraselists")
        Observable<Response<ResponseBody>> listPhraseLists(@Path("appId") UUID appId, @Path("versionId") String versionId, @Query("skip") Integer skip, @Query("take") Integer take, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features list" })
        @GET("apps/{appId}/versions/{versionId}/features")
        Observable<Response<ResponseBody>> list(@Path("appId") UUID appId, @Path("versionId") String versionId, @Query("skip") Integer skip, @Query("take") Integer take, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features getPhraseList" })
        @GET("apps/{appId}/versions/{versionId}/phraselists/{phraselistId}")
        Observable<Response<ResponseBody>> getPhraseList(@Path("appId") UUID appId, @Path("versionId") String versionId, @Path("phraselistId") int phraselistId, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features updatePhraseList" })
        @PUT("apps/{appId}/versions/{versionId}/phraselists/{phraselistId}")
        Observable<Response<ResponseBody>> updatePhraseList(@Path("appId") UUID appId, @Path("versionId") String versionId, @Path("phraselistId") int phraselistId, @Body PhraselistUpdateObject phraselistUpdateObject, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features deletePhraseList" })
        @HTTP(path = "apps/{appId}/versions/{versionId}/phraselists/{phraselistId}", method = "DELETE", hasBody = true)
        Observable<Response<ResponseBody>> deletePhraseList(@Path("appId") UUID appId, @Path("versionId") String versionId, @Path("phraselistId") int phraselistId, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features addIntentFeature" })
        @POST("apps/{appId}/versions/{versionId}/intents/{intentId}/features")
        Observable<Response<ResponseBody>> addIntentFeature(@Path("appId") UUID appId, @Path("versionId") String versionId, @Path("intentId") UUID intentId, @Body ModelFeatureInformation featureRelationCreateObject, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.language.luis.authoring.Features addEntityFeature" })
        @POST("apps/{appId}/versions/{versionId}/entities/{entityId}/features")
        Observable<Response<ResponseBody>> addEntityFeature(@Path("appId") UUID appId, @Path("versionId") String versionId, @Path("entityId") UUID entityId, @Body ModelFeatureInformation featureRelationCreateObject, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

    }

    /**
     * Creates a new phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistCreateObject A Phraselist object containing Name, comma-separated Phrases and the isExchangeable boolean. Default value for isExchangeable is true.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the int object if successful.
     */
    public int addPhraseList(UUID appId, String versionId, PhraselistCreateObject phraselistCreateObject) {
        return addPhraseListWithServiceResponseAsync(appId, versionId, phraselistCreateObject).toBlocking().single().body();
    }

    /**
     * Creates a new phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistCreateObject A Phraselist object containing Name, comma-separated Phrases and the isExchangeable boolean. Default value for isExchangeable is true.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<Integer> addPhraseListAsync(UUID appId, String versionId, PhraselistCreateObject phraselistCreateObject, final ServiceCallback<Integer> serviceCallback) {
        return ServiceFuture.fromResponse(addPhraseListWithServiceResponseAsync(appId, versionId, phraselistCreateObject), serviceCallback);
    }

    /**
     * Creates a new phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistCreateObject A Phraselist object containing Name, comma-separated Phrases and the isExchangeable boolean. Default value for isExchangeable is true.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the Integer object
     */
    public Observable<Integer> addPhraseListAsync(UUID appId, String versionId, PhraselistCreateObject phraselistCreateObject) {
        return addPhraseListWithServiceResponseAsync(appId, versionId, phraselistCreateObject).map(new Func1<ServiceResponse<Integer>, Integer>() {
            @Override
            public Integer call(ServiceResponse<Integer> response) {
                return response.body();
            }
        });
    }

    /**
     * Creates a new phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistCreateObject A Phraselist object containing Name, comma-separated Phrases and the isExchangeable boolean. Default value for isExchangeable is true.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the Integer object
     */
    public Observable<ServiceResponse<Integer>> addPhraseListWithServiceResponseAsync(UUID appId, String versionId, PhraselistCreateObject phraselistCreateObject) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        if (phraselistCreateObject == null) {
            throw new IllegalArgumentException("Parameter phraselistCreateObject is required and cannot be null.");
        }
        Validator.validate(phraselistCreateObject);
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.addPhraseList(appId, versionId, phraselistCreateObject, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Integer>>>() {
                @Override
                public Observable<ServiceResponse<Integer>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Integer> clientResponse = addPhraseListDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<Integer> addPhraseListDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<Integer, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(201, new TypeToken<Integer>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }


    /**
     * Gets all the phraselist features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listPhraseListsOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the List&lt;PhraseListFeatureInfo&gt; object if successful.
     */
    public List<PhraseListFeatureInfo> listPhraseLists(UUID appId, String versionId, ListPhraseListsOptionalParameter listPhraseListsOptionalParameter) {
        return listPhraseListsWithServiceResponseAsync(appId, versionId, listPhraseListsOptionalParameter).toBlocking().single().body();
    }

    /**
     * Gets all the phraselist features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listPhraseListsOptionalParameter the object representing the optional parameters to be set before calling this API
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<List<PhraseListFeatureInfo>> listPhraseListsAsync(UUID appId, String versionId, ListPhraseListsOptionalParameter listPhraseListsOptionalParameter, final ServiceCallback<List<PhraseListFeatureInfo>> serviceCallback) {
        return ServiceFuture.fromResponse(listPhraseListsWithServiceResponseAsync(appId, versionId, listPhraseListsOptionalParameter), serviceCallback);
    }

    /**
     * Gets all the phraselist features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listPhraseListsOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;PhraseListFeatureInfo&gt; object
     */
    public Observable<List<PhraseListFeatureInfo>> listPhraseListsAsync(UUID appId, String versionId, ListPhraseListsOptionalParameter listPhraseListsOptionalParameter) {
        return listPhraseListsWithServiceResponseAsync(appId, versionId, listPhraseListsOptionalParameter).map(new Func1<ServiceResponse<List<PhraseListFeatureInfo>>, List<PhraseListFeatureInfo>>() {
            @Override
            public List<PhraseListFeatureInfo> call(ServiceResponse<List<PhraseListFeatureInfo>> response) {
                return response.body();
            }
        });
    }

    /**
     * Gets all the phraselist features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listPhraseListsOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;PhraseListFeatureInfo&gt; object
     */
    public Observable<ServiceResponse<List<PhraseListFeatureInfo>>> listPhraseListsWithServiceResponseAsync(UUID appId, String versionId, ListPhraseListsOptionalParameter listPhraseListsOptionalParameter) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        final Integer skip = listPhraseListsOptionalParameter != null ? listPhraseListsOptionalParameter.skip() : null;
        final Integer take = listPhraseListsOptionalParameter != null ? listPhraseListsOptionalParameter.take() : null;

        return listPhraseListsWithServiceResponseAsync(appId, versionId, skip, take);
    }

    /**
     * Gets all the phraselist features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param skip The number of entries to skip. Default value is 0.
     * @param take The number of entries to return. Maximum page size is 500. Default is 100.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;PhraseListFeatureInfo&gt; object
     */
    public Observable<ServiceResponse<List<PhraseListFeatureInfo>>> listPhraseListsWithServiceResponseAsync(UUID appId, String versionId, Integer skip, Integer take) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.listPhraseLists(appId, versionId, skip, take, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<List<PhraseListFeatureInfo>>>>() {
                @Override
                public Observable<ServiceResponse<List<PhraseListFeatureInfo>>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<List<PhraseListFeatureInfo>> clientResponse = listPhraseListsDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<List<PhraseListFeatureInfo>> listPhraseListsDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<List<PhraseListFeatureInfo>, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<List<PhraseListFeatureInfo>>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }

    @Override
    public FeaturesListPhraseListsParameters listPhraseLists() {
        return new FeaturesListPhraseListsParameters(this);
    }

    /**
     * Internal class implementing FeaturesListPhraseListsDefinition.
     */
    class FeaturesListPhraseListsParameters implements FeaturesListPhraseListsDefinition {
        private FeaturesImpl parent;
        private UUID appId;
        private String versionId;
        private Integer skip;
        private Integer take;

        /**
         * Constructor.
         * @param parent the parent object.
         */
        FeaturesListPhraseListsParameters(FeaturesImpl parent) {
            this.parent = parent;
        }

        @Override
        public FeaturesListPhraseListsParameters withAppId(UUID appId) {
            this.appId = appId;
            return this;
        }

        @Override
        public FeaturesListPhraseListsParameters withVersionId(String versionId) {
            this.versionId = versionId;
            return this;
        }

        @Override
        public FeaturesListPhraseListsParameters withSkip(Integer skip) {
            this.skip = skip;
            return this;
        }

        @Override
        public FeaturesListPhraseListsParameters withTake(Integer take) {
            this.take = take;
            return this;
        }

        @Override
        public List<PhraseListFeatureInfo> execute() {
        return listPhraseListsWithServiceResponseAsync(appId, versionId, skip, take).toBlocking().single().body();
    }

        @Override
        public Observable<List<PhraseListFeatureInfo>> executeAsync() {
            return listPhraseListsWithServiceResponseAsync(appId, versionId, skip, take).map(new Func1<ServiceResponse<List<PhraseListFeatureInfo>>, List<PhraseListFeatureInfo>>() {
                @Override
                public List<PhraseListFeatureInfo> call(ServiceResponse<List<PhraseListFeatureInfo>> response) {
                    return response.body();
                }
            });
        }
    }


    /**
     * Gets all the extraction phraselist and pattern features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the FeaturesResponseObject object if successful.
     */
    public FeaturesResponseObject list(UUID appId, String versionId, ListFeaturesOptionalParameter listOptionalParameter) {
        return listWithServiceResponseAsync(appId, versionId, listOptionalParameter).toBlocking().single().body();
    }

    /**
     * Gets all the extraction phraselist and pattern features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listOptionalParameter the object representing the optional parameters to be set before calling this API
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<FeaturesResponseObject> listAsync(UUID appId, String versionId, ListFeaturesOptionalParameter listOptionalParameter, final ServiceCallback<FeaturesResponseObject> serviceCallback) {
        return ServiceFuture.fromResponse(listWithServiceResponseAsync(appId, versionId, listOptionalParameter), serviceCallback);
    }

    /**
     * Gets all the extraction phraselist and pattern features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the FeaturesResponseObject object
     */
    public Observable<FeaturesResponseObject> listAsync(UUID appId, String versionId, ListFeaturesOptionalParameter listOptionalParameter) {
        return listWithServiceResponseAsync(appId, versionId, listOptionalParameter).map(new Func1<ServiceResponse<FeaturesResponseObject>, FeaturesResponseObject>() {
            @Override
            public FeaturesResponseObject call(ServiceResponse<FeaturesResponseObject> response) {
                return response.body();
            }
        });
    }

    /**
     * Gets all the extraction phraselist and pattern features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param listOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the FeaturesResponseObject object
     */
    public Observable<ServiceResponse<FeaturesResponseObject>> listWithServiceResponseAsync(UUID appId, String versionId, ListFeaturesOptionalParameter listOptionalParameter) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        final Integer skip = listOptionalParameter != null ? listOptionalParameter.skip() : null;
        final Integer take = listOptionalParameter != null ? listOptionalParameter.take() : null;

        return listWithServiceResponseAsync(appId, versionId, skip, take);
    }

    /**
     * Gets all the extraction phraselist and pattern features in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param skip The number of entries to skip. Default value is 0.
     * @param take The number of entries to return. Maximum page size is 500. Default is 100.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the FeaturesResponseObject object
     */
    public Observable<ServiceResponse<FeaturesResponseObject>> listWithServiceResponseAsync(UUID appId, String versionId, Integer skip, Integer take) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.list(appId, versionId, skip, take, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<FeaturesResponseObject>>>() {
                @Override
                public Observable<ServiceResponse<FeaturesResponseObject>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<FeaturesResponseObject> clientResponse = listDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<FeaturesResponseObject> listDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<FeaturesResponseObject, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<FeaturesResponseObject>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }

    @Override
    public FeaturesListParameters list() {
        return new FeaturesListParameters(this);
    }

    /**
     * Internal class implementing FeaturesListDefinition.
     */
    class FeaturesListParameters implements FeaturesListDefinition {
        private FeaturesImpl parent;
        private UUID appId;
        private String versionId;
        private Integer skip;
        private Integer take;

        /**
         * Constructor.
         * @param parent the parent object.
         */
        FeaturesListParameters(FeaturesImpl parent) {
            this.parent = parent;
        }

        @Override
        public FeaturesListParameters withAppId(UUID appId) {
            this.appId = appId;
            return this;
        }

        @Override
        public FeaturesListParameters withVersionId(String versionId) {
            this.versionId = versionId;
            return this;
        }

        @Override
        public FeaturesListParameters withSkip(Integer skip) {
            this.skip = skip;
            return this;
        }

        @Override
        public FeaturesListParameters withTake(Integer take) {
            this.take = take;
            return this;
        }

        @Override
        public FeaturesResponseObject execute() {
        return listWithServiceResponseAsync(appId, versionId, skip, take).toBlocking().single().body();
    }

        @Override
        public Observable<FeaturesResponseObject> executeAsync() {
            return listWithServiceResponseAsync(appId, versionId, skip, take).map(new Func1<ServiceResponse<FeaturesResponseObject>, FeaturesResponseObject>() {
                @Override
                public FeaturesResponseObject call(ServiceResponse<FeaturesResponseObject> response) {
                    return response.body();
                }
            });
        }
    }

    /**
     * Gets phraselist feature info in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be retrieved.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the PhraseListFeatureInfo object if successful.
     */
    public PhraseListFeatureInfo getPhraseList(UUID appId, String versionId, int phraselistId) {
        return getPhraseListWithServiceResponseAsync(appId, versionId, phraselistId).toBlocking().single().body();
    }

    /**
     * Gets phraselist feature info in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be retrieved.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<PhraseListFeatureInfo> getPhraseListAsync(UUID appId, String versionId, int phraselistId, final ServiceCallback<PhraseListFeatureInfo> serviceCallback) {
        return ServiceFuture.fromResponse(getPhraseListWithServiceResponseAsync(appId, versionId, phraselistId), serviceCallback);
    }

    /**
     * Gets phraselist feature info in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be retrieved.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PhraseListFeatureInfo object
     */
    public Observable<PhraseListFeatureInfo> getPhraseListAsync(UUID appId, String versionId, int phraselistId) {
        return getPhraseListWithServiceResponseAsync(appId, versionId, phraselistId).map(new Func1<ServiceResponse<PhraseListFeatureInfo>, PhraseListFeatureInfo>() {
            @Override
            public PhraseListFeatureInfo call(ServiceResponse<PhraseListFeatureInfo> response) {
                return response.body();
            }
        });
    }

    /**
     * Gets phraselist feature info in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be retrieved.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PhraseListFeatureInfo object
     */
    public Observable<ServiceResponse<PhraseListFeatureInfo>> getPhraseListWithServiceResponseAsync(UUID appId, String versionId, int phraselistId) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.getPhraseList(appId, versionId, phraselistId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<PhraseListFeatureInfo>>>() {
                @Override
                public Observable<ServiceResponse<PhraseListFeatureInfo>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<PhraseListFeatureInfo> clientResponse = getPhraseListDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<PhraseListFeatureInfo> getPhraseListDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<PhraseListFeatureInfo, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<PhraseListFeatureInfo>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }


    /**
     * Updates the phrases, the state and the name of the phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be updated.
     * @param updatePhraseListOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the OperationStatus object if successful.
     */
    public OperationStatus updatePhraseList(UUID appId, String versionId, int phraselistId, UpdatePhraseListOptionalParameter updatePhraseListOptionalParameter) {
        return updatePhraseListWithServiceResponseAsync(appId, versionId, phraselistId, updatePhraseListOptionalParameter).toBlocking().single().body();
    }

    /**
     * Updates the phrases, the state and the name of the phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be updated.
     * @param updatePhraseListOptionalParameter the object representing the optional parameters to be set before calling this API
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<OperationStatus> updatePhraseListAsync(UUID appId, String versionId, int phraselistId, UpdatePhraseListOptionalParameter updatePhraseListOptionalParameter, final ServiceCallback<OperationStatus> serviceCallback) {
        return ServiceFuture.fromResponse(updatePhraseListWithServiceResponseAsync(appId, versionId, phraselistId, updatePhraseListOptionalParameter), serviceCallback);
    }

    /**
     * Updates the phrases, the state and the name of the phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be updated.
     * @param updatePhraseListOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<OperationStatus> updatePhraseListAsync(UUID appId, String versionId, int phraselistId, UpdatePhraseListOptionalParameter updatePhraseListOptionalParameter) {
        return updatePhraseListWithServiceResponseAsync(appId, versionId, phraselistId, updatePhraseListOptionalParameter).map(new Func1<ServiceResponse<OperationStatus>, OperationStatus>() {
            @Override
            public OperationStatus call(ServiceResponse<OperationStatus> response) {
                return response.body();
            }
        });
    }

    /**
     * Updates the phrases, the state and the name of the phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be updated.
     * @param updatePhraseListOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<ServiceResponse<OperationStatus>> updatePhraseListWithServiceResponseAsync(UUID appId, String versionId, int phraselistId, UpdatePhraseListOptionalParameter updatePhraseListOptionalParameter) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        final PhraselistUpdateObject phraselistUpdateObject = updatePhraseListOptionalParameter != null ? updatePhraseListOptionalParameter.phraselistUpdateObject() : null;

        return updatePhraseListWithServiceResponseAsync(appId, versionId, phraselistId, phraselistUpdateObject);
    }

    /**
     * Updates the phrases, the state and the name of the phraselist feature in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be updated.
     * @param phraselistUpdateObject The new values for: - Just a boolean called IsActive, in which case the status of the feature will be changed. - Name, Pattern, Mode, and a boolean called IsActive to update the feature.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<ServiceResponse<OperationStatus>> updatePhraseListWithServiceResponseAsync(UUID appId, String versionId, int phraselistId, PhraselistUpdateObject phraselistUpdateObject) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        Validator.validate(phraselistUpdateObject);
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.updatePhraseList(appId, versionId, phraselistId, phraselistUpdateObject, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<OperationStatus>>>() {
                @Override
                public Observable<ServiceResponse<OperationStatus>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<OperationStatus> clientResponse = updatePhraseListDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<OperationStatus> updatePhraseListDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<OperationStatus, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<OperationStatus>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }

    @Override
    public FeaturesUpdatePhraseListParameters updatePhraseList() {
        return new FeaturesUpdatePhraseListParameters(this);
    }

    /**
     * Internal class implementing FeaturesUpdatePhraseListDefinition.
     */
    class FeaturesUpdatePhraseListParameters implements FeaturesUpdatePhraseListDefinition {
        private FeaturesImpl parent;
        private UUID appId;
        private String versionId;
        private int phraselistId;
        private PhraselistUpdateObject phraselistUpdateObject;

        /**
         * Constructor.
         * @param parent the parent object.
         */
        FeaturesUpdatePhraseListParameters(FeaturesImpl parent) {
            this.parent = parent;
        }

        @Override
        public FeaturesUpdatePhraseListParameters withAppId(UUID appId) {
            this.appId = appId;
            return this;
        }

        @Override
        public FeaturesUpdatePhraseListParameters withVersionId(String versionId) {
            this.versionId = versionId;
            return this;
        }

        @Override
        public FeaturesUpdatePhraseListParameters withPhraselistId(int phraselistId) {
            this.phraselistId = phraselistId;
            return this;
        }

        @Override
        public FeaturesUpdatePhraseListParameters withPhraselistUpdateObject(PhraselistUpdateObject phraselistUpdateObject) {
            this.phraselistUpdateObject = phraselistUpdateObject;
            return this;
        }

        @Override
        public OperationStatus execute() {
        return updatePhraseListWithServiceResponseAsync(appId, versionId, phraselistId, phraselistUpdateObject).toBlocking().single().body();
    }

        @Override
        public Observable<OperationStatus> executeAsync() {
            return updatePhraseListWithServiceResponseAsync(appId, versionId, phraselistId, phraselistUpdateObject).map(new Func1<ServiceResponse<OperationStatus>, OperationStatus>() {
                @Override
                public OperationStatus call(ServiceResponse<OperationStatus> response) {
                    return response.body();
                }
            });
        }
    }

    /**
     * Deletes a phraselist feature from a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be deleted.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the OperationStatus object if successful.
     */
    public OperationStatus deletePhraseList(UUID appId, String versionId, int phraselistId) {
        return deletePhraseListWithServiceResponseAsync(appId, versionId, phraselistId).toBlocking().single().body();
    }

    /**
     * Deletes a phraselist feature from a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be deleted.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<OperationStatus> deletePhraseListAsync(UUID appId, String versionId, int phraselistId, final ServiceCallback<OperationStatus> serviceCallback) {
        return ServiceFuture.fromResponse(deletePhraseListWithServiceResponseAsync(appId, versionId, phraselistId), serviceCallback);
    }

    /**
     * Deletes a phraselist feature from a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be deleted.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<OperationStatus> deletePhraseListAsync(UUID appId, String versionId, int phraselistId) {
        return deletePhraseListWithServiceResponseAsync(appId, versionId, phraselistId).map(new Func1<ServiceResponse<OperationStatus>, OperationStatus>() {
            @Override
            public OperationStatus call(ServiceResponse<OperationStatus> response) {
                return response.body();
            }
        });
    }

    /**
     * Deletes a phraselist feature from a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param phraselistId The ID of the feature to be deleted.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<ServiceResponse<OperationStatus>> deletePhraseListWithServiceResponseAsync(UUID appId, String versionId, int phraselistId) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.deletePhraseList(appId, versionId, phraselistId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<OperationStatus>>>() {
                @Override
                public Observable<ServiceResponse<OperationStatus>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<OperationStatus> clientResponse = deletePhraseListDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<OperationStatus> deletePhraseListDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<OperationStatus, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<OperationStatus>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }

    /**
     * Adds a new feature relation to be used by the intent in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param intentId The intent classifier ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the OperationStatus object if successful.
     */
    public OperationStatus addIntentFeature(UUID appId, String versionId, UUID intentId, ModelFeatureInformation featureRelationCreateObject) {
        return addIntentFeatureWithServiceResponseAsync(appId, versionId, intentId, featureRelationCreateObject).toBlocking().single().body();
    }

    /**
     * Adds a new feature relation to be used by the intent in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param intentId The intent classifier ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<OperationStatus> addIntentFeatureAsync(UUID appId, String versionId, UUID intentId, ModelFeatureInformation featureRelationCreateObject, final ServiceCallback<OperationStatus> serviceCallback) {
        return ServiceFuture.fromResponse(addIntentFeatureWithServiceResponseAsync(appId, versionId, intentId, featureRelationCreateObject), serviceCallback);
    }

    /**
     * Adds a new feature relation to be used by the intent in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param intentId The intent classifier ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<OperationStatus> addIntentFeatureAsync(UUID appId, String versionId, UUID intentId, ModelFeatureInformation featureRelationCreateObject) {
        return addIntentFeatureWithServiceResponseAsync(appId, versionId, intentId, featureRelationCreateObject).map(new Func1<ServiceResponse<OperationStatus>, OperationStatus>() {
            @Override
            public OperationStatus call(ServiceResponse<OperationStatus> response) {
                return response.body();
            }
        });
    }

    /**
     * Adds a new feature relation to be used by the intent in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param intentId The intent classifier ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<ServiceResponse<OperationStatus>> addIntentFeatureWithServiceResponseAsync(UUID appId, String versionId, UUID intentId, ModelFeatureInformation featureRelationCreateObject) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        if (intentId == null) {
            throw new IllegalArgumentException("Parameter intentId is required and cannot be null.");
        }
        if (featureRelationCreateObject == null) {
            throw new IllegalArgumentException("Parameter featureRelationCreateObject is required and cannot be null.");
        }
        Validator.validate(featureRelationCreateObject);
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.addIntentFeature(appId, versionId, intentId, featureRelationCreateObject, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<OperationStatus>>>() {
                @Override
                public Observable<ServiceResponse<OperationStatus>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<OperationStatus> clientResponse = addIntentFeatureDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<OperationStatus> addIntentFeatureDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<OperationStatus, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<OperationStatus>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }

    /**
     * Adds a new feature relation to be used by the entity in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param entityId The entity extractor ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws ErrorResponseException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the OperationStatus object if successful.
     */
    public OperationStatus addEntityFeature(UUID appId, String versionId, UUID entityId, ModelFeatureInformation featureRelationCreateObject) {
        return addEntityFeatureWithServiceResponseAsync(appId, versionId, entityId, featureRelationCreateObject).toBlocking().single().body();
    }

    /**
     * Adds a new feature relation to be used by the entity in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param entityId The entity extractor ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceFuture} object
     */
    public ServiceFuture<OperationStatus> addEntityFeatureAsync(UUID appId, String versionId, UUID entityId, ModelFeatureInformation featureRelationCreateObject, final ServiceCallback<OperationStatus> serviceCallback) {
        return ServiceFuture.fromResponse(addEntityFeatureWithServiceResponseAsync(appId, versionId, entityId, featureRelationCreateObject), serviceCallback);
    }

    /**
     * Adds a new feature relation to be used by the entity in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param entityId The entity extractor ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<OperationStatus> addEntityFeatureAsync(UUID appId, String versionId, UUID entityId, ModelFeatureInformation featureRelationCreateObject) {
        return addEntityFeatureWithServiceResponseAsync(appId, versionId, entityId, featureRelationCreateObject).map(new Func1<ServiceResponse<OperationStatus>, OperationStatus>() {
            @Override
            public OperationStatus call(ServiceResponse<OperationStatus> response) {
                return response.body();
            }
        });
    }

    /**
     * Adds a new feature relation to be used by the entity in a version of the application.
     *
     * @param appId The application ID.
     * @param versionId The version ID.
     * @param entityId The entity extractor ID.
     * @param featureRelationCreateObject A Feature relation information object.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the OperationStatus object
     */
    public Observable<ServiceResponse<OperationStatus>> addEntityFeatureWithServiceResponseAsync(UUID appId, String versionId, UUID entityId, ModelFeatureInformation featureRelationCreateObject) {
        if (this.client.endpoint() == null) {
            throw new IllegalArgumentException("Parameter this.client.endpoint() is required and cannot be null.");
        }
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (versionId == null) {
            throw new IllegalArgumentException("Parameter versionId is required and cannot be null.");
        }
        if (entityId == null) {
            throw new IllegalArgumentException("Parameter entityId is required and cannot be null.");
        }
        if (featureRelationCreateObject == null) {
            throw new IllegalArgumentException("Parameter featureRelationCreateObject is required and cannot be null.");
        }
        Validator.validate(featureRelationCreateObject);
        String parameterizedHost = Joiner.on(", ").join("{Endpoint}", this.client.endpoint());
        return service.addEntityFeature(appId, versionId, entityId, featureRelationCreateObject, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<OperationStatus>>>() {
                @Override
                public Observable<ServiceResponse<OperationStatus>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<OperationStatus> clientResponse = addEntityFeatureDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<OperationStatus> addEntityFeatureDelegate(Response<ResponseBody> response) throws ErrorResponseException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<OperationStatus, ErrorResponseException>newInstance(this.client.serializerAdapter())
                .register(200, new TypeToken<OperationStatus>() { }.getType())
                .registerError(ErrorResponseException.class)
                .build(response);
    }

}
