/**
   * Places and prepares the primary copy volumes when copying a VPLEX virtual volume.
   *
   * @param name The base name for the volume.
   * @param copyCount The number of copies to be made.
   * @param srcPrimaryVolume The primary volume of the VPLEX volume being copied.
   * @param srcCapabilities The capabilities of the primary volume.
   * @param volumeDescriptors The list of descriptors.
   * @return A list of the prepared primary volumes for the VPLEX volume copy.
   */
  private List<Volume> prepareFullCopyPrimaryVolumes(
      String name,
      int copyCount,
      Volume srcPrimaryVolume,
      VirtualPoolCapabilityValuesWrapper srcCapabilities,
      List<VolumeDescriptor> volumeDescriptors) {

    List<Volume> copyPrimaryVolumes = new ArrayList<Volume>();

    // Get the placement recommendations for the primary volume copies.
    // Use the same method as is done for native volume copy.
    VirtualArray vArray =
        _dbClient.queryObject(VirtualArray.class, srcPrimaryVolume.getVirtualArray());
    VirtualPool vPool = _dbClient.queryObject(VirtualPool.class, srcPrimaryVolume.getVirtualPool());
    List<VolumeRecommendation> recommendations =
        ((VPlexScheduler) _scheduler)
            .getBlockScheduler()
            .getRecommendationsForVolumeClones(vArray, vPool, srcPrimaryVolume, srcCapabilities);
    if (recommendations.isEmpty()) {
      throw APIException.badRequests.noStorageForPrimaryVolumesForVplexVolumeCopies();
    }

    // Prepare the copy volumes for each recommendation. Again,
    // use the same manner as is done for native volume copy.
    StringBuilder nameBuilder = new StringBuilder(name);
    nameBuilder.append("-0");
    int copyIndex = (copyCount > 1) ? 1 : 0;
    for (VolumeRecommendation recommendation : recommendations) {
      Volume volume =
          StorageScheduler.prepareFullCopyVolume(
              _dbClient,
              nameBuilder.toString(),
              srcPrimaryVolume,
              recommendation,
              copyIndex++,
              srcCapabilities);
      volume.addInternalFlags(Flag.INTERNAL_OBJECT);
      _dbClient.persistObject(volume);
      copyPrimaryVolumes.add(volume);

      // Create the volume descriptor and add it to the passed list.
      VolumeDescriptor volumeDescriptor =
          new VolumeDescriptor(
              VolumeDescriptor.Type.VPLEX_IMPORT_VOLUME,
              volume.getStorageController(),
              volume.getId(),
              volume.getPool(),
              srcCapabilities);
      volumeDescriptors.add(volumeDescriptor);
    }

    return copyPrimaryVolumes;
  }
  /**
   * Places and prepares the HA volumes when copying a distributed VPLEX volume.
   *
   * @param name The base name for the volume.
   * @param copyCount The number of copies to be made.
   * @param size The size for the HA volume.
   * @param vplexSystem A reference to the VPLEX storage system.
   * @param vplexSystemProject A reference to the VPLEX system project.
   * @param srcVarray The virtual array for the VPLEX volume being copied.
   * @param srcHAVolume The HA volume of the VPLEX volume being copied.
   * @param taskId The task identifier.
   * @param volumeDescriptors The list of descriptors.
   * @return A list of the prepared HA volumes for the VPLEX volume copy.
   */
  private List<Volume> prepareFullCopyHAVolumes(
      String name,
      int copyCount,
      Long size,
      StorageSystem vplexSystem,
      Project vplexSystemProject,
      VirtualArray srcVarray,
      Volume srcHAVolume,
      String taskId,
      List<VolumeDescriptor> volumeDescriptors) {

    List<Volume> copyHAVolumes = new ArrayList<Volume>();

    // Get the storage placement recommendations for the volumes.
    // Placement must occur on the same VPLEX system
    Set<URI> vplexSystemURIS = new HashSet<URI>();
    vplexSystemURIS.add(vplexSystem.getId());
    VirtualArray haVarray =
        _dbClient.queryObject(VirtualArray.class, srcHAVolume.getVirtualArray());
    VirtualPool haVpool = _dbClient.queryObject(VirtualPool.class, srcHAVolume.getVirtualPool());
    VirtualPoolCapabilityValuesWrapper haCapabilities = new VirtualPoolCapabilityValuesWrapper();
    haCapabilities.put(VirtualPoolCapabilityValuesWrapper.SIZE, size);
    haCapabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, copyCount);
    VirtualPool vpool = BlockFullCopyUtils.queryFullCopySourceVPool(srcHAVolume, _dbClient);
    if (VirtualPool.ProvisioningType.Thin.toString()
        .equalsIgnoreCase(vpool.getSupportedProvisioningType())) {
      haCapabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_PROVISIONING, Boolean.TRUE);
      // To guarantee that storage pool for a copy has enough physical
      // space to contain current allocated capacity of thin source volume
      haCapabilities.put(
          VirtualPoolCapabilityValuesWrapper.THIN_VOLUME_PRE_ALLOCATE_SIZE,
          BlockFullCopyUtils.getAllocatedCapacityForFullCopySource(srcHAVolume, _dbClient));
    }
    List<Recommendation> recommendations =
        ((VPlexScheduler) _scheduler)
            .scheduleStorageForImport(
                srcVarray, vplexSystemURIS, haVarray, haVpool, haCapabilities);
    if (recommendations.isEmpty()) {
      throw APIException.badRequests.noStorageForHaVolumesForVplexVolumeCopies();
    }

    // Prepare the HA volumes for the VPLEX volume copy.
    int copyIndex = 1;
    for (Recommendation recommendation : recommendations) {
      VPlexRecommendation haRecommendation = (VPlexRecommendation) recommendation;
      for (int i = 0; i < haRecommendation.getResourceCount(); i++) {
        // Determine the name for the HA volume copy.
        StringBuilder nameBuilder = new StringBuilder(name);
        nameBuilder.append("-1");
        if (copyCount > 1) {
          nameBuilder.append("-");
          nameBuilder.append(copyIndex++);
        }

        // Prepare the volume.
        Volume volume =
            VPlexBlockServiceApiImpl.prepareVolumeForRequest(
                size,
                vplexSystemProject,
                haVarray,
                haVpool,
                haRecommendation.getSourceDevice(),
                haRecommendation.getSourcePool(),
                nameBuilder.toString(),
                null,
                taskId,
                _dbClient);
        volume.addInternalFlags(Flag.INTERNAL_OBJECT);
        _dbClient.persistObject(volume);
        copyHAVolumes.add(volume);

        // Create the volume descriptor and add it to the passed list.
        VolumeDescriptor volumeDescriptor =
            new VolumeDescriptor(
                VolumeDescriptor.Type.BLOCK_DATA,
                volume.getStorageController(),
                volume.getId(),
                volume.getPool(),
                haCapabilities);
        volumeDescriptors.add(volumeDescriptor);
      }
    }

    return copyHAVolumes;
  }