/**
   * Constructs a HttpURLConnection to upload a block. Sign with page length for update, or 0 for
   * clear.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param properties the page properties
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection putPage(
      final URI uri,
      final int timeout,
      final PageProperties properties,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws IOException, URISyntaxException, StorageException {
    final UriQueryBuilder builder = new UriQueryBuilder();
    builder.add("comp", "page");

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);

    request.setDoOutput(true);
    request.setRequestMethod("PUT");

    if (properties.getPageOperation() == PageOperationType.CLEAR) {
      request.setFixedLengthStreamingMode(0);
    }

    // Page write is either update or clean; required
    request.setRequestProperty(BlobConstants.PAGE_WRITE, properties.getPageOperation().toString());
    request.setRequestProperty(
        Constants.HeaderConstants.STORAGE_RANGE_HEADER, properties.getRange().toString());

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    return request;
  }
  /**
   * Constructs a HttpURLConnection to return a list of the block blobs blocks. Sign with no length
   * specified.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param snapshotVersion The snapshot version, if the blob is a snapshot.
   * @param blockFilter The types of blocks to include in the list: committed, uncommitted, or both.
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection getBlockList(
      final URI uri,
      final int timeout,
      final String snapshotVersion,
      final BlockListingFilter blockFilter,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws StorageException, IOException, URISyntaxException {

    final UriQueryBuilder builder = new UriQueryBuilder();

    builder.add("comp", "blocklist");
    builder.add("blocklisttype", blockFilter.toString());
    BaseRequest.addSnapshot(builder, snapshotVersion);

    final HttpURLConnection request =
        BaseRequest.createURLConnection(uri, timeout, builder, opContext);
    request.setRequestMethod("GET");

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    return request;
  }
  /**
   * Constructs a HttpURLConnection to set the blob's properties, Sign with zero length specified.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection putBlockList(
      final URI uri,
      final int timeout,
      final BlobProperties properties,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws IOException, URISyntaxException, StorageException {

    final UriQueryBuilder builder = new UriQueryBuilder();
    builder.add("comp", "blocklist");

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);

    request.setDoOutput(true);
    request.setRequestMethod("PUT");

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    BaseRequest.addOptionalHeader(
        request, Constants.HeaderConstants.CACHE_CONTROL_HEADER, properties.getCacheControl());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.CONTENT_ENCODING_HEADER, properties.getContentEncoding());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.CONTENT_LANGUAGE_HEADER, properties.getContentLanguage());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.BLOB_CONTENT_MD5_HEADER, properties.getContentMD5());
    BaseRequest.addOptionalHeader(
        request, BlobConstants.CONTENT_TYPE_HEADER, properties.getContentType());

    return request;
  }
  /**
   * Generates a web request to abort a copy operation.
   *
   * @param uri The absolute URI to the container.
   * @param timeout The server timeout interval.
   * @param copyId A <code>String</code> object that identifying the copy operation.
   * @param accessCondition The access condition to apply to the request. Only lease conditions are
   *     supported for this operation.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection configured for the operation.
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   * @throws IOException
   * @throws URISyntaxException
   */
  public static HttpURLConnection abortCopy(
      final URI uri,
      final int timeout,
      final String copyId,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws StorageException, IOException, URISyntaxException {

    final UriQueryBuilder builder = new UriQueryBuilder();

    builder.add("comp", "copy");
    builder.add("copyid", copyId);

    final HttpURLConnection request =
        BaseRequest.createURLConnection(uri, timeout, builder, opContext);

    request.setFixedLengthStreamingMode(0);
    request.setDoOutput(true);
    request.setRequestMethod("PUT");

    request.setRequestProperty("x-ms-copy-action", "abort");

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request, true);
    }

    return request;
  }
  /**
   * Constructs a HttpURLConnection to create a snapshot of the blob. Sign with 0 length.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection snapshot(
      final URI uri,
      final int timeout,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws IOException, URISyntaxException, StorageException {
    final UriQueryBuilder builder = new UriQueryBuilder();
    builder.add(Constants.HeaderConstants.COMP, BlobConstants.SNAPSHOT);
    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);

    request.setFixedLengthStreamingMode(0);
    request.setDoOutput(true);
    request.setRequestMethod("PUT");

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    return request;
  }
  /**
   * Constructs a HttpURLConnection to Acquire,Release,Break, or Renew a blob lease. Sign with 0
   * length.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param action the LeaseAction to perform
   * @param visibilityTimeoutInSeconds Specifies the the span of time for which to acquire the
   *     lease, in seconds. If null, an infinite lease will be acquired. If not null, this must be
   *     greater than zero.
   * @param proposedLeaseId A <code>String</code> that represents the proposed lease ID for the new
   *     lease, or null if no lease ID is proposed.
   * @param breakPeriodInSeconds Specifies the amount of time to allow the lease to remain, in
   *     seconds. If null, the break period is the remainder of the current lease, or zero for
   *     infinite leases.
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection lease(
      final URI uri,
      final int timeout,
      final LeaseAction action,
      final Integer leaseTimeInSeconds,
      final String proposedLeaseId,
      final Integer breakPeriodInSeconds,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws IOException, URISyntaxException, StorageException {

    final UriQueryBuilder builder = new UriQueryBuilder();
    builder.add("comp", "lease");

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);

    request.setDoOutput(true);
    request.setRequestMethod("PUT");
    request.setFixedLengthStreamingMode(0);
    request.setRequestProperty("x-ms-lease-action", action.toString());

    if (leaseTimeInSeconds != null) {
      request.setRequestProperty("x-ms-lease-duration", leaseTimeInSeconds.toString());
    } else {
      request.setRequestProperty("x-ms-lease-duration", "-1");
    }

    if (proposedLeaseId != null) {
      request.setRequestProperty("x-ms-proposed-lease-id", proposedLeaseId);
    }

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }
    return request;
  }
  /**
   * Constructs a HttpURLConnection to upload a block. Sign with length of block data.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param blockId the Base64 ID for the block
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection putBlock(
      final URI uri,
      final int timeout,
      final String blockId,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws IOException, URISyntaxException, StorageException {
    final UriQueryBuilder builder = new UriQueryBuilder();
    builder.add("comp", "block");
    builder.add("blockid", blockId);

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);

    request.setDoOutput(true);
    request.setRequestMethod("PUT");

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    return request;
  }
  /**
   * Constructs a HttpURLConnection to return a list of the PageBlob's page ranges. Sign with no
   * length specified.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param snapshotVersion The snapshot version, if the blob is a snapshot.
   * @param accessCondition An {@link AccessCondition} object that represents the access conditions
   *     for the blob.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection to use to perform the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection getPageRanges(
      final URI uri,
      final int timeout,
      final String snapshotVersion,
      final AccessCondition accessCondition,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws StorageException, IOException, URISyntaxException {

    final UriQueryBuilder builder = new UriQueryBuilder();
    builder.add("comp", "pagelist");
    BaseRequest.addSnapshot(builder, snapshotVersion);

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);
    request.setRequestMethod("GET");

    if (accessCondition != null) {
      accessCondition.applyConditionToRequest(request);
    }

    BaseRequest.addOptionalHeader(request, BlobConstants.SNAPSHOT, snapshotVersion);
    return request;
  }
  /**
   * Constructs a HttpURLConnection to list blobs. Sign with no length specified.
   *
   * @param uri The absolute URI to the blob
   * @param timeout The server timeout interval
   * @param listingContext A set of parameters for the listing operation.
   * @param blobOptions the options to use for the request.
   * @param opContext a tracking object for the request
   * @return a HttpURLConnection configured for the operation.
   * @throws IOException if there is an error opening the connection
   * @throws URISyntaxException if the resource URI is invalid
   * @throws StorageException an exception representing any error which occurred during the
   *     operation.
   * @throws IllegalArgumentException
   */
  public static HttpURLConnection list(
      final URI uri,
      final int timeout,
      final BlobListingContext listingContext,
      final BlobRequestOptions blobOptions,
      final OperationContext opContext)
      throws URISyntaxException, IOException, StorageException {

    final UriQueryBuilder builder = ContainerRequest.getContainerUriQueryBuilder();
    builder.add("comp", "list");

    if (listingContext != null) {
      if (!Utility.isNullOrEmpty(listingContext.getPrefix())) {
        builder.add("prefix", listingContext.getPrefix());
      }

      if (!Utility.isNullOrEmpty(listingContext.getDelimiter())) {
        builder.add("delimiter", listingContext.getDelimiter());
      }

      if (!Utility.isNullOrEmpty(listingContext.getMarker())) {
        builder.add("marker", listingContext.getMarker());
      }

      if (listingContext.getMaxResults() != null && listingContext.getMaxResults() > 0) {
        builder.add("maxresults", listingContext.getMaxResults().toString());
      }

      if (listingContext.getListingDetails().size() > 0) {
        final StringBuilder sb = new StringBuilder();

        boolean started = false;

        if (listingContext.getListingDetails().contains(BlobListingDetails.SNAPSHOTS)) {
          if (!started) {
            started = true;
          } else {
            sb.append(",");
          }

          sb.append("snapshots");
        }

        if (listingContext.getListingDetails().contains(BlobListingDetails.UNCOMMITTED_BLOBS)) {
          if (!started) {
            started = true;
          } else {
            sb.append(",");
          }

          sb.append("uncommittedblobs");
        }

        if (listingContext.getListingDetails().contains(BlobListingDetails.METADATA)) {
          if (!started) {
            started = true;
          } else {
            sb.append(",");
          }

          sb.append("metadata");
        }

        builder.add("include", sb.toString());
      }
    }

    final HttpURLConnection request =
        BlobRequest.createURLConnection(uri, timeout, builder, blobOptions, opContext);

    request.setRequestMethod("GET");

    return request;
  }