/*
 Copyright (C) 2007 Ueli Hofstetter

 This source code is release under the BSD License.

 This file is part of JQuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://jquantlib.org/

 JQuantLib is free software: you can redistribute it and/or modify it
 under the terms of the JQuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 . The license is also available online at
 .

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.

 JQuantLib is based on QuantLib. http://quantlib.org/
 When applicable, the original copyright notice follows this notice.
 */

/*
 Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb
 Copyright (C) 2006 Ferdinando Ametrano
 Copyright (C) 2006 Fran�ois du Vignaud
 Copyright (C) 2006, 2007 StatPro Italia srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 . The license is also available online at
 .

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

package org.jquantlib.instruments;

import java.util.List;

import org.jquantlib.QL;
import org.jquantlib.Settings;
import org.jquantlib.cashflow.CashFlow;
import org.jquantlib.cashflow.CashFlows;
import org.jquantlib.cashflow.FloatingRateCoupon;
import org.jquantlib.cashflow.Leg;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.pricingengines.PricingEngine;
import org.jquantlib.quotes.Handle;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.time.Date;

/**
 * Base class for cap-like instruments
 *
 * @category instruments
 *
 * @author Ueli Hofstetter
 */
public class CapFloor extends Instrument {

    public enum Type { Cap, Floor, Collar };

    private final Type type_;
    private final Leg floatingLeg_;
    private List capRates_;
    private List floorRates_;
    private final Handle termStructure_;

    public CapFloor(
            final CapFloor.Type type,
            final Leg floatingLeg,
            final List capRates,
            final List floorRates,
            final Handle termStructure,
            final PricingEngine engine){

    	QL.validateExperimentalMode();
    	
        this.type_ = type;
        this.floatingLeg_ = floatingLeg;
        this.capRates_ = capRates;
        this.floorRates_ = floorRates;
        this.termStructure_ = termStructure;

        setPricingEngine(engine);



        if (type_ == Type.Cap || type_ == Type.Collar) {
            QL.require(capRates_.size()>0 , "no cap rates given"); // TODO: message
            // capRates_.reserve(floatingLeg_.size());
            while (capRates_.size() < floatingLeg_.size()) {
                // this looks kind of suspicious...
                capRates_.add(capRates_.get(capRates_.size() - 1));
            }
        }

        if (type_ == Type.Floor || type_ == Type.Collar) {
            QL.require(floorRates_.size()>0 , "no floor rates given"); // TODO: message
            // floorRates_.reserve(floatingLeg_.size());
            while (floorRates_.size() < floatingLeg_.size()) {
                floorRates_.add(floorRates_.get(floorRates_.size() - 1));
            }
        }

        final Date evaluationDate = new Settings().evaluationDate();
        for (final CashFlow cashFlow : floatingLeg_) {
            cashFlow.addObserver(this);
        }

        // TODO: code review :: please verify against QL/C++ code
        // seems like we should have this.evaluationDate

        this.termStructure_.addObserver(this);
        evaluationDate.addObserver(this);
    }

    public CapFloor(
            final Type type,
            final Leg floatingLeg,
            final List strikes,
            final Handle termStructure,
            final PricingEngine engine){

        if (System.getProperty("EXPERIMENTAL") == null)
            throw new UnsupportedOperationException("Work in progress");

        this.type_ = type;
        this.floatingLeg_ = floatingLeg;
        this.termStructure_ = termStructure;

        setPricingEngine(engine);

        QL.require(strikes.size()>0 , "no strikes given"); // TODO: message
        if (type_ == Type.Cap) {
            capRates_ = strikes;
            //capRates_.reserve(floatingLeg_.size());
            while (capRates_.size() < floatingLeg_.size()) {
                capRates_.add(capRates_.get(capRates_.size()-1));
            }
        } else if (type_ == Type.Floor) {
            floorRates_ = strikes;
            //floorRates_.reserve(floatingLeg_.size());
            while (floorRates_.size() < floatingLeg_.size()) {
                floorRates_.add(floorRates_.get(floorRates_.size()-1));
            }
        } else
            throw new LibraryException("only Cap/Floor types allowed in this constructor"); // TODO: message

        final Date evaluationDate = new Settings().evaluationDate();
        for (final CashFlow cashFlow : floatingLeg_) {
            cashFlow.addObserver(this);
        }

        // TODO: code review :: please verify against QL/C++ code
        // Seems like we should have this.evaluationDate

        this.termStructure_.addObserver(this);
        evaluationDate.addObserver(this);
    }

    public /*@Rate*/double atmRate(){
        return CashFlows.getInstance().atmRate(floatingLeg_, termStructure_);
    }

    @Override
    public boolean isExpired(){
        Date lastPaymentDate = Date.minDate();
        for (int i=0; i(args);
    //   QL_REQUIRE(arguments != 0, "wrong argument type");
    //
    //   Size n = floatingLeg_.size();
    //
    //   arguments->startTimes.clear();
    //   arguments->startTimes.reserve(n);
    //
    //   arguments->fixingDates.clear();
    //   arguments->fixingDates.reserve(n);
    //
    //   arguments->fixingTimes.clear();
    //   arguments->fixingTimes.reserve(n);
    //
    //   arguments->endTimes.clear();
    //   arguments->endTimes.reserve(n);
    //
    //   arguments->accrualTimes.clear();
    //   arguments->accrualTimes.reserve(n);
    //
    //   arguments->forwards.clear();
    //
    //   arguments->discounts.clear();
    //
    //   arguments->nominals.clear();
    //   arguments->nominals.reserve(n);
    //
    //   arguments->gearings.clear();
    //   arguments->gearings.reserve(n);
    //
    //   arguments->capRates.clear();
    //
    //   arguments->floorRates.clear();
    //
    //   arguments->type = type_;
    //
    //   Date today = Settings::instance().evaluationDate();
    //   Date settlement = termStructure_->referenceDate();
    //   DayCounter counter = termStructure_->dayCounter();
    //
    //   for (Size i=0; i coupon =
    //           boost::dynamic_pointer_cast(floatingLeg_[i]);
    //       QL_REQUIRE(coupon, "non-iborCoupon given");
    //       Date beginDate = coupon->accrualStartDate();
    //       Time time = counter.yearFraction(settlement, beginDate);
    //       arguments->startTimes.push_back(time);
    //       Date fixingDate = coupon->fixingDate();
    //       arguments->fixingDates.push_back(fixingDate);
    //       time = counter.yearFraction(today, fixingDate);
    //       arguments->fixingTimes.push_back(time);
    //       time = counter.yearFraction(settlement, coupon->date());
    //       arguments->endTimes.push_back(time);
    //       // this is passed explicitly for precision
    //       arguments->accrualTimes.push_back(coupon->accrualPeriod());
    //       // this is passed explicitly for precision
    //       if (arguments->endTimes.back() >= 0.0) { // but only if needed
    //           arguments->forwards.push_back(coupon->adjustedFixing());
    //           arguments->discounts.push_back(
    //                             termStructure_->discount(coupon->date()));
    //       } else {
    //           arguments->forwards.push_back(Null());
    //           arguments->discounts.push_back(Null());
    //       }
    //       arguments->nominals.push_back(coupon->nominal());
    //       Spread spread = coupon->spread();
    //       Real gearing = coupon->gearing();
    //       QL_REQUIRE(gearing > 0.0, "positive gearing required");
    //       arguments->gearings.push_back(gearing);
    //       arguments->spreads.push_back(spread);
    //       if (type_ == Cap || type_ == Collar)
    //           arguments->capRates.push_back((capRates_[i]-spread)/gearing);
    //       if (type_ == Floor || type_ == Collar)
    //           arguments->floorRates.push_back(
    //                                        (floorRates_[i]-spread)/gearing);
    //   }
    //}

    //void CapFloor::arguments::validate() const {
    //   QL_REQUIRE(endTimes.size() == startTimes.size(),
    //              "number of start times (" << startTimes.size()
    //              << ") different from that of end times ("
    //              << endTimes.size() << ")");
    //   QL_REQUIRE(accrualTimes.size() == startTimes.size(),
    //              "number of start times (" << startTimes.size()
    //              << ") different from that of accrual times ("
    //              << accrualTimes.size() << ")");
    //   QL_REQUIRE(type == CapFloor::Floor ||
    //              capRates.size() == startTimes.size(),
    //              "number of start times (" << startTimes.size()
    //              << ") different from that of cap rates ("
    //              << capRates.size() << ")");
    //   QL_REQUIRE(type == CapFloor::Cap ||
    //              floorRates.size() == startTimes.size(),
    //              "number of start times (" << startTimes.size()
    //              << ") different from that of floor rates ("
    //              << floorRates.size() << ")");
    //   QL_REQUIRE(gearings.size() == startTimes.size(),
    //              "number of start times (" << startTimes.size()
    //              << ") different from that of gearings ("
    //              << floorRates.size() << ")");
    //   QL_REQUIRE(nominals.size() == startTimes.size(),
    //              "number of start times (" << startTimes.size()
    //              << ") different from that of nominals ("
    //              << nominals.size() << ")");
    //}
    //
    //Volatility CapFloor::impliedVolatility(Real targetValue,
    //                                      Real accuracy,
    //                                      Size maxEvaluations,
    //                                      Volatility minVol,
    //                                      Volatility maxVol) const {
    //   calculate();
    //   QL_REQUIRE(!isExpired(), "instrument expired");
    //
    //   Volatility guess = 0.10;   // no way we can get a more accurate one
    //
    //   ImpliedVolHelper f(*this, termStructure_, targetValue);
    //   Brent solver;
    //   //NewtonSafe solver;
    //   solver.setMaxEvaluations(maxEvaluations);
    //   return solver.solve(f, accuracy, guess, minVol, maxVol);
    //}
    //
    //
    //CapFloor::ImpliedVolHelper::ImpliedVolHelper(
    //                         const CapFloor& cap,
    //                         const Handle& termStructure,
    //                         Real targetValue)
    //: termStructure_(termStructure), targetValue_(targetValue) {
    //
    //   vol_ = boost::shared_ptr(new SimpleQuote(0.0));
    //   Handle h(vol_);
    //   engine_ = boost::shared_ptr(new BlackCapFloorEngine(h));
    //   cap.setupArguments(engine_->getArguments());
    //
    //   results_ =
    //       dynamic_cast(engine_->getResults());
    //}
    //
    //Real CapFloor::ImpliedVolHelper::operator()(Volatility x) const {
    //   vol_->setValue(x);
    //   engine_->calculate();
    //   return results_->value-targetValue_;
    //}
    //
    //Real CapFloor::ImpliedVolHelper::derivative(Volatility x) const {
    //   vol_->setValue(x);
    //   engine_->calculate();
    //   return 0.0;
    //   //return results_->vega;
    //}
    //
    //std::ostream& operator<<(std::ostream& out, CapFloor::Type t) {
    //   switch (t) {
    //     case CapFloor::Cap:
    //       return out << "Cap";
    //     case CapFloor::Floor:
    //       return out << "Floor";
    //     case CapFloor::Collar:
    //       return out << "Collar";
    //     default:
    //       QL_FAIL("unknown CapFloor::Type (" << Integer(t) << ")");
    //   }
    //}







    @Override
    protected void performCalculations() throws ArithmeticException {
        // TODO Auto-generated method stub

    }
    @Override
    protected void setupArguments(final PricingEngine.Arguments arguments) {
        // TODO Auto-generated method stub

    }




    //    */
    //    class CapFloor : public Instrument {
    //      public:
    //        enum Type { Cap, Floor, Collar };
    //        class arguments;
    //        class engine;
    //        CapFloor(Type type,
    //                 const Leg& floatingLeg,
    //                 const std::vector& capRates,
    //                 const std::vector& floorRates,
    //                 const Handle& termStructure,
    //                 const boost::shared_ptr& engine);
    //        CapFloor(Type type,
    //                 const Leg& floatingLeg,
    //                 const std::vector& strikes,
    //                 const Handle& termStructure,
    //                 const boost::shared_ptr& engine);
    //        //! \name Instrument interface
    //        //@{
    //        bool isExpired() const;
    //        void setupArguments(PricingEngine::arguments*) const;
    //        //@}
    //        //! \name Inspectors
    //        //@{
    //        Type type() const { return type_; }
    //        const Leg& leg() const {
    //            return floatingLeg_;
    //        }
    //        const std::vector& capRates() const {
    //            return capRates_;
    //        }
    //        const std::vector& floorRates() const {
    //            return floorRates_;
    //        }
    //        const Leg& floatingLeg() const {
    //            return floatingLeg_;
    //        }
    //        Rate atmRate() const;
    //        Date startDate() const;
    //        Date maturityDate() const;
    //        Date lastFixingDate() const;
    //        //@}
    //        //! implied term volatility
    //        Volatility impliedVolatility(Real price,
    //                                     Real accuracy = 1.0e-4,
    //                                     Size maxEvaluations = 100,
    //                                     Volatility minVol = 1.0e-7,
    //                                     Volatility maxVol = 4.0) const;
    //      private:
    //        Type type_;
    //        Leg floatingLeg_;
    //        std::vector capRates_;
    //        std::vector floorRates_;
    //        Handle termStructure_;
    //        // helper class for implied USE_INDEXEDvolatility calculation
    //        class ImpliedVolHelper {
    //          public:
    //            ImpliedVolHelper(const CapFloor&,
    //                             const Handle&,
    //                             Real targetValue);
    //            Real operator()(Volatility x) const;
    //            Real derivative(Volatility x) const;
    //          private:
    //            boost::shared_ptr engine_;
    //            Handle termStructure_;
    //            Real targetValue_;
    //            boost::shared_ptr vol_;
    //            const Instrument::results* results_;
    //        };
    //    };
    //
    //    //! Concrete cap class
    //    /*! \ingroup instruments */
    //    class Cap : public CapFloor {
    //      public:
    //        Cap(const Leg& floatingLeg,
    //            const std::vector& exerciseRates,
    //            const Handle& termStructure,
    //            const boost::shared_ptr& engine)
    //        : CapFloor(CapFloor::Cap, floatingLeg,
    //                   exerciseRates, std::vector(),
    //                   termStructure, engine) {}
    //    };
    //
    //    //! Concrete floor class
    //    /*! \ingroup instruments */
    //    class Floor : public CapFloor {
    //      public:
    //        Floor(const Leg& floatingLeg,
    //              const std::vector& exerciseRates,
    //              const Handle& termStructure,
    //              const boost::shared_ptr& engine)
    //        : CapFloor(CapFloor::Floor, floatingLeg,
    //                   std::vector(), exerciseRates,
    //                   termStructure, engine) {}
    //    };
    //
    //    //! Concrete collar class
    //    /*! \ingroup instruments */
    //    class Collar : public CapFloor {
    //      public:
    //        Collar(const Leg& floatingLeg,
    //               const std::vector& capRates,
    //               const std::vector& floorRates,
    //               const Handle& termStructure,
    //               const boost::shared_ptr& engine)
    //        : CapFloor(CapFloor::Collar, floatingLeg, capRates, floorRates,
    //                   termStructure, engine) {}
    //    };
    //
    //
    //    //! %Arguments for cap/floor calculation
    //    class CapFloor::arguments : public virtual PricingEngine::arguments {
    //      public:
    //        arguments() : type(CapFloor::Type(-1)) {}
    //        CapFloor::Type type;
    //        std::vector 

Ads help maintain this website.