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

import static com.google.common.collect.Sets.newHashSet;
import static com.opengamma.engine.function.dsl.Function.function;
import static com.opengamma.engine.function.dsl.Function.input;
import static com.opengamma.engine.function.dsl.Function.output;
import static com.opengamma.engine.function.dsl.TargetSpecificationReference.originalTarget;
import static com.opengamma.engine.function.dsl.properties.RecordingValueProperties.copyFrom;
import static com.opengamma.engine.value.ValueRequirementNames.BUCKETED_PV01;
import static com.opengamma.engine.value.ValueRequirementNames.YIELD_CURVE_NODE_SENSITIVITIES;
import static com.opengamma.lambdava.streams.Lambdava.functional;

import java.util.Set;

import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
import com.opengamma.engine.function.dsl.FunctionSignature;
import com.opengamma.engine.function.dsl.functions.BaseNonCompiledInvoker;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.lambdava.functions.Function3;
import com.opengamma.util.async.AsynchronousExecution;

/**
 * Generic function to compute the bucketed PV01 of XXX from the YieldCurveNodeSensitivity (scaling to 1 bp).
 */
public class BucketedPV01Function extends BaseNonCompiledInvoker {

  @Override
  protected FunctionSignature functionSignature() {

    return function("Bucketed PV01", ComputationTargetType.POSITION_OR_TRADE)
        .outputs(
            output(BUCKETED_PV01)
                .targetSpec(originalTarget())
                .properties(copyFrom(YIELD_CURVE_NODE_SENSITIVITIES)
                                .withReplacement(ValuePropertyNames.FUNCTION, getUniqueId()))
        )
        .inputs(
            input(YIELD_CURVE_NODE_SENSITIVITIES)
                .properties(copyFrom(BUCKETED_PV01))
                .targetSpec(originalTarget()));
  }

  @Override
  public Set<ComputedValue> execute(FunctionExecutionContext executionContext,
                                    final FunctionInputs inputs,
                                    ComputationTarget target,
                                    Set<ValueRequirement> desiredValues) throws AsynchronousExecution {

    DoubleLabelledMatrix1D matrix = (DoubleLabelledMatrix1D) inputs.getComputedValue(YIELD_CURVE_NODE_SENSITIVITIES).getValue();
    LabelledMatrix1D<Double, Double> matrixDividedBy10k = matrix.mapValues(new Function3<Double, Double, Object, Double>() {
      @Override
      public Double execute(Double _, Double value, Object __) {
        return value / 10000.0;
      }
    });

    ValueRequirement desiredValue = functional(desiredValues).first();
    ValueSpecification valueSpecification = ValueSpecification.of(desiredValue.getValueName(),
                                                                  target.toSpecification(),
                                                                  desiredValue.getConstraints());
    return newHashSet(new ComputedValue(valueSpecification, matrixDividedBy10k));
  }

  @Override
  public String getUniqueId() {
    return "Bucketed PV01 Function";
  }
  
}

@@ -1741,16 +1741,73 @@
 oker %7B%0A%0A
+  private static final double RESCALE_FACTOR = 10000.0;%0A%0A
   @Overr
@@ -2128,28 +2128,16 @@
         
-            
 .withRep
@@ -2365,16 +2365,25 @@
 arget())
+%0A        
 );%0A  %7D%0A%0A
@@ -2477,38 +2477,8 @@
 xt,%0A
-                              
     
@@ -2518,94 +2518,34 @@
     
-                              ComputationTarget target,%0A                              
+ComputationTarget target,%0A
     
@@ -2743,16 +2743,391 @@
 Value();
+%0A%0A    ValueRequirement desiredValue = functional(desiredValues).first();%0A%0A    final double rescaleFactor;%0A    if (desiredValue.getConstraint(%22SCALING_FACTOR%22) != null) %7B%0A      double scalingFactor = Double.parseDouble(desiredValue.getConstraint(%22SCALING_FACTOR%22));%0A      rescaleFactor = RESCALE_FACTOR / scalingFactor;%0A    %7D else %7B%0A      rescaleFactor = RESCALE_FACTOR;%0A    %7D
 %0A    Lab
@@ -3295,17 +3295,23 @@
 (Double 
-_
+notUsed
 , Double
@@ -3329,10 +3329,16 @@
 ect 
-__
+notUsed2
 ) %7B%0A
@@ -3360,23 +3360,29 @@
 value / 
-10000.0
+rescaleFactor
 ;%0A      
@@ -3396,79 +3396,8 @@
 );%0A%0A
-    ValueRequirement desiredValue = functional(desiredValues).first();%0A
     
@@ -3499,150 +3499,34 @@
     
-                                                          target.toSpecification(),%0A                                                          
+target.toSpecification(),%0A
     
@@ -3733,13 +3733,11 @@
 n%22;%0A  %7D%0A
-  
 %0A%7D%0A

Introduce a scaling factor - to be reviewed