/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.calc.runner;
import static java.util.stream.Collectors.groupingBy;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.opengamma.strata.basics.CalculationTarget;
/**
* A set of {@link DerivedCalculationFunction} instances which decorates another {@link CalculationFunctions}
* instance, creating a combined set of functions.
*/
class DerivedCalculationFunctions implements CalculationFunctions {
/** The underlying set of calculation functions. */
private final CalculationFunctions delegateFunctions;
/** Derived calculation functions keyed by the type of target they handle. */
private final Map<Class<?>, List<DerivedCalculationFunction<?, ?>>> functionsByTargetType;
/**
* Creates an instance.
*
* @param delegateFunctions the underlying set of calculation functions
* @param functions the derived calculation functions
*/
DerivedCalculationFunctions(CalculationFunctions delegateFunctions, DerivedCalculationFunction<?, ?>... functions) {
this.delegateFunctions = delegateFunctions;
this.functionsByTargetType = Arrays.stream(functions).collect(groupingBy(fn -> fn.targetType()));
}
@Override
public <T extends CalculationTarget> Optional<CalculationFunction<? super T>> findFunction(T target) {
return delegateFunctions.findFunction(target).map(fn -> wrap(fn, target));
}
@SuppressWarnings("unchecked")
private <T extends CalculationTarget, R> CalculationFunction<? super T> wrap(CalculationFunction<? super T> fn, T target) {
List<DerivedCalculationFunction<?, ?>> derivedFunctions = functionsByTargetType.get(target.getClass());
CalculationFunction<? super T> wrappedFn = fn;
for (DerivedCalculationFunction<?, ?> derivedFn : derivedFunctions) {
// These casts are necessary because the type information is lost when the functions are stored in the map.
// They are safe because T is the target type which is is the map key and R isn't actually used
CalculationFunction<T> wrappedFnCast = (CalculationFunction<T>) wrappedFn;
DerivedCalculationFunction<T, R> derivedFnCast = (DerivedCalculationFunction<T, R>) derivedFn;
wrappedFn = new DerivedCalculationFunctionWrapper<>(derivedFnCast, wrappedFnCast);
}
return wrappedFn;
}
}