/**
   * Include only Unified,Virtual [Thin] and Device Storage Pools (Thick Pool)
   *
   * @param poolInstance
   * @return String [] array of pool class name (as a first element) and supported volume types (as
   *     a second element)
   */
  private String[] determinePoolClassNameAndSupportedVolumeTypes(
      CIMInstance poolInstance, StorageSystem system) {

    if (StoragePool.PoolClassNames.Clar_DeviceStoragePool.toString()
        .equalsIgnoreCase(poolInstance.getClassName())) {
      return new String[] {
        StoragePool.PoolClassNames.Clar_DeviceStoragePool.toString(),
        StoragePool.SupportedResourceTypes.THICK_ONLY.toString()
      };
    } else if (StoragePool.PoolClassNames.Clar_UnifiedStoragePool.toString()
        .equalsIgnoreCase(poolInstance.getClassName())) {
      return new String[] {
        StoragePool.PoolClassNames.Clar_UnifiedStoragePool.toString(),
        StoragePool.SupportedResourceTypes.THIN_AND_THICK.toString()
      };
    }

    if (!system.checkIfVmax3()) {
      if (StoragePool.PoolClassNames.Symm_DeviceStoragePool.toString()
              .equalsIgnoreCase(poolInstance.getClassName())
          && !SupportedProvisioningTypes.THIN
              .toString()
              .equalsIgnoreCase(system.getSupportedProvisioningType())) {
        return new String[] {
          StoragePool.PoolClassNames.Symm_DeviceStoragePool.toString(),
          StoragePool.SupportedResourceTypes.THICK_ONLY.toString()
        };
      } else if (StoragePool.PoolClassNames.Symm_VirtualProvisioningPool.toString()
              .equalsIgnoreCase(poolInstance.getClassName())
          && !SupportedProvisioningTypes.THICK
              .toString()
              .equalsIgnoreCase(system.getSupportedProvisioningType())) {
        return new String[] {
          StoragePool.PoolClassNames.Symm_VirtualProvisioningPool.toString(),
          StoragePool.SupportedResourceTypes.THIN_ONLY.toString()
        };
      }
    } else {
      // VMAX3 has StorageResourcePools (SRP). These are composed of ThinPools, which we can
      // discover, but would not have write access to. So, we will only discovery SRP pools
      // and skip over other pool discoveries.
      if (StoragePool.PoolClassNames.Symm_SRPStoragePool.toString()
          .equalsIgnoreCase(poolInstance.getClassName())) {
        return new String[] {
          StoragePool.PoolClassNames.Symm_SRPStoragePool.toString(),
          StoragePool.SupportedResourceTypes.THIN_ONLY.toString()
        };
      }
    }
    return null;
  }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public void processResult(Operation operation, Object resultObj, Map<String, Object> keyMap)
      throws BaseCollectionException {
    final Iterator<CIMInstance> it = (Iterator<CIMInstance>) resultObj;
    profile = (AccessProfile) keyMap.get(Constants.ACCESSPROFILE);
    try {
      _newPoolList = new ArrayList<StoragePool>();
      _updatePoolList = new ArrayList<StoragePool>();
      _dbClient = (DbClient) keyMap.get(Constants.dbClient);
      _cimClient = (WBEMClient) keyMap.get(Constants._cimClient);
      _coordinator = (CoordinatorClient) keyMap.get(Constants.COORDINATOR_CLIENT);
      _eventManager = (RecordableEventManager) keyMap.get(Constants.EVENT_MANAGER);
      _logger.info("StoragePoolProcessor --- event manager: " + _eventManager);
      StorageSystem device = getStorageSystem(_dbClient, profile.getSystemId());
      if (SupportedProvisioningTypes.NONE
          .toString()
          .equalsIgnoreCase(device.getSupportedProvisioningType())) {
        _logger.info(
            "Storage System doesn't support volume creations :" + device.getSerialNumber());
        return;
      }
      Set<String> protocols = (Set<String>) keyMap.get(Constants.PROTOCOLS);
      Map<URI, StoragePool> poolsToMatchWithVpool =
          (Map<URI, StoragePool>) keyMap.get(Constants.MODIFIED_STORAGEPOOLS);
      while (it.hasNext()) {
        CIMInstance poolInstance = null;
        try {
          poolInstance = it.next();

          // Supporting both thick and thin pools
          String[] poolClassNameAndSupportedVolumeTypes =
              determinePoolClassNameAndSupportedVolumeTypes(poolInstance, device);
          if (null != poolClassNameAndSupportedVolumeTypes) {
            String instanceID = getCIMPropertyValue(poolInstance, Constants.INSTANCEID);
            addPath(keyMap, operation.getResult(), poolInstance.getObjectPath());
            StoragePool pool =
                checkStoragePoolExistsInDB(getNativeIDFromInstance(instanceID), _dbClient, device);
            createStoragePool(
                pool,
                poolInstance,
                profile,
                poolClassNameAndSupportedVolumeTypes[0],
                poolClassNameAndSupportedVolumeTypes[1],
                protocols,
                poolsToMatchWithVpool,
                device);

            if (DiscoveredDataObject.Type.vnxblock
                .toString()
                .equalsIgnoreCase(device.getSystemType())) {
              addPath(keyMap, Constants.VNXPOOLS, poolInstance.getObjectPath());
            }

            if (DiscoveredDataObject.Type.vmax
                .toString()
                .equalsIgnoreCase(device.getSystemType())) {
              addPath(keyMap, Constants.VMAXPOOLS, poolInstance.getObjectPath());
              if (!device.checkIfVmax3()) {
                addPath(keyMap, Constants.VMAX2POOLS, poolInstance.getObjectPath());
              }
            }
            // This approach deviates from the existing built plugin framework for plugin
            // Discovery
            // To follow the existing pattern, we need to have different SMI-S calls
            // 1st to get Device StoragePools alone ,and 2nd to get Thin Pools.
            // Its a tradeoff between whether to go with the current plugin design or
            // reduce the number of calls to SMI Provider.
            // I chose the 2nd option.
            if (!poolClassNameAndSupportedVolumeTypes[0].contains(DEVICE_STORAGE_POOL)) {
              addPath(keyMap, Constants.THINPOOLS, poolInstance.getObjectPath());
            }

            addPath(keyMap, Constants.DEVICEANDTHINPOOLS, poolInstance.getObjectPath());
          } else {
            _logger.debug(
                "Skipping Pools other than Unified & Virtual & Device : {}",
                poolInstance.getObjectPath().toString());
          }
        } catch (Exception e) {
          _logger.warn(
              "StoragePool Discovery failed for {}",
              getCIMPropertyValue(poolInstance, Constants.INSTANCEID),
              e);
        }
      }

      _dbClient.createObject(_newPoolList);
      _dbClient.updateAndReindexObject(_updatePoolList);

      // find the pools not visible in this discovery
      List<StoragePool> discoveredPools = new ArrayList<StoragePool>(_newPoolList);
      discoveredPools.addAll(_updatePoolList);
      List<StoragePool> notVisiblePools =
          DiscoveryUtils.checkStoragePoolsNotVisible(discoveredPools, _dbClient, device.getId());
      for (StoragePool notVisiblePool : notVisiblePools) {
        poolsToMatchWithVpool.put(notVisiblePool.getId(), notVisiblePool);
      }
      // If any storage ports on the storage system are in a transport
      // zone, there is an implicit connection to the transport zone
      // varray. We need to add these implicit varray
      // connections for the new storage pool.
      StoragePoolAssociationHelper.setStoragePoolVarrays(device.getId(), _newPoolList, _dbClient);
    } catch (Exception e) {
      _logger.error("StoragePool Discovery failed --> {}", getMessage(e));
    } finally {
      _newPoolList = null;
      _updatePoolList = null;
    }
  }