class BondSecurityDiscountingMethod {

  public double modifiedDurationFromYield(final BondFixedSecurity bond, final double yield) {
    final int nbCoupon = bond.getCoupon().getNumberOfPayments();
    //    final double nominal = bond.getNominal().getNthPayment(bond.getNominal().getNumberOfPayments() - 1).getAmount();
    final YieldConvention yieldConvention = bond.getYieldConvention();
    if (nbCoupon == 1) {
      if (yieldConvention.equals(US_STREET) || yieldConvention.equals(GERMAN_BOND) || yieldConvention.equals(ITALY_TREASURY_BONDS)
          || yieldConvention.equals(AUSTRALIA_EX_DIVIDEND) || yieldConvention.equals(MEXICAN_BONOS)) {
        return bond.getFactorToNextCoupon() / bond.getCouponPerYear() / (1.0 + bond.getFactorToNextCoupon() * yield / bond.getCouponPerYear());
      }
      if (yieldConvention.equals(FRANCE_COMPOUND_METHOD)) {
        return bond.getFactorToNextCoupon() / bond.getCouponPerYear() / (1.0 + yield / bond.getCouponPerYear());
      }
    }
    if (yieldConvention.equals(US_STREET) || yieldConvention.equals(UK_BUMP_DMO_METHOD) || yieldConvention.equals(GERMAN_BOND)
        || (yieldConvention.equals(FRANCE_COMPOUND_METHOD)) || (yieldConvention.equals(AUSTRALIA_EX_DIVIDEND))) {
      return modifiedDurationFromYieldStandard(bond, yield);
    }
    if (yieldConvention.equals(ITALY_TREASURY_BONDS)) {
      final double yieldSemiAnnual = (Math.sqrt(1 + yield) - 1) * 2;
      final double modifiedDurationSemiAnnual = modifiedDurationFromYieldStandard(bond, yieldSemiAnnual);
      final double modifiedDuration = modifiedDurationSemiAnnual / Math.sqrt(1 + yield);
      return modifiedDuration;
    }
    throw new UnsupportedOperationException("The convention " + yieldConvention.getName() + " is not supported for modified duration computation.");
  }

  private  BondSecurityDiscountingMethod();

}