public ZeroCouponInflationSwapHelper(
            Handle <Quote> quote,
            Period swapObsLag, // lag on swap observation of index
            Date maturity,
            Calendar calendar, // index may have null calendar as valid on every day
            BusinessDayConvention paymentConvention,
            DayCounter dayCounter,
            ZeroInflationIndex zii)
            : base(quote)
        {
            swapObsLag_        = swapObsLag;
            maturity_          = maturity;
            calendar_          = calendar;
            paymentConvention_ = paymentConvention;
            dayCounter_        = dayCounter;
            zii_ = zii;

            if (zii_.interpolated())
            {
                // if interpolated then simple
                earliestDate_ = maturity_ - swapObsLag_;
                latestDate_   = maturity_ - swapObsLag_;
            }
            else
            {
                // but if NOT interpolated then the value is valid
                // for every day in an inflation period so you actually
                // get an extended validity, however for curve building
                // just put the first date because using that convention
                // for the base date throughout
                KeyValuePair <Date, Date> limStart = Utils.inflationPeriod(maturity_ - swapObsLag_,
                                                                           zii_.frequency());
                earliestDate_ = limStart.Key;
                latestDate_   = limStart.Key;
            }

            // check that the observation lag of the swap
            // is compatible with the availability lag of the index AND
            // it's interpolation (assuming the start day is spot)
            if (zii_.interpolated())
            {
                Period pShift = new Period(zii_.frequency());
                Utils.QL_REQUIRE((swapObsLag_ - pShift) > zii_.availabilityLag(), () =>
                                 "inconsistency between swap observation of index "
                                 + swapObsLag_ +
                                 " index availability " + zii_.availabilityLag() +
                                 " index period " + pShift +
                                 " and index availability " + zii_.availabilityLag() +
                                 " need (obsLag-index period) > availLag");
            }
            Settings.Instance.registerWith(update);
        }
        /* Generally inflation indices are available with a lag of 1month
         * and then observed with a lag of 2-3 months depending whether
         * they use an interpolated fixing or not.  Here, we make the
         * swap use the interpolation of the index to avoid incompatibilities.
         */
        public ZeroCouponInflationSwap(Type type,
                                       double nominal,
                                       Date startDate, // start date of contract (only)
                                       Date maturity,  // this is pre-adjustment!
                                       Calendar fixCalendar,
                                       BusinessDayConvention fixConvention,
                                       DayCounter dayCounter,
                                       double fixedRate,
                                       ZeroInflationIndex infIndex,
                                       Period observationLag,
                                       bool adjustInfObsDates = false,
                                       Calendar infCalendar   = null,
                                       BusinessDayConvention?infConvention = null)
            : base(2)
        {
            type_              = type;
            nominal_           = nominal;
            startDate_         = startDate;
            maturityDate_      = maturity;
            fixCalendar_       = fixCalendar;
            fixConvention_     = fixConvention;
            fixedRate_         = fixedRate;
            infIndex_          = infIndex;
            observationLag_    = observationLag;
            adjustInfObsDates_ = adjustInfObsDates;
            infCalendar_       = infCalendar;
            dayCounter_        = dayCounter;

            // first check compatibility of index and swap definitions
            if (infIndex_.interpolated())
            {
                Period pShift = new Period(infIndex_.frequency());
                Utils.QL_REQUIRE(observationLag_ - pShift > infIndex_.availabilityLag(), () =>
                                 "inconsistency between swap observation of index " + observationLag_ +
                                 " index availability " + infIndex_.availabilityLag() +
                                 " interpolated index period " + pShift +
                                 " and index availability " + infIndex_.availabilityLag() +
                                 " need (obsLag-index period) > availLag");
            }
            else
            {
                Utils.QL_REQUIRE(infIndex_.availabilityLag() < observationLag_, () =>
                                 "index tries to observe inflation fixings that do not yet exist: "
                                 + " availability lag " + infIndex_.availabilityLag()
                                 + " versus obs lag = " + observationLag_);
            }

            if (infCalendar_ == null)
            {
                infCalendar_ = fixCalendar_;
            }
            if (infConvention == null)
            {
                infConvention_ = fixConvention_;
            }
            else
            {
                infConvention_ = infConvention.Value;
            }

            if (adjustInfObsDates_)
            {
                baseDate_ = infCalendar_.adjust(startDate - observationLag_, infConvention_);
                obsDate_  = infCalendar_.adjust(maturity - observationLag_, infConvention_);
            }
            else
            {
                baseDate_ = startDate - observationLag_;
                obsDate_  = maturity - observationLag_;
            }

            Date infPayDate   = infCalendar_.adjust(maturity, infConvention_);
            Date fixedPayDate = fixCalendar_.adjust(maturity, fixConvention_);

            // At this point the index may not be able to forecast
            // i.e. do not want to force the existence of an inflation
            // term structure before allowing users to create instruments.
            double T = Utils.inflationYearFraction(infIndex_.frequency(), infIndex_.interpolated(),
                                                   dayCounter_, baseDate_, obsDate_);
            // N.B. the -1.0 is because swaps only exchange growth, not notionals as well
            double fixedAmount = nominal * (Math.Pow(1.0 + fixedRate, T) - 1.0);

            legs_[0].Add(new SimpleCashFlow(fixedAmount, fixedPayDate));
            bool growthOnly = true;

            legs_[1].Add(new IndexedCashFlow(nominal, infIndex, baseDate_, obsDate_, infPayDate, growthOnly));

            for (int j = 0; j < 2; ++j)
            {
                legs_[j].ForEach((i, x) => x.registerWith(update));
            }

            switch (type_)
            {
            case Type.Payer:
                payer_[0] = +1.0;
                payer_[1] = -1.0;
                break;

            case Type.Receiver:
                payer_[0] = -1.0;
                payer_[1] = +1.0;
                break;

            default:
                Utils.QL_FAIL("Unknown zero-inflation-swap type");
                break;
            }
        }