class BloombergIdentifierProvider implements ExternalIdResolver {

  @Override
  public Map<ExternalId, ExternalIdBundleWithDates> getExternalIds(Set<ExternalId> unresolvedIdentifiers) {
    Map<ExternalId, ExternalIdBundleWithDates> result = new HashMap<ExternalId, ExternalIdBundleWithDates>(unresolvedIdentifiers.size());
    
    Map<String, ExternalId> bloombergKeys = new HashMap<String, ExternalId>(unresolvedIdentifiers.size());
    for (ExternalId identifier : unresolvedIdentifiers) {
      String bloombergKey = BloombergDomainIdentifierResolver.toBloombergKey(identifier);
      if (bloombergKey != null) {
        bloombergKeys.put(bloombergKey, identifier);
      } else {
        s_logger.warn("cannot resolve {} to bloomberg identifier", bloombergKey);
      }
    }
    
    ReferenceDataProviderGetRequest refDataRequest = ReferenceDataProviderGetRequest.createGet(bloombergKeys.keySet(), _bbgFields, true);
    ReferenceDataProviderGetResult refDataResult = _bbgRefDataProvider.getReferenceData(refDataRequest);
    
    for (ReferenceData refData : refDataResult.getReferenceData()) {
      String securityDes = refData.getIdentifier();
      
      // check no exceptions
      if (refData.isIdentifierError()) {
        List<ReferenceDataError> errors = refData.getErrors();
        if (errors != null && errors.size() > 0) {
          for (ReferenceDataError error : errors) {
            s_logger.warn("Exception looking up {}/{} - {}",
                new Object[] {securityDes, _bbgFields, error });
          }
          continue;
        }
      }
      
      // check same security was returned
      String refSec = refData.getIdentifier();
      if (!securityDes.equals(refSec)) {
        s_logger.warn("Returned security {} not the same as searched security {}", refSec, securityDes);
        continue;
      }
      // get field data
      FudgeMsg fieldData = refData.getFieldValues();
      
      final String securityType = fieldData.getString(FIELD_SECURITY_TYPE);
      if (securityType != null && securityType.toUpperCase().contains(" FUTURE")) {
        final String firstTradeStr = fieldData.getString(FIELD_FUT_FIRST_TRADE_DT);
        final LocalDate firstTradeDate = parseDate(firstTradeStr);
        final String lastTradeStr = fieldData.getString(FIELD_FUT_LAST_TRADE_DT);
        final LocalDate lastTradeDate = parseDate(lastTradeStr);
        if (lastTradeDate.isBefore(firstTradeDate)) {
          s_logger.warn("Reference data for {} indicates last trade date ({}) before first trade date ({}) - ignoring", new Object[] {securityDes, lastTradeDate, firstTradeDate});
          continue;
        }
      }
      
      try {
        ExternalIdBundleWithDates bundleWithDates = parseIdentifiers(fieldData);
        if (bundleWithDates != null) {
          result.put(bloombergKeys.get(securityDes), bundleWithDates);
        }
      } catch (Exception e) {
        s_logger.error("Error parsing identifiers for security " + securityDes, e);
        throw new OpenGammaRuntimeException("Error parsing identifiers for security " + securityDes, e);
      }
    }
    return result;
  }

  public  BloombergIdentifierProvider(ReferenceDataProvider refDataProvider);

}