/**
 * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.financial.analytics.model.forex;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import com.google.common.collect.Iterables;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.config.ConfigSource;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.core.value.MarketDataRequirementNames;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.financial.OpenGammaCompilationContext;
import com.opengamma.financial.analytics.timeseries.DateConstraint;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils;
import com.opengamma.financial.currency.ConfigDBCurrencyPairsSource;
import com.opengamma.financial.currency.CurrencyPair;
import com.opengamma.financial.currency.CurrencyPairs;
import com.opengamma.financial.security.FinancialSecurity;
import com.opengamma.financial.security.FinancialSecurityUtils;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolutionResult;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolver;
import com.opengamma.util.money.Currency;

/**
 *
 */
public class BloombergSecurityFXHistoricalTimeSeriesFunction extends AbstractSecurityFXHistoricalTimeSeriesFunction {

  @Override
  public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) {
    final ValueProperties constraints = desiredValue.getConstraints();
    final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
    final Collection<Currency> securityCurrencies = FinancialSecurityUtils.getCurrencies(security, getSecuritySource());
    final Set<String> resultCurrencies = constraints.getValues(ValuePropertyNames.CURRENCY);
    if (resultCurrencies != null && resultCurrencies.size() == 1) {
      final Currency desiredCurrency = Currency.of(Iterables.getOnlyElement(resultCurrencies));
      if (securityCurrencies.size() == 1) {
        final Currency securityCurrency = Iterables.getOnlyElement(securityCurrencies);
        return Collections.singleton(getHTSRequirement(context, desiredCurrency, securityCurrency));
      }
      final Set<ValueRequirement> requirements = new HashSet<ValueRequirement>();
      for (final Currency securityCurrency : securityCurrencies) {
        requirements.add(getHTSRequirement(context, desiredCurrency, securityCurrency));
      }
      return requirements;
    }
    return null;
  }

  private ValueRequirement getHTSRequirement(final FunctionCompilationContext context, final Currency desiredCurrency, final Currency securityCurrency) {
    if (desiredCurrency.equals(securityCurrency)) {
      return null;
    }
    final HistoricalTimeSeriesResolver htsResolver = OpenGammaCompilationContext.getHistoricalTimeSeriesResolver(context);
    final ConfigSource configSource = OpenGammaCompilationContext.getConfigSource(context);
    final ConfigDBCurrencyPairsSource currencyPairsSource = new ConfigDBCurrencyPairsSource(configSource);
    final CurrencyPairs baseQuotePairs = currencyPairsSource.getCurrencyPairs(CurrencyPairs.DEFAULT_CURRENCY_PAIRS);
    final CurrencyPair baseQuotePair = baseQuotePairs.getCurrencyPair(desiredCurrency, securityCurrency);
    if (baseQuotePair == null) {
      throw new OpenGammaRuntimeException("Could not get base/quote pair for currency pair (" + desiredCurrency + ", " + securityCurrency + ")");
    }
    final ExternalId externalId = getBBGId(baseQuotePair);
    final HistoricalTimeSeriesResolutionResult resolutionResult = htsResolver.resolve(ExternalIdBundle.of(externalId), null, null, null, MarketDataRequirementNames.MARKET_VALUE, null);
    if (resolutionResult == null) {
      return null;
    }
    return HistoricalTimeSeriesFunctionUtils.createHTSRequirement(resolutionResult, MarketDataRequirementNames.MARKET_VALUE, DateConstraint.EARLIEST_START, true, DateConstraint.VALUATION_TIME, true);
  }

  private ExternalId getBBGId(final CurrencyPair baseQuotePair) {
    return ExternalSchemes.bloombergTickerSecurityId(baseQuotePair.getBase().getCode() + baseQuotePair.getCounter().getCode() + " Curncy");
  }
}

@@ -233,27 +233,23 @@
 va.util.
-Collections
+HashSet
 ;%0Aimport
@@ -263,40 +263,61 @@
 til.
-Hash
 Set;%0A
+%0A
 import 
-java.util.
+com.google.common.collect.Immutable
 Set;%0A
-%0A
 impo
@@ -2605,37 +2605,42 @@
     
-return Collections.singleton(
+ValueRequirement htsRequirement = 
 getH
@@ -2688,33 +2688,112 @@
 ecurityCurrency)
-)
+;%0A        return htsRequirement != null ? ImmutableSet.of(htsRequirement) : null
 ;%0A      %7D%0A      
@@ -2943,17 +2943,37 @@
         
-r
+ValueRequirement htsR
 equireme
@@ -2978,14 +2978,11 @@
 ment
-s.add(
+ = 
 getH
@@ -3038,18 +3038,109 @@
 urrency)
-)
 ;
+%0A        if (htsRequirement != null) %7B%0A          requirements.add(htsRequirement);%0A        %7D
 %0A      %7D
@@ -3153,16 +3153,17 @@
  return 
+!
 requirem
@@ -3166,16 +3166,48 @@
 irements
+.isEmpty() ? requirements : null
 ;%0A    %7D%0A

Fix bug where null value requirement is added to set of function's requirements