#include "MFM_Model_tests.h"

void MFM_Model_tests::GetModelDFs(gelib::d_vector* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread,*discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	mfm.get_discount_factors(*output);
}

bool MFM_Model_tests::GetModelDFsCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetModelxVariances(gelib::d_vector* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	mfm.get_variances(*output);
}

bool MFM_Model_tests::GetModelxVariancesCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetModelGridpoints(gelib::d_matrix* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	mfm.get_grids(*output);
}

bool MFM_Model_tests::GetModelGridpointsCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetModelConditionalMeans(gelib::d_matrix* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	mfm.get_conditional_means(*output);
}

bool MFM_Model_tests::GetModelConditionalMeansCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetDigitalCapletPrices(gelib::d_vector* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors, double* k)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	std::vector<const TimeSlice<SingleCurrencyCalibrator>*> slices;
	// retrieve all the timeslices from the model
	mfm.get_slices(slices);

	output->resize(slices.size());

	for (size_t i = 0; i < output->size(); ++i)
		(*output)[i] = mfm.digital_caplet_price(i, *k);
}

bool MFM_Model_tests::GetDigitalCapletPricesCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, gelib::d_vector* times, gelib::d_vector* forward_libors, gelib::d_vector* caplet_volatilities, gelib::d_vector* x_volatilities, gelib::d_vector* accrual_factors, double* k)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	if (*k <= 0)
		error = "Strike price should be positive.";

	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetModelJ0s(d_matrix* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	mfm.calibrate();
	mfm.get_J0_grids(*output);
}

bool MFM_Model_tests::GetModelJ0sCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetModelArrowDebreus(d_matrix* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	mfm.calibrate();
	mfm.get_ad_grids(*output);
}

bool MFM_Model_tests::GetModelArrowDebreusCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetModelLibors(d_matrix* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);
	mfm.calibrate();
	mfm.get_libor_grids(*output);
}

bool MFM_Model_tests::GetModelLiborsCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	return attach_check(error, exception_output);
}

void MFM_Model_tests::GetInverseDigitalCapletPrice(double* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors, int* which_slice, double* dcp)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	std::vector<const TimeSlice<SingleCurrencyCalibrator>*> slices;
	// retrieve all the timeslices from the model
	mfm.get_slices(slices);

	*output = mfm.digital_caplet_price_inverse((size_t) *which_slice, *dcp);
}

bool MFM_Model_tests::GetInverseDigitalCapletPriceCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors, int* which_slice, double* dcp)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	if (*dcp <= 0)
		error = "Digital caplet price should be positive.";

	if (((size_t) *which_slice < 1) || ((size_t) *which_slice > times->size()))
		error = "Invalid time slice number";

	return attach_check(error, exception_output);
}


void MFM_Model_tests::CalculateCapletValue(double* output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors, int* which_slice, double* strike_price)
{
	MFMSingleCurrency mfm(
		*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	mfm.calibrate();

	*output = mfm.value_caplet(*strike_price, (size_t) *which_slice);
}

bool MFM_Model_tests::CalculateCapletValueCheck(XLOPER12* exception_output, double* mean_reversion_parameter, int* gridpoints_per_slice, double* sd_spread, double* discount_factor_T1, int* poly_order, d_vector* times, d_vector* forward_libors, d_vector* caplet_volatilities, d_vector* x_volatilities, d_vector* accrual_factors, int* which_slice, double* strike_price)
{
	std::string error = MFMSingleCurrency::constructor_check(*mean_reversion_parameter, (size_t)*gridpoints_per_slice,
		*sd_spread, *discount_factor_T1, (size_t)*poly_order, *times,
		*forward_libors, *caplet_volatilities, *x_volatilities, *accrual_factors);

	if (error == "")
		error = MFMSingleCurrency::caplet_valuation_check(*strike_price, (size_t)*which_slice, times->size());

	return attach_check(error, exception_output);
}
