/**
 * 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.applicationinsights.query.implementation;

import retrofit2.Retrofit;
import com.microsoft.azure.applicationinsights.query.Metrics;
import com.google.common.reflect.TypeToken;
import com.microsoft.azure.applicationinsights.query.models.ErrorResponseException;
import com.microsoft.azure.applicationinsights.query.models.MetricId;
import com.microsoft.azure.applicationinsights.query.models.MetricsAggregation;
import com.microsoft.azure.applicationinsights.query.models.MetricsPostBodySchema;
import com.microsoft.azure.applicationinsights.query.models.MetricsResult;
import com.microsoft.azure.applicationinsights.query.models.MetricsResultsItem;
import com.microsoft.azure.applicationinsights.query.models.MetricsSegment;
import com.microsoft.rest.CollectionFormat;
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 okhttp3.ResponseBody;
import org.joda.time.Period;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.Path;
import retrofit2.http.POST;
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 Metrics.
 */
public class MetricsImpl implements Metrics {
    /** The Retrofit service to perform REST calls. */
    private MetricsService service;
    /** The service client containing this operation class. */
    private ApplicationInsightsDataClientImpl client;

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

    /**
     * The interface defining all the services for Metrics to be
     * used by Retrofit to perform actually REST calls.
     */
    interface MetricsService {
        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.applicationinsights.query.Metrics get" })
        @GET("apps/{appId}/metrics/{metricId}")
        Observable<Response<ResponseBody>> get(@Path("appId") String appId, @Path("metricId") MetricId metricId1, @Query("timespan") String timespan, @Query("interval") Period interval, @Query("aggregation") String aggregation, @Query("segment") String segment, @Query("top") Integer top, @Query("orderby") String orderby, @Query("filter") String filter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.applicationinsights.query.Metrics getMultiple" })
        @POST("apps/{appId}/metrics")
        Observable<Response<ResponseBody>> getMultiple(@Path("appId") String appId, @Body List<MetricsPostBodySchema> body, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent);

        @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.applicationinsights.query.Metrics getMetadata" })
        @GET("apps/{appId}/metrics/metadata")
        Observable<Response<ResponseBody>> getMetadata(@Path("appId") String appId, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent);

    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @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 MetricsResult object if successful.
     */
    public MetricsResult get(String appId, MetricId metricId) {
        return getWithServiceResponseAsync(appId, metricId).toBlocking().single().body();
    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @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<MetricsResult> getAsync(String appId, MetricId metricId, final ServiceCallback<MetricsResult> serviceCallback) {
        return ServiceFuture.fromResponse(getWithServiceResponseAsync(appId, metricId), serviceCallback);
    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the MetricsResult object
     */
    public Observable<MetricsResult> getAsync(String appId, MetricId metricId) {
        return getWithServiceResponseAsync(appId, metricId).map(new Func1<ServiceResponse<MetricsResult>, MetricsResult>() {
            @Override
            public MetricsResult call(ServiceResponse<MetricsResult> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the MetricsResult object
     */
    public Observable<ServiceResponse<MetricsResult>> getWithServiceResponseAsync(String appId, MetricId metricId) {
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (metricId == null) {
            throw new IllegalArgumentException("Parameter metricId is required and cannot be null.");
        }
        final String timespan = null;
        final Period interval = null;
        final List<MetricsAggregation> aggregation = null;
        final List<MetricsSegment> segment = null;
        final Integer top = null;
        final String orderby = null;
        final String filter = null;
        String aggregationConverted = this.client.serializerAdapter().serializeList(aggregation, CollectionFormat.CSV);String segmentConverted = this.client.serializerAdapter().serializeList(segment, CollectionFormat.CSV);
        return service.get(appId, metricId, timespan, interval, aggregationConverted, segmentConverted, top, orderby, filter, this.client.acceptLanguage(), this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<MetricsResult>>>() {
                @Override
                public Observable<ServiceResponse<MetricsResult>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<MetricsResult> clientResponse = getDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @param timespan The timespan over which to retrieve metric values. This is an ISO8601 time period value. If timespan is omitted, a default time range of `PT12H` ("last 12 hours") is used. The actual timespan that is queried may be adjusted by the server based. In all cases, the actual time span used for the query is included in the response.
     * @param interval The time interval to use when retrieving metric values. This is an ISO8601 duration. If interval is omitted, the metric value is aggregated across the entire timespan. If interval is supplied, the server may adjust the interval to a more appropriate size based on the timespan used for the query. In all cases, the actual interval used for the query is included in the response.
     * @param aggregation The aggregation to use when computing the metric values. To retrieve more than one aggregation at a time, separate them with a comma. If no aggregation is specified, then the default aggregation for the metric is used.
     * @param segment The name of the dimension to segment the metric values by. This dimension must be applicable to the metric you are retrieving. To segment by more than one dimension at a time, separate them with a comma (,). In this case, the metric data will be segmented in the order the dimensions are listed in the parameter.
     * @param top The number of segments to return.  This value is only valid when segment is specified.
     * @param orderby The aggregation function and direction to sort the segments by.  This value is only valid when segment is specified.
     * @param filter An expression used to filter the results.  This value should be a valid OData filter expression where the keys of each clause should be applicable dimensions for the metric you are retrieving.
     * @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 MetricsResult object if successful.
     */
    public MetricsResult get(String appId, MetricId metricId, String timespan, Period interval, List<MetricsAggregation> aggregation, List<MetricsSegment> segment, Integer top, String orderby, String filter) {
        return getWithServiceResponseAsync(appId, metricId, timespan, interval, aggregation, segment, top, orderby, filter).toBlocking().single().body();
    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @param timespan The timespan over which to retrieve metric values. This is an ISO8601 time period value. If timespan is omitted, a default time range of `PT12H` ("last 12 hours") is used. The actual timespan that is queried may be adjusted by the server based. In all cases, the actual time span used for the query is included in the response.
     * @param interval The time interval to use when retrieving metric values. This is an ISO8601 duration. If interval is omitted, the metric value is aggregated across the entire timespan. If interval is supplied, the server may adjust the interval to a more appropriate size based on the timespan used for the query. In all cases, the actual interval used for the query is included in the response.
     * @param aggregation The aggregation to use when computing the metric values. To retrieve more than one aggregation at a time, separate them with a comma. If no aggregation is specified, then the default aggregation for the metric is used.
     * @param segment The name of the dimension to segment the metric values by. This dimension must be applicable to the metric you are retrieving. To segment by more than one dimension at a time, separate them with a comma (,). In this case, the metric data will be segmented in the order the dimensions are listed in the parameter.
     * @param top The number of segments to return.  This value is only valid when segment is specified.
     * @param orderby The aggregation function and direction to sort the segments by.  This value is only valid when segment is specified.
     * @param filter An expression used to filter the results.  This value should be a valid OData filter expression where the keys of each clause should be applicable dimensions for the metric you are retrieving.
     * @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<MetricsResult> getAsync(String appId, MetricId metricId, String timespan, Period interval, List<MetricsAggregation> aggregation, List<MetricsSegment> segment, Integer top, String orderby, String filter, final ServiceCallback<MetricsResult> serviceCallback) {
        return ServiceFuture.fromResponse(getWithServiceResponseAsync(appId, metricId, timespan, interval, aggregation, segment, top, orderby, filter), serviceCallback);
    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @param timespan The timespan over which to retrieve metric values. This is an ISO8601 time period value. If timespan is omitted, a default time range of `PT12H` ("last 12 hours") is used. The actual timespan that is queried may be adjusted by the server based. In all cases, the actual time span used for the query is included in the response.
     * @param interval The time interval to use when retrieving metric values. This is an ISO8601 duration. If interval is omitted, the metric value is aggregated across the entire timespan. If interval is supplied, the server may adjust the interval to a more appropriate size based on the timespan used for the query. In all cases, the actual interval used for the query is included in the response.
     * @param aggregation The aggregation to use when computing the metric values. To retrieve more than one aggregation at a time, separate them with a comma. If no aggregation is specified, then the default aggregation for the metric is used.
     * @param segment The name of the dimension to segment the metric values by. This dimension must be applicable to the metric you are retrieving. To segment by more than one dimension at a time, separate them with a comma (,). In this case, the metric data will be segmented in the order the dimensions are listed in the parameter.
     * @param top The number of segments to return.  This value is only valid when segment is specified.
     * @param orderby The aggregation function and direction to sort the segments by.  This value is only valid when segment is specified.
     * @param filter An expression used to filter the results.  This value should be a valid OData filter expression where the keys of each clause should be applicable dimensions for the metric you are retrieving.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the MetricsResult object
     */
    public Observable<MetricsResult> getAsync(String appId, MetricId metricId, String timespan, Period interval, List<MetricsAggregation> aggregation, List<MetricsSegment> segment, Integer top, String orderby, String filter) {
        return getWithServiceResponseAsync(appId, metricId, timespan, interval, aggregation, segment, top, orderby, filter).map(new Func1<ServiceResponse<MetricsResult>, MetricsResult>() {
            @Override
            public MetricsResult call(ServiceResponse<MetricsResult> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve metric data.
     * Gets metric values for a single metric.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param metricId ID of the metric. This is either a standard AI metric, or an application-specific custom metric. Possible values include: 'requests/count', 'requests/duration', 'requests/failed', 'users/count', 'users/authenticated', 'pageViews/count', 'pageViews/duration', 'client/processingDuration', 'client/receiveDuration', 'client/networkDuration', 'client/sendDuration', 'client/totalDuration', 'dependencies/count', 'dependencies/failed', 'dependencies/duration', 'exceptions/count', 'exceptions/browser', 'exceptions/server', 'sessions/count', 'performanceCounters/requestExecutionTime', 'performanceCounters/requestsPerSecond', 'performanceCounters/requestsInQueue', 'performanceCounters/memoryAvailableBytes', 'performanceCounters/exceptionsPerSecond', 'performanceCounters/processCpuPercentage', 'performanceCounters/processIOBytesPerSecond', 'performanceCounters/processPrivateBytes', 'performanceCounters/processorCpuPercentage', 'availabilityResults/availabilityPercentage', 'availabilityResults/duration', 'billing/telemetryCount', 'customEvents/count'
     * @param timespan The timespan over which to retrieve metric values. This is an ISO8601 time period value. If timespan is omitted, a default time range of `PT12H` ("last 12 hours") is used. The actual timespan that is queried may be adjusted by the server based. In all cases, the actual time span used for the query is included in the response.
     * @param interval The time interval to use when retrieving metric values. This is an ISO8601 duration. If interval is omitted, the metric value is aggregated across the entire timespan. If interval is supplied, the server may adjust the interval to a more appropriate size based on the timespan used for the query. In all cases, the actual interval used for the query is included in the response.
     * @param aggregation The aggregation to use when computing the metric values. To retrieve more than one aggregation at a time, separate them with a comma. If no aggregation is specified, then the default aggregation for the metric is used.
     * @param segment The name of the dimension to segment the metric values by. This dimension must be applicable to the metric you are retrieving. To segment by more than one dimension at a time, separate them with a comma (,). In this case, the metric data will be segmented in the order the dimensions are listed in the parameter.
     * @param top The number of segments to return.  This value is only valid when segment is specified.
     * @param orderby The aggregation function and direction to sort the segments by.  This value is only valid when segment is specified.
     * @param filter An expression used to filter the results.  This value should be a valid OData filter expression where the keys of each clause should be applicable dimensions for the metric you are retrieving.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the MetricsResult object
     */
    public Observable<ServiceResponse<MetricsResult>> getWithServiceResponseAsync(String appId, MetricId metricId, String timespan, Period interval, List<MetricsAggregation> aggregation, List<MetricsSegment> segment, Integer top, String orderby, String filter) {
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (metricId == null) {
            throw new IllegalArgumentException("Parameter metricId is required and cannot be null.");
        }
        Validator.validate(aggregation);
        Validator.validate(segment);
        String aggregationConverted = this.client.serializerAdapter().serializeList(aggregation, CollectionFormat.CSV);String segmentConverted = this.client.serializerAdapter().serializeList(segment, CollectionFormat.CSV);
        return service.get(appId, metricId, timespan, interval, aggregationConverted, segmentConverted, top, orderby, filter, this.client.acceptLanguage(), this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<MetricsResult>>>() {
                @Override
                public Observable<ServiceResponse<MetricsResult>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<MetricsResult> clientResponse = getDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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

    /**
     * Retrieve metric data.
     * Gets metric values for multiple metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param body The batched metrics query.
     * @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;MetricsResultsItem&gt; object if successful.
     */
    public List<MetricsResultsItem> getMultiple(String appId, List<MetricsPostBodySchema> body) {
        return getMultipleWithServiceResponseAsync(appId, body).toBlocking().single().body();
    }

    /**
     * Retrieve metric data.
     * Gets metric values for multiple metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param body The batched metrics query.
     * @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<MetricsResultsItem>> getMultipleAsync(String appId, List<MetricsPostBodySchema> body, final ServiceCallback<List<MetricsResultsItem>> serviceCallback) {
        return ServiceFuture.fromResponse(getMultipleWithServiceResponseAsync(appId, body), serviceCallback);
    }

    /**
     * Retrieve metric data.
     * Gets metric values for multiple metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param body The batched metrics query.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;MetricsResultsItem&gt; object
     */
    public Observable<List<MetricsResultsItem>> getMultipleAsync(String appId, List<MetricsPostBodySchema> body) {
        return getMultipleWithServiceResponseAsync(appId, body).map(new Func1<ServiceResponse<List<MetricsResultsItem>>, List<MetricsResultsItem>>() {
            @Override
            public List<MetricsResultsItem> call(ServiceResponse<List<MetricsResultsItem>> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve metric data.
     * Gets metric values for multiple metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @param body The batched metrics query.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the List&lt;MetricsResultsItem&gt; object
     */
    public Observable<ServiceResponse<List<MetricsResultsItem>>> getMultipleWithServiceResponseAsync(String appId, List<MetricsPostBodySchema> body) {
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        if (body == null) {
            throw new IllegalArgumentException("Parameter body is required and cannot be null.");
        }
        Validator.validate(body);
        return service.getMultiple(appId, body, this.client.acceptLanguage(), this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<List<MetricsResultsItem>>>>() {
                @Override
                public Observable<ServiceResponse<List<MetricsResultsItem>>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<List<MetricsResultsItem>> clientResponse = getMultipleDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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

    /**
     * Retrieve metric metatadata.
     * Gets metadata describing the available metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @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 Object object if successful.
     */
    public Object getMetadata(String appId) {
        return getMetadataWithServiceResponseAsync(appId).toBlocking().single().body();
    }

    /**
     * Retrieve metric metatadata.
     * Gets metadata describing the available metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @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<Object> getMetadataAsync(String appId, final ServiceCallback<Object> serviceCallback) {
        return ServiceFuture.fromResponse(getMetadataWithServiceResponseAsync(appId), serviceCallback);
    }

    /**
     * Retrieve metric metatadata.
     * Gets metadata describing the available metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the Object object
     */
    public Observable<Object> getMetadataAsync(String appId) {
        return getMetadataWithServiceResponseAsync(appId).map(new Func1<ServiceResponse<Object>, Object>() {
            @Override
            public Object call(ServiceResponse<Object> response) {
                return response.body();
            }
        });
    }

    /**
     * Retrieve metric metatadata.
     * Gets metadata describing the available metrics.
     *
     * @param appId ID of the application. This is Application ID from the API Access settings blade in the Azure portal.
     * @throws IllegalArgumentException thrown if parameters fail the validation
     * @return the observable to the Object object
     */
    public Observable<ServiceResponse<Object>> getMetadataWithServiceResponseAsync(String appId) {
        if (appId == null) {
            throw new IllegalArgumentException("Parameter appId is required and cannot be null.");
        }
        return service.getMetadata(appId, this.client.acceptLanguage(), this.client.userAgent())
            .flatMap(new Func1<Response<ResponseBody>, Observable<ServiceResponse<Object>>>() {
                @Override
                public Observable<ServiceResponse<Object>> call(Response<ResponseBody> response) {
                    try {
                        ServiceResponse<Object> clientResponse = getMetadataDelegate(response);
                        return Observable.just(clientResponse);
                    } catch (Throwable t) {
                        return Observable.error(t);
                    }
                }
            });
    }

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

}
