#include<ql/quantlib.hpp>
#include "analytic_cont_arith_av_price.h"
#include<string>

using namespace QuantLib;
using namespace std;

Month numericToMonth(int);

int main()
{
	cout<<"Enter Put or Call: \t\t\t";
	string type;
	cin>>type;

	Option::Type optionType;

	if(type=="Call")
		optionType=Option::Call;
	else if(type=="Put")
		optionType=Option::Put;
	else
	{
		cout<<"Unknown type, ending program"<<endl;
		return 1;
	}
	
	cout<<"Enter Strike: \t\t\t\t";
	Real strike;
	cin>>strike;

	cout<<"Enter Price of underlying: \t\t";
	Real underlying;
	cin>>underlying;

	cout<<"Enter Risk Free Rate: \t\t\t";
	Rate riskFreeRate;
	cin>>riskFreeRate;

	cout<<"Enter Dividend Yield: \t\t\t";
	Rate dividendYield;
	cin>>dividendYield;

	cout<<"Enter Volatility: \t\t\t";
	Volatility volatility;
	cin>>volatility;

	cout<<"Enter Expiration Date (d m yyyy): \t";
	Day d;
	int m;
	Year y;
	cin>>d>>m>>y;

	Month month=January;
	month=numericToMonth(m);

	Date expirationDate(d,month,y);

	cout<<"Enter Todays Date (d m yyyy): \t\t";
	cin>>d>>m>>y;

	month=numericToMonth(m);

	Date todaysDate(d,month,y);

	DayCounter dayCounter=Actual365Fixed();
	Time maturity=dayCounter.yearFraction(todaysDate,expirationDate);

	cout << "option type = "  << OptionTypeFormatter::toString(optionType)
                  << endl;
    cout << "Time to maturity = "        << maturity
                  << endl;
    cout << "Underlying price = "        << underlying
                  << endl;
    cout << "Strike = "                  << strike
                  << endl;
    cout << "Risk-free interest rate = " << riskFreeRate
                  << endl;
    cout << "dividend yield = " << dividendYield
                  << endl;
    cout << "Volatility = "              << volatility
                  << endl;
    cout <<endl;

	boost::shared_ptr<StrikedTypePayoff> payoff(new PlainVanillaPayoff(optionType, strike));

	boost::shared_ptr<Exercise> euroExercise(new EuropeanExercise(expirationDate));
	boost::shared_ptr<Exercise> amExercise(new AmericanExercise(todaysDate,
		expirationDate));

	Handle<Quote> underlyingH(boost::shared_ptr<Quote>(new SimpleQuote(underlying)));

	Handle<YieldTermStructure> flatTermStructure(boost::shared_ptr<YieldTermStructure>(
		new FlatForward(todaysDate,riskFreeRate,dayCounter)));
	Handle<YieldTermStructure> flatDividendTS(boost::shared_ptr<YieldTermStructure>(
		new FlatForward(todaysDate,dividendYield,dayCounter)));
	Handle<BlackVolTermStructure> flatVolTS(boost::shared_ptr<BlackVolTermStructure>(
		new BlackConstantVol(todaysDate,volatility,dayCounter)));


	boost::shared_ptr<BlackScholesProcess> stochasticProcess(new BlackScholesProcess(
		underlyingH,flatDividendTS,flatTermStructure,flatVolTS));

	boost::shared_ptr<PricingEngine> engine(new AnalyticEuropeanEngine());

	VanillaOption euroOption(stochasticProcess,payoff,euroExercise,
		engine);

	Real value;

	value=euroOption.NPV();

	cout<<"The price of the European Option is: \t\t"<<value<<endl;

	VanillaOption amOption(stochasticProcess,payoff,amExercise);

	Size timeSteps=500;

	amOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
		new BinomialVanillaEngine<CoxRossRubinstein>(timeSteps)));

	value=amOption.NPV();

	cout<<"The price of the American Option via CRR is: \t"<<value<<endl;
	

	amOption.setPricingEngine(boost::shared_ptr<PricingEngine>(
		new BinomialVanillaEngine<JarrowRudd>(timeSteps)));

	value=amOption.NPV();

	cout<<"The price of the American Option via JR is: \t"<<value<<endl;

	Average::Type asianType=Average::Geometric;

	boost::shared_ptr<StrikedTypePayoff> asianPayoff(new 
		PlainVanillaPayoff(optionType,strike));

	ContinuousAveragingAsianOption geometricAsianOption(asianType,stochasticProcess,
		asianPayoff,euroExercise);

	geometricAsianOption.setPricingEngine(boost::shared_ptr<PricingEngine>
		(new AnalyticContinuousGeometricAveragePriceAsianEngine()));

	value=geometricAsianOption.NPV();

	cout<<"The price of the Geometric Asian Option is: \t"<<value<<endl;

	asianType=Average::Arithmetic;

	ContinuousAveragingAsianOption arithmeticAsianOption(asianType,stochasticProcess,
		asianPayoff,euroExercise);


		arithmeticAsianOption.setPricingEngine(boost::shared_ptr<PricingEngine>
		(new AnalyticContinuousArithmeticAveragePriceAsianEngine()));

	value=arithmeticAsianOption.NPV();

	cout<<"The price of the Arithmetic Asian Option is: \t"<<value<<endl;

	return 0;



	

	}

Month numericToMonth(int m){
	Month month;

	switch(m)
	{
	case 1: month=January; 
		break;
	case 2: month=February;
		break;
	case 3: month=March;
		break;
	case 4: month=April;
		break;
	case 5: month=May;
		break;
	case 6: month=June;
		break;
	case 7: month=July;
		break;
	case 8: month=August;
		break;
	case 9: month=September;
		break;
	case 10: month=October;
		break;
	case 11: month=November;
		break;
	case 12: month=December;
		break;
	default: ;
	}

	return month;
}
