/**
 * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.financial.generator;

import javax.time.calendar.LocalDate;
import javax.time.calendar.ZonedDateTime;

import com.opengamma.financial.analytics.ircurve.CurveSpecificationBuilderConfiguration;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.financial.convention.daycount.DayCountFactory;
import com.opengamma.financial.convention.frequency.Frequency;
import com.opengamma.financial.convention.frequency.SimpleFrequency;
import com.opengamma.financial.security.capfloor.CapFloorSecurity;
import com.opengamma.id.ExternalId;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.Tenor;

/**
 * Source of random, but reasonable, Cap/Floor securities.
 */
public class CapFloorSecurityGenerator extends SecurityGenerator<CapFloorSecurity> {

  private static final DayCount[] DAY_COUNT = new DayCount[] {DayCountFactory.INSTANCE.getDayCount("Act/360"), DayCountFactory.INSTANCE.getDayCount("30U/360") };
  private static final Frequency[] FREQUENCY = new Frequency[] {SimpleFrequency.QUARTERLY, SimpleFrequency.SEMI_ANNUAL, SimpleFrequency.ANNUAL };
  private static final Tenor[] TENORS = new Tenor[] {Tenor.TWO_YEARS, Tenor.FIVE_YEARS, Tenor.ofYears(10), Tenor.ofYears(20) };

  protected String createName(final boolean ibor, final boolean cap, final double strike, final ZonedDateTime startDate, final ZonedDateTime maturityDate, final Frequency frequency,
      final Currency currency, final double notional) {
    final StringBuilder sb = new StringBuilder();
    sb.append(ibor ? "Ibor " : "CMS ");
    sb.append(cap ? "cap " : "floor");
    sb.append(" @ ").append(strike).append(" [").append(startDate.toString(DATE_FORMATTER)).append(" - ").append(maturityDate.toString(DATE_FORMATTER)).append("], ");
    sb.append(frequency.getConventionName()).append(", ").append(currency.getCode()).append(' ').append(NOTIONAL_FORMATTER.format(notional));
    return sb.toString();
  }

  private ExternalId getUnderlying(final Currency ccy, final LocalDate tradeDate, final Tenor tenor, final boolean ibor) {
    final CurveSpecificationBuilderConfiguration curveSpecConfig = getCurrencyCurveConfig(ccy);
    if (curveSpecConfig == null) {
      return null;
    }
    if (ibor) {
      return curveSpecConfig.getLiborSecurity(tradeDate, tenor);
    } else {
      if (ccy.equals(Currency.USD)) {
        return curveSpecConfig.getSwap3MSecurity(tradeDate, tenor);
      } else {
        return curveSpecConfig.getSwap6MSecurity(tradeDate, tenor);
      }
    }
  }

  @Override
  public CapFloorSecurity createSecurity() {
    final Currency currency = getRandomCurrency();
    final boolean payer = getRandom().nextBoolean();
    final boolean cap = getRandom().nextBoolean();
    final boolean ibor = getRandom().nextBoolean();
    final ZonedDateTime startDate = previousWorkingDay(ZonedDateTime.now().minusDays(getRandom(365) + 7), currency);
    final int length = getRandom(22) + 3;
    final ZonedDateTime maturityDate = nextWorkingDay(startDate.plusYears(length), currency);
    final double notional = (double) getRandom(100000) * 1000;
    final ExternalId underlyingIdentifier = getUnderlying(currency, startDate.toLocalDate(), getRandom(TENORS), ibor);
    if (underlyingIdentifier == null) {
      return null;
    }
    final double strike = 0.01 + (double) getRandom(6) / 200;
    final Frequency frequency = getRandom(FREQUENCY);
    final DayCount dayCount = getRandom(DAY_COUNT);
    final CapFloorSecurity capFloor = new CapFloorSecurity(startDate, maturityDate, notional, underlyingIdentifier, strike, frequency, currency, dayCount, payer, cap, ibor);
    capFloor.setName(createName(ibor, cap, strike, startDate, maturityDate, frequency, currency, notional));
    return capFloor;
  }

}

@@ -256,16 +256,74 @@
 eTime;%0A%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0A
 import c
@@ -403,16 +403,16 @@
 ration;%0A
-
 import c
@@ -999,16 +999,118 @@
 urity%3E %7B
+%0A  %0A  private static final Logger s_logger = LoggerFactory.getLogger(CapFloorSecurityGenerator.class);
 %0A%0A  priv
@@ -1538,16 +1538,396 @@
 s(20) %7D;
+%0A  private static final Tenor%5B%5D IBOR_TENORS = new Tenor%5B%5D %7BTenor.ONE_DAY, Tenor.TWO_DAYS, Tenor.THREE_DAYS, Tenor.ofDays(7), Tenor.ofDays(14), Tenor.ofDays(21), %0A    Tenor.ONE_MONTH, Tenor.TWO_MONTHS, Tenor.THREE_MONTHS, Tenor.FOUR_MONTHS, Tenor.FIVE_MONTHS, Tenor.SIX_MONTHS, Tenor.SEVEN_MONTHS, Tenor.EIGHT_MONTHS, %0A    Tenor.NINE_MONTHS, Tenor.TEN_MONTHS, Tenor.ELEVEN_MONTHS%7D;
 %0A%0A  prot
@@ -3792,22 +3792,16 @@
 00;%0A    
-final 
 External
@@ -3802,16 +3802,130 @@
 ternalId
+ underlyingIdentifier = null;%0A    Tenor tenor = ibor ? getRandom(IBOR_TENORS) : getRandom(TENORS);%0A    try %7B%0A     
  underly
@@ -3989,33 +3989,21 @@
 Date(), 
-getRandom(TENORS)
+tenor
 , ibor);
@@ -3999,24 +3999,26 @@
 nor, ibor);%0A
+  
     if (unde
@@ -4037,32 +4037,211 @@
 fier == null) %7B%0A
+        return null;%0A      %7D%0A    %7D catch (Exception ex) %7B%0A      s_logger.warn(%22Unable to obtain underlying id for %22 + currency + %22 %22 + startDate.toLocalDate() + %22 %22 + tenor, ex);%0A
       return nul

use tenors within 1year for LIBOR rates