/*
   * (non-Javadoc)
   *
   * @see
   * com.emc.storageos.volumecontroller.BlockStorageDevice#doWaitForSynchronized
   * (java.lang.Class, com.emc.storageos.db.client.model.StorageSystem,
   * java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter)
   */
  @Override
  public void doWaitForSynchronized(
      Class<? extends BlockObject> clazz,
      StorageSystem storageObj,
      URI target,
      TaskCompleter completer) {
    log.info("START waitForSynchronized for {}", target);

    try {
      Volume targetObj = dbClient.queryObject(Volume.class, target);
      // Source could be either Volume or BlockSnapshot
      BlockObject sourceObj = BlockObject.fetch(dbClient, targetObj.getAssociatedSourceVolume());

      // We split the pair which causes the data to be synchronized.
      // When the split is complete that data is synchronized.
      HDSApiClient hdsApiClient =
          hdsApiFactory.getClient(
              HDSUtils.getHDSServerManagementServerInfo(storageObj),
              storageObj.getSmisUserName(),
              storageObj.getSmisPassword());
      HDSApiProtectionManager hdsApiProtectionManager = hdsApiClient.getHdsApiProtectionManager();
      String replicationGroupObjectID = hdsApiProtectionManager.getReplicationGroupObjectId();
      ReplicationInfo replicationInfo =
          hdsApiProtectionManager.getReplicationInfoFromSystem(
                  sourceObj.getNativeId(), targetObj.getNativeId())
              .first;
      hdsApiProtectionManager.modifyShadowImagePair(
          replicationGroupObjectID,
          replicationInfo.getObjectID(),
          HDSApiProtectionManager.ShadowImageOperationType.split);

      // Update state in case we are waiting for synchronization
      // after creation of a new full copy that was not created
      // inactive.
      String state = targetObj.getReplicaState();
      if (!ReplicationState.SYNCHRONIZED.name().equals(state)) {
        targetObj.setSyncActive(true);
        targetObj.setReplicaState(ReplicationState.SYNCHRONIZED.name());
        dbClient.persistObject(targetObj);
      }

      // Queue job to wait for replication status to move to split.
      ControllerServiceImpl.enqueueJob(
          new QueueJob(
              new HDSReplicationSyncJob(
                  storageObj.getId(),
                  sourceObj.getNativeId(),
                  targetObj.getNativeId(),
                  ReplicationStatus.SPLIT,
                  completer)));
    } catch (Exception e) {
      log.error("Exception occurred while waiting for synchronization", e);
      ServiceError serviceError = DeviceControllerException.errors.jobFailed(e);
      completer.error(dbClient, serviceError);
    }
    log.info("completed doWaitForSynchronized");
  }
  /**
   * Prepares the VPLEX volume copies.
   *
   * @param name The base name for the volume.
   * @param copyCount The total number of copies.
   * @param copyIndex The index for this copy.
   * @param size The size for the HA volume.
   * @param srcVPlexVolume The VPLEX volume being copied.
   * @param srcProject The project for the VPLEX volume being copied.
   * @param srcVarray The virtual array for the VPLEX volume being copied.
   * @param srcVpool The virtual pool for the VPLEX volume being copied.
   * @param srcSystemURI The VPLEX system URI.
   * @param primaryVolume The primary volume for the copy.
   * @param haVolume The HA volume for the copy, or null.
   * @param taskId The task identifier.
   * @param volumeDescriptors The list of descriptors.
   * @return A reference to the prepared VPLEX volume copy.
   */
  private Volume prepareFullCopyVPlexVolume(
      String name,
      int copyCount,
      int copyIndex,
      long size,
      Volume srcVPlexVolume,
      Project srcProject,
      VirtualArray srcVarray,
      VirtualPool srcVpool,
      URI srcSystemURI,
      Volume primaryVolume,
      Volume haVolume,
      String taskId,
      List<VolumeDescriptor> volumeDescriptors) {

    // Determine the VPLEX volume copy name.
    StringBuilder nameBuilder = new StringBuilder(name);
    if (copyCount > 1) {
      nameBuilder.append("-");
      nameBuilder.append(copyIndex + 1);
    }

    // Prepare the VPLEX volume copy.
    Volume vplexCopyVolume =
        VPlexBlockServiceApiImpl.prepareVolumeForRequest(
            size,
            srcProject,
            srcVarray,
            srcVpool,
            srcSystemURI,
            NullColumnValueGetter.getNullURI(),
            nameBuilder.toString(),
            ResourceOperationTypeEnum.CREATE_VOLUME_FULL_COPY,
            taskId,
            _dbClient);

    // Create a volume descriptor and add it to the passed list.
    VolumeDescriptor vplexCopyVolumeDescr =
        new VolumeDescriptor(
            VolumeDescriptor.Type.VPLEX_VIRT_VOLUME,
            srcSystemURI,
            vplexCopyVolume.getId(),
            null,
            null);
    volumeDescriptors.add(vplexCopyVolumeDescr);

    // Set the associated volumes for this new VPLEX volume copy to
    // the copy of the backend primary and the newly prepared HA
    // volume if the VPLEX volume being copied is distributed.
    vplexCopyVolume.setAssociatedVolumes(new StringSet());
    StringSet assocVolumes = vplexCopyVolume.getAssociatedVolumes();
    assocVolumes.add(primaryVolume.getId().toString());
    if (haVolume != null) {
      assocVolumes.add(haVolume.getId().toString());
    }

    // Set the VPLEX source volume for the copy.
    vplexCopyVolume.setAssociatedSourceVolume(srcVPlexVolume.getId());

    // Copies always created active.
    vplexCopyVolume.setSyncActive(Boolean.TRUE);

    // Persist the copy.
    _dbClient.persistObject(vplexCopyVolume);

    return vplexCopyVolume;
  }