/**
   * Reserved for internal use. Populates the blob from an XMLStreamReader, reader must be at Start
   * element of Blob
   *
   * @param xmlr the XMLStreamReader to read from
   * @param serviceClient the CloudBlobClient associated with the objects.
   * @throws XMLStreamException if there is an error parsing the stream
   * @throws ParseException if there is an error in parsing a date
   * @throws URISyntaxException if the uri is invalid
   * @throws StorageException
   */
  protected static CloudBlob readBlob(
      final XMLStreamReader xmlr,
      final CloudBlobClient serviceClient,
      final CloudBlobContainer container)
      throws XMLStreamException, ParseException, URISyntaxException, StorageException {
    xmlr.require(XMLStreamConstants.START_ELEMENT, null, BlobConstants.BLOB_ELEMENT);

    String blobName = Constants.EMPTY_STRING;

    String snapshotID = null;
    String urlString = null;
    HashMap<String, String> metadata = null;
    BlobProperties properties = null;
    CopyState copyState = null;

    int eventType = xmlr.getEventType();
    // check if there are more events in the input stream
    while (xmlr.hasNext()) {
      eventType = xmlr.next();
      final String name = xmlr.getName().toString();

      if (eventType == XMLStreamConstants.START_ELEMENT) {
        if (name.equals(Constants.URL_ELEMENT)) {
          urlString = Utility.readElementFromXMLReader(xmlr, Constants.URL_ELEMENT);
        } else if (name.equals(BlobConstants.SNAPSHOT_ELEMENT)) {
          snapshotID = Utility.readElementFromXMLReader(xmlr, BlobConstants.SNAPSHOT_ELEMENT);
        } else if (name.equals(Constants.NAME_ELEMENT)) {
          blobName = Utility.readElementFromXMLReader(xmlr, Constants.NAME_ELEMENT);
        } else if (name.equals(BlobConstants.PROPERTIES)) {
          properties = BlobDeserializationHelper.readBlobProperties(xmlr);
          xmlr.require(XMLStreamConstants.END_ELEMENT, null, BlobConstants.PROPERTIES);
        } else if (name.equals(Constants.METADATA_ELEMENT)) {
          metadata = DeserializationHelper.parseMetadateFromXML(xmlr);
          xmlr.require(XMLStreamConstants.END_ELEMENT, null, Constants.METADATA_ELEMENT);
        } else if (name.equals(Constants.COPY_ID_ELEMENT)) {
          if (copyState == null) {
            copyState = new CopyState();
          }
          copyState.setCopyId(Utility.readElementFromXMLReader(xmlr, Constants.COPY_ID_ELEMENT));
        } else if (name.equals(Constants.COPY_COMPLETION_TIME_ELEMENT)) {
          if (copyState == null) {
            copyState = new CopyState();
          }
          copyState.setCompletionTime(
              Utility.parseRFC1123DateFromStringInGMT(
                  Utility.readElementFromXMLReader(xmlr, Constants.COPY_COMPLETION_TIME_ELEMENT)));
        } else if (name.equals(Constants.COPY_STATUS_ELEMENT)) {
          if (copyState == null) {
            copyState = new CopyState();
          }
          copyState.setStatus(
              CopyStatus.parse(
                  Utility.readElementFromXMLReader(xmlr, Constants.COPY_STATUS_ELEMENT)));
        } else if (name.equals(Constants.COPY_SOURCE_ELEMENT)) {
          if (copyState == null) {
            copyState = new CopyState();
          }
          copyState.setSource(
              new URI(Utility.readElementFromXMLReader(xmlr, Constants.COPY_SOURCE_ELEMENT)));
        } else if (name.equals(Constants.COPY_PROGRESS_ELEMENT)) {
          if (copyState == null) {
            copyState = new CopyState();
          }

          final String tempString =
              Utility.readElementFromXMLReader(xmlr, Constants.COPY_PROGRESS_ELEMENT);
          String[] progressSequence = tempString.split("/");
          copyState.setBytesCopied(Long.parseLong(progressSequence[0]));
          copyState.setTotalBytes(Long.parseLong(progressSequence[1]));
        } else if (name.equals(Constants.COPY_STATUS_DESCRIPTION_ELEMENT)) {
          if (copyState == null) {
            copyState = new CopyState();
          }
          copyState.setStatusDescription(
              Utility.readElementFromXMLReader(xmlr, Constants.COPY_STATUS_DESCRIPTION_ELEMENT));
        }
      } else if (eventType == XMLStreamConstants.END_ELEMENT
          && name.equals(BlobConstants.BLOB_ELEMENT)) {
        break;
      }
    }

    xmlr.require(XMLStreamConstants.END_ELEMENT, null, BlobConstants.BLOB_ELEMENT);

    // Assemble and return
    if (properties != null) {
      CloudBlob retBlob = null;
      final int blobNameSectionIndex = urlString.lastIndexOf("/".concat(blobName));
      final URI baseUri = new URI(urlString.substring(0, blobNameSectionIndex + 1));
      String query = null;
      if (blobNameSectionIndex + 1 + blobName.length() < urlString.length()) {
        // Snapshot blob URI
        // example:http://<yourstorageaccount>.blob.core.windows.net/<yourcontainer>/<yourblobname>?snapshot=2009-12-03T15%3a26%3a19.4466877Z
        query = urlString.substring(blobNameSectionIndex + 1 + blobName.length() + 1);
      }

      final URI blobURI =
          new URI(
              baseUri.getScheme(),
              baseUri.getAuthority(),
              baseUri.getRawPath().concat(blobName),
              query,
              null);

      if (properties.getBlobType() == BlobType.BLOCK_BLOB) {
        retBlob = new CloudBlockBlob(blobURI, serviceClient, container);
      } else if (properties.getBlobType() == BlobType.PAGE_BLOB) {
        retBlob = new CloudPageBlob(blobURI, serviceClient, container);
      } else {
        throw new StorageException(
            StorageErrorCodeStrings.INVALID_XML_DOCUMENT,
            "The response received is invalid or improperly formatted.",
            Constants.HeaderConstants.HTTP_UNUSED_306,
            null,
            null);
      }

      retBlob.uri = blobURI;
      retBlob.snapshotID = snapshotID;
      retBlob.properties = properties;
      retBlob.metadata = metadata;
      retBlob.copyState = copyState;
      return retBlob;
    } else {
      throw new StorageException(
          StorageErrorCodeStrings.INVALID_XML_DOCUMENT,
          "The response received is invalid or improperly formatted.",
          Constants.HeaderConstants.HTTP_UNUSED_306,
          null,
          null);
    }
  }
  /**
   * Create a snapshot
   *
   * @throws StorageException
   * @throws URISyntaxException
   * @throws IOException
   * @throws InterruptedException
   */
  @Test
  public void testPageBlobSnapshotValidationTest()
      throws StorageException, URISyntaxException, IOException {
    final int length = 1024;
    CloudPageBlob blockBlobRef =
        (CloudPageBlob)
            BlobTestHelper.uploadNewBlob(
                this.container, BlobType.PAGE_BLOB, "originalBlob", length, null);
    final CloudBlob blobSnapshot = blockBlobRef.createSnapshot();

    for (ListBlobItem blob :
        this.container.listBlobs(null, true, EnumSet.allOf(BlobListingDetails.class), null, null)) {
      final ByteArrayOutputStream outStream = new ByteArrayOutputStream(length);
      ((CloudBlob) blob).download(outStream);
    }

    ByteArrayOutputStream outStream = new ByteArrayOutputStream(length);

    blobSnapshot.download(outStream);
    byte[] retrievedBuff = outStream.toByteArray();
    assertEquals(length, retrievedBuff.length);

    // Read operation should work fine.
    blobSnapshot.downloadAttributes();

    final CloudPageBlob blobSnapshotUsingRootUri =
        this.container.getPageBlobReference(blockBlobRef.getName(), blobSnapshot.getSnapshotID());
    outStream = new ByteArrayOutputStream(length);

    blobSnapshotUsingRootUri.download(outStream);
    retrievedBuff = outStream.toByteArray();
    assertEquals(length, retrievedBuff.length);
    assertEquals(blobSnapshot.getSnapshotID(), blobSnapshotUsingRootUri.getSnapshotID());

    // Expect an IllegalArgumentException from upload.
    try {
      final Random randGenerator = new Random();
      final byte[] buff = new byte[length];
      randGenerator.nextBytes(buff);
      blobSnapshot.upload(new ByteArrayInputStream(buff), -1);
      fail("Expect an IllegalArgumentException from upload");
    } catch (IllegalArgumentException e) {
      assertEquals(
          "Cannot perform this operation on a blob representing a snapshot.", e.getMessage());
    }

    // Expect an IllegalArgumentException from uploadMetadata.
    try {
      blobSnapshot.uploadMetadata();
      fail("Expect an IllegalArgumentException from uploadMetadata");
    } catch (IllegalArgumentException e) {
      assertEquals(
          "Cannot perform this operation on a blob representing a snapshot.", e.getMessage());
    }

    // Expect an IllegalArgumentException from uploadProperties.
    try {
      blobSnapshot.uploadProperties();
      fail("Expect an IllegalArgumentException from uploadProperties");
    } catch (IllegalArgumentException e) {
      assertEquals(
          "Cannot perform this operation on a blob representing a snapshot.", e.getMessage());
    }

    // Expect an IllegalArgumentException from createSnapshot.
    try {
      blobSnapshot.createSnapshot();
      fail("Expect an IllegalArgumentException from createSnapshot");
    } catch (IllegalArgumentException e) {
      assertEquals(
          "Cannot perform this operation on a blob representing a snapshot.", e.getMessage());
    }
  }