#pragma once

#include "../../general_model/TimeSliceCalibrator.h"
#include "../../generic/Algorithm.h"
#include "../../2_dimensional/Gaussian2d.h"
#include "../../random_process/InterestRateTimeSliceProcess.h"
#include "../../random_process/FXTimeSliceProcess.h"
#include "UsesHullWhiteJ0.h"

//////////////////////////////////////////////////////////////////////////////////////
// Hull white calibrator for 3 random processes
// Does not calculate 3d Arrow Debreu prices
//////////////////////////////////////////////////////////////////////////////////////
class HullWhiteCalibrator : public TimeSliceCalibrator, public UsesHullWhiteJ0
{

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// parameters to calculate J0x
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	gelib::d_vector m_calibration_factors;
	gelib::d_vector m_arrow_debreu;

	void calibrate_x(const InterestRateTimeSliceProcess* currency);

	void calibrate_x_T0(const InterestRateTimeSliceProcess* currency);

public:

	// This flag is used to indicate to compiler whether this class calculates Arrow Debreu prices
	static const bool ARROW_DEBREU_CALIBRATOR_3D = false;

	static std::unique_ptr<HullWhiteCalibrator> construct();

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Overrides to the general calibrator
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void initialise(const std::vector<size_t>& grid_sizes, const MFMBase* model) override;

	void calibrate(std::vector<std::unique_ptr<TimeSliceProcess>>& processes) override;

	void calibrate_at_T0(std::vector<std::unique_ptr<TimeSliceProcess>>& processes_at_T0) override;

	void calibrate_next(TimeSliceCalibrator& next_calibrator, std::vector<std::unique_ptr<TimeSliceProcess>>& current_processes, std::vector<std::unique_ptr<TimeSliceProcess>>& next_processes) override;

	void calculate_next_spot_values(std::vector<std::unique_ptr<TimeSliceProcess>>& next_processes) override;


	std::vector<double>& get() override;

};
