/**
   * <br>
   * This function performs following checks on allPartitionRegion and bucket2Node region of
   * Partition Region</br><br>
   * 1. allPartitionRegion should not be null</br><br>
   * 2. Size of allPartitionRegion should be no. of regions + 1.</br><br>
   * 3. Bucket2Node should not be null and size should = no. of regions</br> <br>
   * 4. Name of the Bucket2Node should be PartitionedRegionHelper.BUCKET_2_NODE_TABLE_PREFIX +
   * pr.getName().</br>
   */
  private void validateMultiplePartitionedRegions(
      VM vm0, VM vm1, VM vm2, VM vm3, int startIndexForRegion, int endIndexForRegion)
      throws Throwable {
    int AsyncInvocationArrSize = 4;
    AsyncInvocation[] async = new AsyncInvocation[AsyncInvocationArrSize];
    async[0] =
        vm0.invokeAsync(
            validateMultiplePartitionRegion(prPrefix, startIndexForRegion, endIndexForRegion));
    async[1] =
        vm1.invokeAsync(
            validateMultiplePartitionRegion(prPrefix, startIndexForRegion, endIndexForRegion));
    async[2] =
        vm2.invokeAsync(
            validateMultiplePartitionRegion(prPrefix, startIndexForRegion, endIndexForRegion));
    async[3] =
        vm3.invokeAsync(
            validateMultiplePartitionRegion(prPrefix, startIndexForRegion, endIndexForRegion));

    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      DistributedTestCase.join(async[count], 30 * 1000, getLogWriter());
    }

    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      if (async[count].exceptionOccurred()) {
        fail("exception during " + count, async[count].getException());
      }
    }
  }
  /**
   * This test performs following operations: <br>
   * 1. Create multiple Partition Regions in 4 VMs</br><br>
   * 2. Performs put()operations on all the partitioned region from all the VM's </br><br>
   * 3. Performs destroy(key)operations for some of the keys of all the partitioned region from all
   * the VM's</br><br>
   * 4. Chekcs containsKey and ContainsValueForKey APIs</br>
   */
  public void testPartitionedRegionDestroyAndContainsAPI() throws Throwable {
    Host host = Host.getHost(0);
    VM vm0 = host.getVM(0);
    VM vm1 = host.getVM(1);
    VM vm2 = host.getVM(2);
    VM vm3 = host.getVM(3);
    prPrefix = "testPartitionedRegionDestroyAndContainsAPI";
    int startIndexForRegion = 0;
    int endIndexForRegion = MAX_REGIONS;
    int AsyncInvocationArrSize = 4;
    AsyncInvocation[] async = new AsyncInvocation[AsyncInvocationArrSize];

    /** creating Partition Regions and testing for the APIs contains() */
    createMultiplePartitionRegion(vm0, vm1, vm2, vm3, startIndexForRegion, endIndexForRegion);
    getLogWriter()
        .info(
            "testPartitionedRegionDestroyAndContainsAPI() - Partition Regions Successfully Created ");
    validateMultiplePartitionedRegions(vm0, vm1, vm2, vm3, startIndexForRegion, endIndexForRegion);
    getLogWriter()
        .info(
            "testPartitionedRegionDestroyAndContainsAPI() - Partition Regions Successfully Validated ");
    putInMultiplePartitionedRegion(vm0, vm1, vm2, vm3, startIndexForRegion, endIndexForRegion);
    getLogWriter()
        .info(
            "testPartitionedRegionDestroyAndContainsAPI() - Put() Operation done Successfully in Partition Regions ");
    destroyInMultiplePartitionedRegion(vm0, vm1, vm2, vm3, startIndexForRegion, endIndexForRegion);
    getLogWriter()
        .info(
            "testPartitionedRegionDestroyAndContainsAPI() - Destroy(Key) Operation done Successfully in Partition Regions ");
    async[0] =
        vm0.invokeAsync(
            validateContainsAPIForPartitionRegion(startIndexForRegion, endIndexForRegion));
    async[1] =
        vm1.invokeAsync(
            validateContainsAPIForPartitionRegion(startIndexForRegion, endIndexForRegion));
    async[2] =
        vm2.invokeAsync(
            validateContainsAPIForPartitionRegion(startIndexForRegion, endIndexForRegion));
    async[3] =
        vm3.invokeAsync(
            validateContainsAPIForPartitionRegion(startIndexForRegion, endIndexForRegion));

    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      DistributedTestCase.join(async[count], 120 * 1000, getLogWriter());
    }

    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      if (async[count].exceptionOccurred()) {
        fail("exception during " + count, async[count].getException());
      }
    }

    getLogWriter()
        .info(
            "testPartitionedRegionDestroyAndContainsAPI() - Validation of Contains APIs done Successfully in Partition Regions ");
  }
  /**
   * This function performs destroy(key) operations in multiple Partiton Regions. The range of keys
   * to be destroyed is from 100 to 200. Each Vm destroys different set of the keys.
   */
  private void destroyInMultiplePartitionedRegion(
      VM vm0, VM vm1, VM vm2, VM vm3, int startIndexForRegion, int endIndexForRegion)
      throws Throwable {

    int AsyncInvocationArrSize = 4;
    AsyncInvocation[] async = new AsyncInvocation[AsyncInvocationArrSize];
    int delta = (endIndexForDestroy - startIndexForDestroy) / 4;

    async[0] =
        vm0.invokeAsync(
            destroyInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy,
                startIndexForDestroy + 1 * delta,
                startIndexForRegion,
                endIndexForRegion));
    async[1] =
        vm1.invokeAsync(
            destroyInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy + 1 * delta,
                startIndexForDestroy + 2 * delta,
                startIndexForRegion,
                endIndexForRegion));
    async[2] =
        vm2.invokeAsync(
            destroyInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy + 2 * delta,
                startIndexForDestroy + 3 * delta,
                startIndexForRegion,
                endIndexForRegion));
    async[3] =
        vm3.invokeAsync(
            destroyInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy + 3 * delta,
                endIndexForDestroy,
                startIndexForRegion,
                endIndexForRegion));

    /** main thread is waiting for the other threads to complete */
    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      DistributedTestCase.join(async[count], 30 * 1000, getLogWriter());
    }

    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      if (async[count].exceptionOccurred()) {
        fail("exception during " + count, async[count].getException());
      }
    }
  }
  /**
   * This function performs get() operations in multiple Partition Regions. Each Vm gets keys from 0
   * to 400.
   */
  private void getInMultiplePartitionedRegion(
      VM vm0, VM vm1, VM vm2, VM vm3, int startIndexForRegion, int endIndexForRegion)
      throws Throwable {
    int AsyncInvocationArrSize = 4;
    AsyncInvocation[] async = new AsyncInvocation[AsyncInvocationArrSize];
    async[0] =
        vm0.invokeAsync(
            getInMultiplePartitionRegion(
                prPrefix,
                startIndexForKey,
                endIndexForKey,
                startIndexForRegion,
                endIndexForRegion));
    async[1] =
        vm1.invokeAsync(
            getInMultiplePartitionRegion(
                prPrefix,
                startIndexForKey,
                endIndexForKey,
                startIndexForRegion,
                endIndexForRegion));
    async[2] =
        vm2.invokeAsync(
            getInMultiplePartitionRegion(
                prPrefix,
                startIndexForKey,
                endIndexForKey,
                startIndexForRegion,
                endIndexForRegion));
    async[3] =
        vm3.invokeAsync(
            getInMultiplePartitionRegion(
                prPrefix,
                startIndexForKey,
                endIndexForKey,
                startIndexForRegion,
                endIndexForRegion));
    /** main thread is waiting for the other threads to complete */
    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      DistributedTestCase.join(async[count], 30 * 1000, getLogWriter());
    }

    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      if (async[count].exceptionOccurred()) {
        fail(
            "Failed due to exception: " + async[count].getException(), async[count].getException());
      }
    }
  }
  /**
   * This function performs get() operations in multiple Partition Regions after destroy of keys.
   * Each Vm gets keys from 100 to 200.
   */
  private void getDestroyedEntryInMultiplePartitionedRegion(
      VM vm0,
      VM vm1,
      VM vm2,
      VM vm3,
      int startIndexForRegion,
      int endIndexForRegion,
      int afterPutFlag)
      throws Throwable {
    int AsyncInvocationArrSize = 4;
    AsyncInvocation[] async = new AsyncInvocation[AsyncInvocationArrSize];

    async[0] =
        vm0.invokeAsync(
            getRemovedOrDestroyedInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy,
                endIndexForDestroy,
                startIndexForRegion,
                endIndexForRegion,
                afterPutFlag));
    async[1] =
        vm1.invokeAsync(
            getRemovedOrDestroyedInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy,
                endIndexForDestroy,
                startIndexForRegion,
                endIndexForRegion,
                afterPutFlag));
    async[2] =
        vm2.invokeAsync(
            getRemovedOrDestroyedInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy,
                endIndexForDestroy,
                startIndexForRegion,
                endIndexForRegion,
                afterPutFlag));
    async[3] =
        vm3.invokeAsync(
            getRemovedOrDestroyedInMultiplePartitionRegion(
                prPrefix,
                startIndexForDestroy,
                endIndexForDestroy,
                startIndexForRegion,
                endIndexForRegion,
                afterPutFlag));
    /** main thread is waiting for the other threads to complete */
    for (int count = 0; count < AsyncInvocationArrSize; count++) {
      DistributedTestCase.join(async[count], 30 * 1000, getLogWriter());
      if (async[count].exceptionOccurred()) {
        fail("exception during " + count, async[count].getException());
      }
    }

    //    for (int count = 0; count < AsyncInvocationArrSize; count++) {
    //      async[count].join();
    //    }
    //
    //    for (int count = 0; count < AsyncInvocationArrSize; count++) {
    //      if (async[count].exceptionOccurred()) {
    //        fail("exception during " + count, async[count].getException());
    //      }
    //    }
  }