/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.marketdata;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.threeten.bp.Instant;
import com.google.common.collect.Maps;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.id.UniqueId;
/**
* Combines an underlying {@link MarketDataSnapshot} with one designed to provide overrides for certain requirements.
* <p>
* Note that the overriding snapshot can provide instances of {@link OverrideOperation} instead of (or as well as) actual values for this to return. In this case the operation is applied to the
* underlying.
*/
public class MarketDataSnapshotWithOverride extends AbstractMarketDataSnapshot {
private final MarketDataSnapshot _underlying;
private final MarketDataInjectorImpl.Snapshot _override;
public MarketDataSnapshotWithOverride(final MarketDataSnapshot underlying, final MarketDataInjectorImpl.Snapshot override) {
_underlying = underlying;
_override = override;
}
@Override
public UniqueId getUniqueId() {
assertInitialized();
if (getOverride() == null) {
// NOTE jonathan 2013-03-08 -- important for batch to have access to the real underlying snapshot ID when possible
return getUnderlying().getUniqueId();
}
// REVIEW 2013-02-04 Andrew -- This is not a good unique id, it should be allocated by whatever persists or creates these snapshots
return UniqueId.of(MARKET_DATA_SNAPSHOT_ID_SCHEME, "MarketDataSnapshotWithOverride:" + getSnapshotTime());
}
@Override
public Instant getSnapshotTimeIndication() {
return getUnderlying().getSnapshotTimeIndication();
}
@Override
public void init() {
getUnderlying().init();
if (getOverride() != null) {
getOverride().init();
}
}
@Override
public void init(final Set<ValueSpecification> values, final long timeout, final TimeUnit unit) {
getUnderlying().init(values, timeout, unit);
if (getOverride() != null) {
getOverride().init();
}
}
@Override
public boolean isInitialized() {
return getUnderlying().isInitialized();
}
@Override
public boolean isEmpty() {
assertInitialized();
return getUnderlying().isEmpty() && (getOverride() == null);
}
@Override
public Instant getSnapshotTime() {
return getUnderlying().getSnapshotTime();
}
@Override
public Object query(final ValueSpecification value) {
if (getOverride() != null) {
Object result = getOverride().query(value);
if (result != null) {
if (result instanceof OverrideOperation) {
final OverrideOperation operation = (OverrideOperation) result;
result = getUnderlying().query(value);
if (result != null) {
return operation.apply(getOverrideValueRequirement(value), result);
} else {
return null;
}
} else {
return result;
}
}
}
return getUnderlying().query(value);
}
@Override
public Map<ValueSpecification, Object> query(final Set<ValueSpecification> values) {
if (getOverride() != null) {
final Set<ValueSpecification> unresolved = new HashSet<ValueSpecification>(values);
final Map<ValueSpecification, Object> result = Maps.newHashMapWithExpectedSize(values.size());
final Map<ValueSpecification, OverrideOperation> overrideOperations = Maps.newHashMapWithExpectedSize(values.size());
for (ValueSpecification value : values) {
Object response = getOverride().query(value);
if (response == null) {
continue;
} else if (response instanceof OverrideOperation) {
overrideOperations.put(value, (OverrideOperation) response);
} else {
result.put(value, response);
unresolved.remove(value);
}
}
if (!unresolved.isEmpty()) {
final Map<ValueSpecification, Object> response = getUnderlying().query(unresolved);
if (response != null) {
for (final Map.Entry<ValueSpecification, Object> underlyingEntry : response.entrySet()) {
final OverrideOperation overrideOperation = overrideOperations.get(underlyingEntry.getKey());
if (overrideOperation != null) {
result.put(underlyingEntry.getKey(), overrideOperation.apply(getOverrideValueRequirement(underlyingEntry.getKey()), underlyingEntry.getValue()));
} else {
result.put(underlyingEntry.getKey(), underlyingEntry.getValue());
}
}
}
}
return result;
} else {
return getUnderlying().query(values);
}
}
private ValueRequirement getOverrideValueRequirement(final ValueSpecification subscription) {
// TODO: Converting a value specification to a requirement like this is probably going to be wrong
return new ValueRequirement(subscription.getValueName(), subscription.getTargetSpecification(), subscription.getProperties());
}
//-------------------------------------------------------------------------
private MarketDataSnapshot getUnderlying() {
return _underlying;
}
private MarketDataInjectorImpl.Snapshot getOverride() {
return _override;
}
}