#include "SpreadFactory3d.h"

void SpreadFactory3d::calculate_spread(gelib::d_cube& spread, const std::function<double(size_t, size_t)>& value_func, size_t fixed_dim1, size_t fixed_dim2, size_t varied_dim)
{

	gelib::d_vector fill_vector;
	double fill_val;
	fill_vector.resize(spread.get_dimension_size(varied_dim));

	std::array<int, 3> index = { -1, -1, -1 };

	for (size_t i = 0; i < spread.get_dimension_size(fixed_dim1); ++i)
	{
		for (size_t j = 0; j < spread.get_dimension_size(fixed_dim2); ++j)
		{
			fill_val = value_func(i, j);
			std::fill(fill_vector.begin(), fill_vector.end(), fill_val);
			index[fixed_dim1] = (int) i;
			index[fixed_dim2] = (int) j;
			spread.insert_vector(index, fill_vector);

		}
	}

}

void SpreadFactory3d::calculate_dom_fx_spread(gelib::d_cube& spread, double A, double B, const InterestRateTimeSliceProcess* dom_process, const FXTimeSliceProcess* fx_process, const InterestRateTimeSliceProcess* for_process)
{
	const std::function<double(size_t, size_t)> value_func = [&](size_t i, size_t j)
	{
		return A * (1.0 + dom_process->get_accrual_factor() * dom_process->get_spot(i)) - B * fx_process->get_spot(j);
	};

	spread.resize(dom_process->get_grid()->size(), fx_process->get_grid()->size(), for_process->get_grid()->size());

	calculate_spread(spread,
		value_func,
		0, 1, 2);
}

void SpreadFactory3d::calculate_fgn_fx_spread(gelib::d_cube& spread, double A, double B, const InterestRateTimeSliceProcess* dom_process, const FXTimeSliceProcess* fx_process, const InterestRateTimeSliceProcess* for_process)
{
	const std::function<double(size_t, size_t)> value_func = [&](size_t i, size_t j)
	{
		return A * (1.0 + for_process->get_accrual_factor() * for_process->get_spot(i)) - B * fx_process->get_spot(j);
	};

	spread.resize(dom_process->get_grid()->size(), fx_process->get_grid()->size(), for_process->get_grid()->size());

	calculate_spread(spread,
		value_func,
		2, 1, 0);
}

void SpreadFactory3d::calculate_dom_fgn_spread(gelib::d_cube& spread, double A, double B, const InterestRateTimeSliceProcess* dom_process, const FXTimeSliceProcess* fx_process, const InterestRateTimeSliceProcess* for_process)
{
	const std::function<double(size_t, size_t)> value_func = [&](size_t i, size_t j)
	{
		return A * (1.0 + dom_process->get_accrual_factor() * dom_process->get_spot(i)) - B * (1.0 + for_process->get_accrual_factor() * for_process->get_spot(j));
	};

	spread.resize(dom_process->get_grid()->size(), fx_process->get_grid()->size(), for_process->get_grid()->size());

	calculate_spread(spread,
		value_func,
		0, 2, 1);
}
