/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.function;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Sets;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.target.ComputationTargetReference;
import com.opengamma.engine.target.ComputationTargetSpecificationResolver;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.id.UniqueId;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* An implementation of {@link FunctionInputs} that stores all inputs in internal maps.
*/
public class FunctionInputsImpl implements FunctionInputs, Serializable {
private static final long serialVersionUID = 1L;
private final ComputationTargetSpecificationResolver.AtVersionCorrection _resolver;
private final Set<ComputedValue> _values;
private final Map<String, ComputedValue> _valuesByRequirementName = new HashMap<String, ComputedValue>();
private final Map<Pair<String, Object>, ComputedValue[]> _valuesByRequirement = new HashMap<Pair<String, Object>, ComputedValue[]>();
private final Collection<ValueSpecification> _missingValues;
public FunctionInputsImpl(final ComputationTargetSpecificationResolver.AtVersionCorrection resolver, final ComputedValue value) {
_resolver = resolver;
_missingValues = Collections.emptySet();
_values = new HashSet<ComputedValue>();
addValue(value);
}
public FunctionInputsImpl(final ComputationTargetSpecificationResolver.AtVersionCorrection resolver, final Collection<? extends ComputedValue> values) {
this(resolver, values, Collections.<ValueSpecification>emptySet());
}
public FunctionInputsImpl(final ComputationTargetSpecificationResolver.AtVersionCorrection resolver, final Collection<? extends ComputedValue> values,
final Collection<ValueSpecification> missingValues) {
_resolver = resolver;
_missingValues = missingValues;
_values = Sets.newHashSetWithExpectedSize(values.size());
for (final ComputedValue value : values) {
addValue(value);
}
}
private void targetRefKey(final ComputationTargetReference targetRef, final List<UniqueId> uids) {
if (targetRef.getParent() != null) {
targetRefKey(targetRef.getParent(), uids);
}
uids.add(_resolver.getTargetSpecification(targetRef).getUniqueId());
}
private Object targetSpecKey(final ComputationTargetSpecification targetSpec) {
if (targetSpec.getParent() == null) {
return targetSpec.getUniqueId();
} else {
final List<UniqueId> uids = new ArrayList<UniqueId>();
targetRefKey(targetSpec.getParent(), uids);
uids.add(targetSpec.getUniqueId());
return uids;
}
}
private void addValue(final ComputedValue value) {
ArgumentChecker.notNull(value, "Computed Value");
if (value.getValue() instanceof ComputedValue) {
throw new IllegalArgumentException("Double-nested value");
}
_values.add(value);
_valuesByRequirementName.put(value.getSpecification().getValueName(), value);
final Pair<String, Object> key = Pairs.of(value.getSpecification().getValueName(), targetSpecKey(value.getSpecification().getTargetSpecification()));
final ComputedValue[] prev = _valuesByRequirement.get(key);
if (prev == null) {
_valuesByRequirement.put(key, new ComputedValue[] {value });
} else {
final ComputedValue[] values = new ComputedValue[prev.length + 1];
System.arraycopy(prev, 0, values, 0, prev.length);
values[prev.length] = value;
_valuesByRequirement.put(key, values);
}
}
@Override
public Collection<ComputedValue> getAllValues() {
return Collections.unmodifiableSet(_values);
}
@Override
public Object getValue(final ValueRequirement requirement) {
final ComputedValue cv = getComputedValue(requirement);
if (cv != null) {
return cv.getValue();
}
return null;
}
@Override
public ComputedValue getComputedValue(final ValueRequirement requirement) {
final Pair<String, Object> key = Pairs.of(requirement.getValueName(), targetSpecKey(_resolver.getTargetSpecification(requirement.getTargetReference())));
final ComputedValue[] values = _valuesByRequirement.get(key);
if (values != null) {
for (final ComputedValue value : values) {
// Shortcut to check the properties as we already know the name and target match
if (requirement.getConstraints().isSatisfiedBy(value.getSpecification().getProperties())) {
return value;
}
}
}
return null;
}
@Override
public Object getValue(final String requirementName) {
final ComputedValue computedValue = getComputedValue(requirementName);
return computedValue != null ? computedValue.getValue() : null;
}
@Override
public ComputedValue getComputedValue(final String requirementName) {
return _valuesByRequirementName.get(requirementName);
}
@Override
public Collection<ValueSpecification> getMissingValues() {
return Collections.unmodifiableCollection(_missingValues);
}
@Override
public String toString() {
return "Values = " + _values + ", Missing = " + _missingValues;
}
}