/**
   * Allows the user to get data for the storage system with the passed system id that is associated
   * with the storage provider with the passed provider id.
   *
   * @param id the URN of a ViPR Storage provider
   * @param systemId The id of the storage system.
   * @brief Show Storage provider storage system
   * @return A StorageSystemRestRep reference specifying the data for the storage system.
   */
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/storage-systems/{systemId}")
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR})
  public StorageSystemRestRep getStorageSystem(
      @PathParam("id") URI id, @PathParam("systemId") URI systemId) {

    // Validate the provider.
    ArgValidator.checkFieldUriType(id, StorageProvider.class, "id");
    StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id);
    ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id));
    ArgValidator.checkFieldUriType(systemId, StorageSystem.class, "id");

    // Return the storage system if found.
    StringSet providerSystemURIStrs = provider.getStorageSystems();
    if (providerSystemURIStrs != null) {
      for (String providerSystemURIStr : providerSystemURIStrs) {
        if (providerSystemURIStr.equals(systemId.toString())) {
          StorageSystem storageSystem =
              _dbClient.queryObject(StorageSystem.class, URI.create(providerSystemURIStr));
          if (storageSystem != null) {
            return map(storageSystem);
          }
          break;
        }
      }
    }

    throw APIException.notFound.unableToFindEntityInURL(id);
  }
  /**
   * Allows the user to get the id, name, and self link for all storage systems visible to the
   * provider with the passed id.
   *
   * @param id the URN of a ViPR Storage provider
   * @brief List Storage provider storage systems
   * @return A StorageSystemList reference specifying the id, name, and self link for the storage
   *     systems visible to the provider.
   */
  @GET
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}/storage-systems")
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR})
  public StorageSystemList getStorageSystems(@PathParam("id") URI id) {

    // Validate the provider
    ArgValidator.checkFieldUriType(id, StorageProvider.class, "id");
    StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id);
    ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id));

    // Return the list of storage systems for the provider.
    StorageSystemList storageSystemsForProvider = new StorageSystemList();
    StringSet providerSystemURIStrs = provider.getStorageSystems();
    if (providerSystemURIStrs != null) {
      for (String providerSystemURIStr : providerSystemURIStrs) {
        StorageSystem storageSystem =
            _dbClient.queryObject(StorageSystem.class, URI.create(providerSystemURIStr));
        if (storageSystem != null) {
          storageSystemsForProvider.getStorageSystems().add(toNamedRelatedResource(storageSystem));
        }
      }
    }

    return storageSystemsForProvider;
  }
  @POST
  @Path("/{id}/deactivate")
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN})
  public Response deleteStorageProvider(@PathParam("id") URI id) {
    // Validate the provider
    ArgValidator.checkFieldUriType(id, StorageProvider.class, "id");
    StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id);
    ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id));
    // Verify the provider can be removed without leaving "dangling" storages.
    StringSet providerStorageSystems = provider.getStorageSystems();
    if (null != providerStorageSystems && !providerStorageSystems.isEmpty()) {
      // First we need to verify that all related storage systems has at least   2 providers
      for (String system : providerStorageSystems) {
        StorageSystem storageSys = _dbClient.queryObject(StorageSystem.class, URI.create(system));
        if (storageSys != null
            && !storageSys.getInactive()
            && storageSys.getProviders() != null
            && storageSys.getProviders().size() == 1) {
          throw APIException.badRequests.cannotDeleteProviderWithManagedStorageSystems(
              storageSys.getId());
        }
      }
      // Next we can clear this provider from storage systems.
      for (String system : providerStorageSystems) {
        StorageSystem storageSys = _dbClient.queryObject(StorageSystem.class, URI.create(system));
        provider.removeStorageSystem(_dbClient, storageSys);
      }
    }

    StringSet decommissionedSystems = provider.getDecommissionedSystems();
    if (null != decommissionedSystems && !decommissionedSystems.isEmpty()) {
      for (String decommissioned : decommissionedSystems) {
        DecommissionedResource oldRes =
            _dbClient.queryObject(DecommissionedResource.class, URI.create(decommissioned));
        if (oldRes != null) {
          _dbClient.markForDeletion(oldRes);
        }
      }
    }

    // Set to inactive.
    _dbClient.markForDeletion(provider);

    auditOp(
        OperationTypeEnum.DELETE_STORAGEPROVIDER,
        true,
        null,
        provider.getId().toString(),
        provider.getLabel(),
        provider.getIPAddress(),
        provider.getPortNumber(),
        provider.getUserName(),
        provider.getInterfaceType());

    return Response.ok().build();
  }
  /**
   * Update the Storage Provider. This is useful when we move arrays to some other provider.
   *
   * @param id the URN of a ViPR Storage Provider
   * @brief Update Storage provider
   * @return Updated Storage Provider information.
   */
  @PUT
  @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  @Path("/{id}")
  @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN})
  public StorageProviderRestRep updateStorageProvider(
      @PathParam("id") URI id, StorageProviderUpdateParam param) {
    StorageProvider storageProvider = _dbClient.queryObject(StorageProvider.class, id);
    if (null == storageProvider || storageProvider.getInactive()) {
      throw APIException.notFound.unableToFindEntityInURL(id);
    } else {
      /* Usecase is not to remove the provider instead we can update the old storage provider with
      new provider details. */
      if (param.getName() != null
          && !param.getName().equals("")
          && !param.getName().equalsIgnoreCase(storageProvider.getLabel())) {
        checkForDuplicateName(param.getName(), StorageProvider.class);
        storageProvider.setLabel(param.getName());
      }

      // if the ip or port passed are different from the existing one
      // check to ensure a provider does not exist with the new ip + port combo
      String existingIPAddress = storageProvider.getIPAddress();
      Integer existingPortNumber = storageProvider.getPortNumber();
      if ((param.getIpAddress() != null && !param.getIpAddress().equals(existingIPAddress))
          || (param.getPortNumber() != null && !param.getPortNumber().equals(existingPortNumber))) {
        String ipAddress =
            (param.getIpAddress() != null) ? param.getIpAddress() : existingIPAddress;
        Integer portNumber =
            (param.getPortNumber() != null) ? param.getPortNumber() : existingPortNumber;
        ArgValidator.checkFieldRange(portNumber, 1, 65535, "port_number");

        String providerKey = ipAddress + "-" + portNumber;
        List<StorageProvider> providers =
            CustomQueryUtility.getActiveStorageProvidersByProviderId(_dbClient, providerKey);
        if (providers != null && !providers.isEmpty()) {
          throw APIException.badRequests.invalidParameterStorageProviderAlreadyRegistered(
              providerKey);
        }

        // User can update IP address for an existing Provider object
        // if and only if the connection with old IP is not alive.
        if (!existingIPAddress.equals(param.getIpAddress())
            && isOldConnectionAlive(
                existingIPAddress, existingPortNumber, storageProvider.getInterfaceType())
            && (storageProvider.getStorageSystems() != null
                && !storageProvider.getStorageSystems().isEmpty())) {
          throw APIException.badRequests.cannotUpdateProviderIP(
              existingIPAddress + "-" + existingPortNumber);
        }

        storageProvider.setIPAddress(ipAddress);
        storageProvider.setPortNumber(portNumber);
      }
      if (param.getUserName() != null && StringUtils.isNotBlank(param.getUserName())) {
        storageProvider.setUserName(param.getUserName());
      }
      if (param.getPassword() != null && StringUtils.isNotBlank(param.getPassword())) {
        storageProvider.setPassword(param.getPassword());
      }
      if (param.getUseSSL() != null) {
        storageProvider.setUseSSL(param.getUseSSL());
      }

      if (param.getInterfaceType() != null) {
        ArgValidator.checkFieldValueFromEnum(
            param.getInterfaceType(),
            "interface_type",
            EnumSet.of(
                StorageProvider.InterfaceType.hicommand,
                StorageProvider.InterfaceType.smis,
                StorageProvider.InterfaceType.scaleio,
                StorageProvider.InterfaceType.ibmxiv));
        storageProvider.setInterfaceType(param.getInterfaceType());
      }

      if (param.getSecondaryUsername() != null) {
        storageProvider.setSecondaryUsername(param.getSecondaryUsername());
      }
      if (param.getSecondaryPassword() != null) {
        storageProvider.setSecondaryPassword(param.getSecondaryPassword());
      }
      if (param.getElementManagerURL() != null) {
        storageProvider.setElementManagerURL(param.getElementManagerURL());
      }

      _dbClient.persistObject(storageProvider);
    }

    auditOp(
        OperationTypeEnum.UPDATE_STORAGEPROVIDER,
        true,
        null,
        storageProvider.getId().toString(),
        storageProvider.getLabel(),
        storageProvider.getIPAddress(),
        storageProvider.getPortNumber(),
        storageProvider.getUserName(),
        storageProvider.getInterfaceType());

    return map(storageProvider);
  }