/**
   * Creates a {@link Builder} for executing a bulk {@code DELETE} request, and wrap the
   * X-result-count header as a integer response.
   *
   * @param apiKey the authorization token for accessing the EVRYTHNG API
   * @param uri the {@link URI} holding the absolute URL
   * @param responseStatus the expected {@link HttpResponse} status
   * @return an EVRYTHNG API-ready {@link Builder}
   */
  public static Builder<Long> deleteMultiple(
      final String apiKey, final URI uri, final Status responseStatus) {

    return new CheckedBuilder<Long>(
        apiKey, HttpMethodBuilder.httpDelete(), uri, responseStatus, new TypeReference<Long>() {}) {

      @Override
      public Long execute() throws EvrythngException {
        // Perform request (response status code will be automatically checked):
        HttpResponse response = request();
        Header header = response.getFirstHeader(ApiConfiguration.HTTP_HEADER_RESULT_COUNT);
        Long result = null;
        if (header != null) {
          try {
            result = Long.parseLong(header.getValue());
          } catch (NumberFormatException ex) {
            logger.warn(
                "Invalid numeric value in header {} : {}",
                ApiConfiguration.HTTP_HEADER_RESULT_COUNT,
                header.getValue());
          }
        }
        return result;
      }
    };
  }
  public static Builder<AcceptedResourceResponse> postAsynchronously(
      final String apiKey, final URI uri, final Object data, final Pattern extractor) {

    return new CheckedBuilder<AcceptedResourceResponse>(
        apiKey,
        HttpMethodBuilder.httpPost(data),
        uri,
        Status.ACCEPTED,
        new TypeReference<AcceptedResourceResponse>() {}) {

      @Override
      public AcceptedResourceResponse execute() throws EvrythngException {
        // Perform request (response status code will be automatically checked):
        HttpResponse response = request();
        String location = null;
        Header header = response.getFirstHeader("location");
        String id = null;
        if (header != null) {
          location = header.getValue();
          if (location != null) {
            Matcher match = extractor.matcher(location);
            if (match.matches() && match.groupCount() > 0) {
              id = match.group(1);
            }
          }
        }
        return new AcceptedResourceResponse(id, location);
      }
    };
  }
  static <T> IteratorBuilder<T> iterate(
      final String apiKey,
      final URI uri,
      final Status responseStatus,
      final TypeReference<List<T>> pageType) {

    return new IteratorBuilder<>(
        apiKey, HttpMethodBuilder.httpGet(), uri, responseStatus, pageType);
  }
  /**
   * Creates a {@link Builder} for executing a {@code GET} request.
   *
   * @param apiKey the authorization token for accessing the EVRYTHNG API
   * @param uri the {@link URI} holding the absolute URL
   * @param responseStatus the expected {@link HttpResponse} status
   * @param returnType the native type to which the {@link HttpResponse} will be mapped to
   * @return an EVRYTHNG API-ready {@link Builder}
   */
  public static <T> Builder<T> get(
      final String apiKey,
      final URI uri,
      final Status responseStatus,
      final TypeReference<T> returnType) {

    return new CheckedBuilder<>(
        apiKey, HttpMethodBuilder.httpGet(), uri, responseStatus, returnType);
  }
  /**
   * Creates a {@link CheckedBuilder} for executing a {@code POST} request.
   *
   * @param apiKey the authorization token for accessing the EVRYTHNG API
   * @param uri the {@link URI} holding the absolute URL
   * @param data the content data that will be associated with the POST request
   * @param responseStatus the expected {@link HttpResponse} status
   * @param responseType the native type to which the {@link HttpResponse} will be mapped to
   * @return an EVRYTHNG API-ready {@link CheckedBuilder}
   */
  public static <T> Builder<T> post(
      final String apiKey,
      final URI uri,
      final Object data,
      final Status responseStatus,
      final TypeReference<T> responseType) {

    return new CheckedBuilder<>(
        apiKey, HttpMethodBuilder.httpPost(data), uri, responseStatus, responseType);
  }
  /**
   * Creates a {@link CheckedBuilder} for executing a file upload via a {@code PUT} request.
   *
   * @param apiKey the authorization token for accessing the EVRYTHNG API
   * @param uri the {@link URI} holding the absolute URL
   * @param file file
   * @param responseStatus the expected response {@link Status}
   * @param responseType the native type to which the {@link HttpResponse} will be mapped to
   * @return an EVRYTHNG API-ready {@link CheckedBuilder}
   */
  public static <T> Builder<T> putMultipart(
      final String apiKey,
      final URI uri,
      final File file,
      final Status responseStatus,
      final TypeReference<T> responseType) {

    return new CheckedBuilder<>(
        apiKey, HttpMethodBuilder.httpPutMultipart(file), uri, responseStatus, responseType, null);
  }
  /**
   * Creates a {@link Builder} for executing a {@code DELETE} request.
   *
   * @param apiKey the authorization token for accessing the EVRYTHNG API
   * @param uri the {@link URI} holding the absolute URL
   * @param responseStatus the expected {@link HttpResponse} status
   * @return an EVRYTHNG API-ready {@link Builder}
   */
  public static Builder<Boolean> delete(
      final String apiKey, final URI uri, final Status responseStatus) {

    return new CheckedBuilder<Boolean>(
        apiKey,
        HttpMethodBuilder.httpDelete(),
        uri,
        responseStatus,
        new TypeReference<Boolean>() {}) {

      /**
       * {@code true} if the request has been successfully executed (i.e. returned response status
       * code equals {@link Status#OK}), {@code false} otherwise
       */
      @Override
      public Boolean execute() throws EvrythngException {
        // Perform request (response status code will be automatically checked):
        return request() != null;
      }
    };
  }