class IsdaCompliantIndexCurveCalibrator {

  public LegalEntitySurvivalProbabilities calibrate(
      IsdaCreditCurveDefinition curveDefinition,
      MarketData marketData,
      ImmutableCreditRatesProvider ratesProvider,
      ReferenceData refData) {

    ArgChecker.isTrue(curveDefinition.getCurveValuationDate().equals(ratesProvider.getValuationDate()),
        "ratesProvider and curveDefinition must be based on the same valuation date");
    ImmutableList<CdsIndexIsdaCreditCurveNode> curveNodes = curveDefinition.getCurveNodes().stream()
        .filter(n -> n instanceof CdsIndexIsdaCreditCurveNode)
        .map(n -> (CdsIndexIsdaCreditCurveNode) n)
        .collect(Guavate.toImmutableList());
    // Homogeneity of curveNode will be checked within IsdaCompliantCreditCurveCalibrator
    double indexFactor = computeIndexFactor(curveNodes.get(0), marketData);
    List<CdsIsdaCreditCurveNode> cdsNodes = curveNodes.stream().map(i -> toCdsNode(i)).collect(Guavate.toImmutableList());
    LegalEntitySurvivalProbabilities creditCurve = creditCurveCalibrator.calibrate(
        cdsNodes,
        curveDefinition.getName(),
        marketData,
        ratesProvider,
        curveDefinition.getDayCount(),
        curveDefinition.getCurrency(),
        curveDefinition.isComputeJacobian(),
        false,
        refData);
    NodalCurve underlyingCurve = ((IsdaCreditDiscountFactors) creditCurve.getSurvivalProbabilities()).getCurve();
    CurveMetadata metadata = underlyingCurve.getMetadata().withInfo(CurveInfoType.CDS_INDEX_FACTOR, indexFactor);
    if (curveDefinition.isStoreNodeTrade()) {
      int nNodes = curveDefinition.getCurveNodes().size();
      ImmutableList<ParameterMetadata> parameterMetadata = IntStream.range(0, nNodes)
          .mapToObj(
              n -> ResolvedTradeParameterMetadata.of(
                  curveNodes.get(n).trade(1d, marketData, refData).getUnderlyingTrade().resolve(refData),
                  curveNodes.get(n).getLabel()))
          .collect(Guavate.toImmutableList());
      metadata = metadata.withParameterMetadata(parameterMetadata);
    }
    NodalCurve curveWithFactor = underlyingCurve.withMetadata(metadata);

    return LegalEntitySurvivalProbabilities.of(
        creditCurve.getLegalEntityId(),
        IsdaCreditDiscountFactors.of(creditCurve.getCurrency(), creditCurve.getValuationDate(), curveWithFactor));
  }

  public  IsdaCompliantIndexCurveCalibrator(IsdaCompliantCreditCurveCalibrator creditCurveCalibrator);

}