#pragma once

#include "GaussianExpectationLib.h"
#include "../general_model/TimeSliceProcess.h"
#include "../general_model/MFMBase.h"
#include "../1_dimensional/Function1d.h"
#include "../generic/Algorithm.h"
#include "option_pricer/HullWhiteOptionPricer.h"
#include "option_pricer/CapletOptionPricer.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Stores data of a random process X at discrete time step X_Ti, which is driven by some currency
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class InterestRateTimeSliceProcess : public TimeSliceProcess
{

protected:

	std::string m_ub_error;

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// D_{0T_1}
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	double m_t1_discount_factor;

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// D_{0T_i}
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	double m_discount_factor;

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// alpha_i 
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	double m_accrual_factor;

	InterestRateTimeSliceProcess(std::unique_ptr<TimeSliceProcess>  base_process, std::unique_ptr<OptionPricer> pricer, double accrual_factor, double discount_factor, double t1_discount_factor);

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Hull white option pricer
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	InterestRateTimeSliceProcess(std::unique_ptr<TimeSliceProcess> base_process, const std::string& ub_error, double beta, double mux_price, double muy_price, double Cxx_price, double Cyy_price, double Cxy_price, double accrual_factor, double discount_factor, double t1_discount_factor);

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// General option pricer
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	InterestRateTimeSliceProcess(std::unique_ptr<TimeSliceProcess>  base_process, const std::string& ub_error, double time, double this_caplet_volatility, double this_fwd_libor, double accrual_factor, double discount_factor, double t1_discount_factor);

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// static constructors
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	static std::unique_ptr<InterestRateTimeSliceProcess> construct(std::unique_ptr<TimeSliceProcess>  base_process, const std::string& ub_error, double time, double this_caplet_volatility, double this_fwd_libor, double accrual_factor, double discount_factor, double t1_discount_factor);

	static std::unique_ptr<InterestRateTimeSliceProcess> construct(std::unique_ptr<TimeSliceProcess>  base_process, const std::string& ub_error, double beta, double mux_price, double muy_price, double Cxx_price, double Cyy_price, double Cxy_price, double accrual_factor, double discount_factor, double t1_discount_factor);

public:

	double get_t1_discount_factor() const;

	double get_discount_factor() const;

	double get_accrual_factor() const;

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Construct this process in a sequence of contiguous time slices - General Libor in arrears formula is employed
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	static std::vector<std::unique_ptr<InterestRateTimeSliceProcess>> construct(
		double grid_spread, size_t number_of_gridpoints, const MFMBase* model,
		double mean_reversion_param, gelib::d_vector const& times, gelib::d_vector const& process_volatilities_squared, gelib::d_vector const& process_variances,
		gelib::d_vector const& forward_libors, gelib::d_vector const& caplet_volatilities, gelib::d_vector const& accrual_factors, double t1_discount_factor);

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Construct this process in a sequence of contiguous time slices 
	// The constructed processes will calculate LIA call options by employing a Hull-White model controlled by the last
	// 5 parameters at each time slice
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	static std::vector<std::unique_ptr<InterestRateTimeSliceProcess>> construct(
		double grid_spread, size_t number_of_gridpoints, const MFMBase* model, double mean_reversion_param, gelib::d_vector const& times, gelib::d_vector const& forward_libors, gelib::d_vector const& process_volatilities_squared, gelib::d_vector const& process_variances, gelib::d_vector const& accrual_factors, double t1_discount_factor, gelib::d_vector const& mux_price, gelib::d_vector const& muy_price, gelib::d_vector const& Cxx_price, gelib::d_vector const& Cyy_price, gelib::d_vector const& Cxy_price);

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Check the constructor variable for obvious errors
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	static void constructor_check(
		double grid_spread, size_t number_of_gridpoints, double mean_reversion_param,
		gelib::d_vector const& process_volatilities_squared, double discount_factor_t1, gelib::d_vector const& forward_libors,
		gelib::d_vector const& caplet_volatilities, gelib::d_vector const& accrual_factors);

};