/**
 * 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.vision.faceapi.implementation;

import com.microsoft.azure.cognitiveservices.vision.faceapi.models.CreatePersonGroupsOptionalParameter;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.UpdatePersonGroupsOptionalParameter;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.ListPersonGroupsOptionalParameter;
import retrofit2.Retrofit;
import com.microsoft.azure.cognitiveservices.vision.faceapi.PersonGroups;
import com.google.common.base.Joiner;
import com.google.common.reflect.TypeToken;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.APIErrorException;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.NameAndUserDataContract;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.PersonGroup;
import com.microsoft.azure.cognitiveservices.vision.faceapi.models.TrainingStatus;
import com.microsoft.rest.ServiceCallback;
import com.microsoft.rest.ServiceFuture;
import com.microsoft.rest.ServiceResponse;
import java.io.IOException;
import java.util.List;
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.PATCH;
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 PersonGroups.
 */
public class PersonGroupsImpl implements PersonGroups {
    /** The Retrofit service to perform REST calls. */
    private PersonGroupsService service;
    /** The service client containing this operation class. */
    private FaceAPIImpl client;

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

    /**
     * The interface defining all the services for PersonGroups to be
     * used by Retrofit to perform actually REST calls.
     */
    interface PersonGroupsService {
        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.cognitiveservices.vision.faceapi.PersonGroups create" })
        @PUT("persongroups/{personGroupId}")
        Observable<Response<ResponseBody>> create(@Path("personGroupId") String personGroupId, @Header("accept-language") String acceptLanguage, @Body NameAndUserDataContract bodyParameter, @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.vision.faceapi.PersonGroups delete" })
        @HTTP(path = "persongroups/{personGroupId}", method = "DELETE", hasBody = true)
        Observable<Response<ResponseBody>> delete(@Path("personGroupId") String personGroupId, @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.vision.faceapi.PersonGroups get" })
        @GET("persongroups/{personGroupId}")
        Observable<Response<ResponseBody>> get(@Path("personGroupId") String personGroupId, @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.vision.faceapi.PersonGroups update" })
        @PATCH("persongroups/{personGroupId}")
        Observable<Response<ResponseBody>> update(@Path("personGroupId") String personGroupId, @Header("accept-language") String acceptLanguage, @Body NameAndUserDataContract bodyParameter, @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.vision.faceapi.PersonGroups getTrainingStatus" })
        @GET("persongroups/{personGroupId}/training")
        Observable<Response<ResponseBody>> getTrainingStatus(@Path("personGroupId") String personGroupId, @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.vision.faceapi.PersonGroups list" })
        @GET("persongroups")
        Observable<Response<ResponseBody>> list(@Query("start") String start, @Query("top") Integer top, @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.vision.faceapi.PersonGroups train" })
        @POST("persongroups/{personGroupId}/train")
        Observable<Response<ResponseBody>> train(@Path("personGroupId") String personGroupId, @Header("accept-language") String acceptLanguage, @Header("x-ms-parameterized-host") String parameterizedHost, @Header("User-Agent") String userAgent);

    }


    /**
     * Create a new person group with specified personGroupId, name and user-provided userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param createOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void create(String personGroupId, CreatePersonGroupsOptionalParameter createOptionalParameter) {
        createWithServiceResponseAsync(personGroupId, createOptionalParameter).toBlocking().single().body();
    }

    /**
     * Create a new person group with specified personGroupId, name and user-provided userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param createOptionalParameter 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<Void> createAsync(String personGroupId, CreatePersonGroupsOptionalParameter createOptionalParameter, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(createWithServiceResponseAsync(personGroupId, createOptionalParameter), serviceCallback);
    }

    /**
     * Create a new person group with specified personGroupId, name and user-provided userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param createOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> createAsync(String personGroupId, CreatePersonGroupsOptionalParameter createOptionalParameter) {
        return createWithServiceResponseAsync(personGroupId, createOptionalParameter).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Create a new person group with specified personGroupId, name and user-provided userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param createOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> createWithServiceResponseAsync(String personGroupId, CreatePersonGroupsOptionalParameter createOptionalParameter) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        final String name = createOptionalParameter != null ? createOptionalParameter.name() : null;
        final String userData = createOptionalParameter != null ? createOptionalParameter.userData() : null;

        return createWithServiceResponseAsync(personGroupId, name, userData);
    }

    /**
     * Create a new person group with specified personGroupId, name and user-provided userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param name User defined name, maximum length is 128.
     * @param userData User specified data. Length should not exceed 16KB.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> createWithServiceResponseAsync(String personGroupId, String name, String userData) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        NameAndUserDataContract bodyParameter = new NameAndUserDataContract();
        bodyParameter.withName(name);
        bodyParameter.withUserData(userData);
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.create(personGroupId, this.client.acceptLanguage(), bodyParameter, parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = createDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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

    @Override
    public PersonGroupsCreateParameters create() {
        return new PersonGroupsCreateParameters(this);
    }

    /**
     * Internal class implementing PersonGroupsCreateDefinition.
     */
    class PersonGroupsCreateParameters implements PersonGroupsCreateDefinition {
        private PersonGroupsImpl parent;
        private String personGroupId;
        private String name;
        private String userData;

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

        @Override
        public PersonGroupsCreateParameters withPersonGroupId(String personGroupId) {
            this.personGroupId = personGroupId;
            return this;
        }

        @Override
        public PersonGroupsCreateParameters withName(String name) {
            this.name = name;
            return this;
        }

        @Override
        public PersonGroupsCreateParameters withUserData(String userData) {
            this.userData = userData;
            return this;
        }

        @Override
        public void execute() {
        createWithServiceResponseAsync(personGroupId, name, userData).toBlocking().single().body();
    }

        @Override
        public Observable<Void> executeAsync() {
            return createWithServiceResponseAsync(personGroupId, name, userData).map(new Func1<ServiceResponse<Void>, Void>() {
                @Override
                public Void call(ServiceResponse<Void> response) {
                    return response.body();
                }
            });
        }
    }

    /**
     * Delete an existing person group. Persisted face images of all people in the person group will also be deleted.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void delete(String personGroupId) {
        deleteWithServiceResponseAsync(personGroupId).toBlocking().single().body();
    }

    /**
     * Delete an existing person group. Persisted face images of all people in the person group will also be deleted.
     *
     * @param personGroupId Id referencing a particular person group.
     * @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<Void> deleteAsync(String personGroupId, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(personGroupId), serviceCallback);
    }

    /**
     * Delete an existing person group. Persisted face images of all people in the person group will also be deleted.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> deleteAsync(String personGroupId) {
        return deleteWithServiceResponseAsync(personGroupId).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Delete an existing person group. Persisted face images of all people in the person group will also be deleted.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> deleteWithServiceResponseAsync(String personGroupId) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.delete(personGroupId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = deleteDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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

    /**
     * Retrieve the information of a person group, including its name and userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the PersonGroup object if successful.
     */
    public PersonGroup get(String personGroupId) {
        return getWithServiceResponseAsync(personGroupId).toBlocking().single().body();
    }

    /**
     * Retrieve the information of a person group, including its name and userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @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<PersonGroup> getAsync(String personGroupId, final ServiceCallback<PersonGroup> serviceCallback) {
        return ServiceFuture.fromResponse(getWithServiceResponseAsync(personGroupId), serviceCallback);
    }

    /**
     * Retrieve the information of a person group, including its name and userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersonGroup object
     */
    public Observable<PersonGroup> getAsync(String personGroupId) {
        return getWithServiceResponseAsync(personGroupId).map(new Func1<ServiceResponse<PersonGroup>, PersonGroup>() {
            @Override
            public PersonGroup call(ServiceResponse<PersonGroup> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve the information of a person group, including its name and userData.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the PersonGroup object
     */
    public Observable<ServiceResponse<PersonGroup>> getWithServiceResponseAsync(String personGroupId) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.get(personGroupId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<PersonGroup>>>() {
                @Override
                public Observable<ServiceResponse<PersonGroup>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<PersonGroup> clientResponse = getDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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


    /**
     * Update an existing person group's display name and userData. The properties which does not appear in request body will not be updated.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param updateOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void update(String personGroupId, UpdatePersonGroupsOptionalParameter updateOptionalParameter) {
        updateWithServiceResponseAsync(personGroupId, updateOptionalParameter).toBlocking().single().body();
    }

    /**
     * Update an existing person group's display name and userData. The properties which does not appear in request body will not be updated.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param updateOptionalParameter 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<Void> updateAsync(String personGroupId, UpdatePersonGroupsOptionalParameter updateOptionalParameter, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(updateWithServiceResponseAsync(personGroupId, updateOptionalParameter), serviceCallback);
    }

    /**
     * Update an existing person group's display name and userData. The properties which does not appear in request body will not be updated.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param updateOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> updateAsync(String personGroupId, UpdatePersonGroupsOptionalParameter updateOptionalParameter) {
        return updateWithServiceResponseAsync(personGroupId, updateOptionalParameter).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Update an existing person group's display name and userData. The properties which does not appear in request body will not be updated.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param updateOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> updateWithServiceResponseAsync(String personGroupId, UpdatePersonGroupsOptionalParameter updateOptionalParameter) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        final String name = updateOptionalParameter != null ? updateOptionalParameter.name() : null;
        final String userData = updateOptionalParameter != null ? updateOptionalParameter.userData() : null;

        return updateWithServiceResponseAsync(personGroupId, name, userData);
    }

    /**
     * Update an existing person group's display name and userData. The properties which does not appear in request body will not be updated.
     *
     * @param personGroupId Id referencing a particular person group.
     * @param name User defined name, maximum length is 128.
     * @param userData User specified data. Length should not exceed 16KB.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> updateWithServiceResponseAsync(String personGroupId, String name, String userData) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        NameAndUserDataContract bodyParameter = new NameAndUserDataContract();
        bodyParameter.withName(name);
        bodyParameter.withUserData(userData);
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.update(personGroupId, this.client.acceptLanguage(), bodyParameter, parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = updateDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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

    @Override
    public PersonGroupsUpdateParameters update() {
        return new PersonGroupsUpdateParameters(this);
    }

    /**
     * Internal class implementing PersonGroupsUpdateDefinition.
     */
    class PersonGroupsUpdateParameters implements PersonGroupsUpdateDefinition {
        private PersonGroupsImpl parent;
        private String personGroupId;
        private String name;
        private String userData;

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

        @Override
        public PersonGroupsUpdateParameters withPersonGroupId(String personGroupId) {
            this.personGroupId = personGroupId;
            return this;
        }

        @Override
        public PersonGroupsUpdateParameters withName(String name) {
            this.name = name;
            return this;
        }

        @Override
        public PersonGroupsUpdateParameters withUserData(String userData) {
            this.userData = userData;
            return this;
        }

        @Override
        public void execute() {
        updateWithServiceResponseAsync(personGroupId, name, userData).toBlocking().single().body();
    }

        @Override
        public Observable<Void> executeAsync() {
            return updateWithServiceResponseAsync(personGroupId, name, userData).map(new Func1<ServiceResponse<Void>, Void>() {
                @Override
                public Void call(ServiceResponse<Void> response) {
                    return response.body();
                }
            });
        }
    }

    /**
     * Retrieve the training status of a person group (completed or ongoing).
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     * @return the TrainingStatus object if successful.
     */
    public TrainingStatus getTrainingStatus(String personGroupId) {
        return getTrainingStatusWithServiceResponseAsync(personGroupId).toBlocking().single().body();
    }

    /**
     * Retrieve the training status of a person group (completed or ongoing).
     *
     * @param personGroupId Id referencing a particular person group.
     * @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<TrainingStatus> getTrainingStatusAsync(String personGroupId, final ServiceCallback<TrainingStatus> serviceCallback) {
        return ServiceFuture.fromResponse(getTrainingStatusWithServiceResponseAsync(personGroupId), serviceCallback);
    }

    /**
     * Retrieve the training status of a person group (completed or ongoing).
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the TrainingStatus object
     */
    public Observable<TrainingStatus> getTrainingStatusAsync(String personGroupId) {
        return getTrainingStatusWithServiceResponseAsync(personGroupId).map(new Func1<ServiceResponse<TrainingStatus>, TrainingStatus>() {
            @Override
            public TrainingStatus call(ServiceResponse<TrainingStatus> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve the training status of a person group (completed or ongoing).
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the TrainingStatus object
     */
    public Observable<ServiceResponse<TrainingStatus>> getTrainingStatusWithServiceResponseAsync(String personGroupId) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.getTrainingStatus(personGroupId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<TrainingStatus>>>() {
                @Override
                public Observable<ServiceResponse<TrainingStatus>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<TrainingStatus> clientResponse = getTrainingStatusDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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


    /**
     * List person groups and their information.
     *
     * @param listOptionalParameter the object representing the optional parameters to be set before calling this API
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException 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;PersonGroup&gt; object if successful.
     */
    public List<PersonGroup> list(ListPersonGroupsOptionalParameter listOptionalParameter) {
        return listWithServiceResponseAsync(listOptionalParameter).toBlocking().single().body();
    }

    /**
     * List person groups and their information.
     *
     * @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<List<PersonGroup>> listAsync(ListPersonGroupsOptionalParameter listOptionalParameter, final ServiceCallback<List<PersonGroup>> serviceCallback) {
        return ServiceFuture.fromResponse(listWithServiceResponseAsync(listOptionalParameter), serviceCallback);
    }

    /**
     * List person groups and their information.
     *
     * @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 List&lt;PersonGroup&gt; object
     */
    public Observable<List<PersonGroup>> listAsync(ListPersonGroupsOptionalParameter listOptionalParameter) {
        return listWithServiceResponseAsync(listOptionalParameter).map(new Func1<ServiceResponse<List<PersonGroup>>, List<PersonGroup>>() {
            @Override
            public List<PersonGroup> call(ServiceResponse<List<PersonGroup>> response) {
                return response.body();
            }
        });
    }

    /**
     * List person groups and their information.
     *
     * @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 List&lt;PersonGroup&gt; object
     */
    public Observable<ServiceResponse<List<PersonGroup>>> listWithServiceResponseAsync(ListPersonGroupsOptionalParameter listOptionalParameter) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        final String start = listOptionalParameter != null ? listOptionalParameter.start() : null;
        final Integer top = listOptionalParameter != null ? listOptionalParameter.top() : null;

        return listWithServiceResponseAsync(start, top);
    }

    /**
     * List person groups and their information.
     *
     * @param start List person groups from the least personGroupId greater than the "start".
     * @param top The number of person groups to list.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;PersonGroup&gt; object
     */
    public Observable<ServiceResponse<List<PersonGroup>>> listWithServiceResponseAsync(String start, Integer top) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.list(start, top, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<List<PersonGroup>>>>() {
                @Override
                public Observable<ServiceResponse<List<PersonGroup>>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<List<PersonGroup>> clientResponse = listDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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

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

    /**
     * Internal class implementing PersonGroupsListDefinition.
     */
    class PersonGroupsListParameters implements PersonGroupsListDefinition {
        private PersonGroupsImpl parent;
        private String start;
        private Integer top;

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

        @Override
        public PersonGroupsListParameters withStart(String start) {
            this.start = start;
            return this;
        }

        @Override
        public PersonGroupsListParameters withTop(Integer top) {
            this.top = top;
            return this;
        }

        @Override
        public List<PersonGroup> execute() {
        return listWithServiceResponseAsync(start, top).toBlocking().single().body();
    }

        @Override
        public Observable<List<PersonGroup>> executeAsync() {
            return listWithServiceResponseAsync(start, top).map(new Func1<ServiceResponse<List<PersonGroup>>, List<PersonGroup>>() {
                @Override
                public List<PersonGroup> call(ServiceResponse<List<PersonGroup>> response) {
                    return response.body();
                }
            });
        }
    }

    /**
     * Queue a person group training task, the training task may not be started immediately.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @throws APIErrorException thrown if the request is rejected by server
     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
     */
    public void train(String personGroupId) {
        trainWithServiceResponseAsync(personGroupId).toBlocking().single().body();
    }

    /**
     * Queue a person group training task, the training task may not be started immediately.
     *
     * @param personGroupId Id referencing a particular person group.
     * @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<Void> trainAsync(String personGroupId, final ServiceCallback<Void> serviceCallback) {
        return ServiceFuture.fromResponse(trainWithServiceResponseAsync(personGroupId), serviceCallback);
    }

    /**
     * Queue a person group training task, the training task may not be started immediately.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<Void> trainAsync(String personGroupId) {
        return trainWithServiceResponseAsync(personGroupId).map(new Func1<ServiceResponse<Void>, Void>() {
            @Override
            public Void call(ServiceResponse<Void> response) {
                return response.body();
            }
        });
    }

    /**
     * Queue a person group training task, the training task may not be started immediately.
     *
     * @param personGroupId Id referencing a particular person group.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the {@link ServiceResponse} object if successful.
     */
    public Observable<ServiceResponse<Void>> trainWithServiceResponseAsync(String personGroupId) {
        if (this.client.azureRegion() == null) {
            throw new IllegalArgumentException("Parameter this.client.azureRegion() is required and cannot be null.");
        }
        if (personGroupId == null) {
            throw new IllegalArgumentException("Parameter personGroupId is required and cannot be null.");
        }
        String parameterizedHost = Joiner.on(", ").join("{AzureRegion}", this.client.azureRegion());
        return service.train(personGroupId, this.client.acceptLanguage(), parameterizedHost, this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Void>>>() {
                @Override
                public Observable<ServiceResponse<Void>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Void> clientResponse = trainDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    private ServiceResponse<Void> trainDelegate(Response<ResponseBody> response) throws APIErrorException, IOException, IllegalArgumentException {
        return this.client.restClient().responseBuilderFactory().<Void, APIErrorException>newInstance(this.client.serializerAdapter())
                .register(202, new TypeToken<Void>() { }.getType())
                .registerError(APIErrorException.class)
                .build(response);
    }

}
