class ForwardOvernightAveragedRateComputationFn implements RateComputationFn<OvernightAveragedRateComputation> {

  @Override
  public double rate(
      OvernightAveragedRateComputation computation,
      LocalDate startDate,
      LocalDate endDate,
      RatesProvider provider) {

    OvernightIndex index = computation.getIndex();
    OvernightIndexRates rates = provider.overnightIndexRates(index);
    LocalDate lastNonCutoffFixing = computation.getEndDate();
    int cutoffOffset = computation.getRateCutOffDays() > 1 ? computation.getRateCutOffDays() : 1;
    double accumulatedInterest = 0.0d;
    double accrualFactorTotal = 0.0d;
    // Cut-off period. Starting from the end as the cutoff period is defined as a lag from the end.
    // When the fixing period end-date is not a good business day in the index calendar, 
    // the last fixing end date will be after the fixing end-date.
    double cutoffAccrualFactor = 0.0;
    OvernightIndexObservation lastIndexObs = null;
    // cutoffOffset >= 1, so loop always runs at least once
    for (int i = 0; i < cutoffOffset; i++) {
      lastNonCutoffFixing = computation.getFixingCalendar().previous(lastNonCutoffFixing);
      lastIndexObs = computation.observeOn(lastNonCutoffFixing);
      accrualFactorTotal += lastIndexObs.getYearFraction();
      cutoffAccrualFactor += lastIndexObs.getYearFraction();
    }
    double forwardRateCutOff = rates.rate(lastIndexObs);
    accumulatedInterest += cutoffAccrualFactor * forwardRateCutOff;
    LocalDate currentFixingNonCutoff = computation.getStartDate();
    while (currentFixingNonCutoff.isBefore(lastNonCutoffFixing)) {
      // All dates involved in the period are computed. Potentially slow.
      // The fixing periods are added as long as their start date is (strictly) before the no cutoff period end-date.
      OvernightIndexObservation indexObs = computation.observeOn(currentFixingNonCutoff);
      double forwardRate = rates.rate(indexObs);
      accrualFactorTotal += indexObs.getYearFraction();
      accumulatedInterest += indexObs.getYearFraction() * forwardRate;
      currentFixingNonCutoff = computation.getFixingCalendar().next(currentFixingNonCutoff);
    }
    // final rate
    return accumulatedInterest / accrualFactorTotal;
  }

  public  ForwardOvernightAveragedRateComputationFn();

}