#pragma once

#include "Spline1d.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------------------------------------
// LIBRARY FUNCTIONS 
//--------------------------------------------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


namespace gelib
{

	using d_vector = gelib_impl::d_vector;
	using Spline1d = gelib_impl::Spline1d;

	/// <summary>
	/// Generate a vector of expectations \f$ E[f(X)] \f$  for \f$ X \sim N(\mu, \sigma) \f$
	/// for a corresponding vector of means, with sigma fixed.
	/// The function is defined by a piecewise-poynomial fitted on the data provided
	/// </summary>
	/// <param name="output">Output vector of expectations.</param>
	/// <param name="X">Grid points that piecewise-poynomial function is fitted on.</param>
	/// <param name="F_X">Function value on each grid point.</param>
	/// <param name="mu">Vector of means.</param>
	/// <param name="standard_deviation">Standard deviation.</param>
	/// <param name="l">Lower limit of integral.</param>
	/// <param name="h">Upper limit of integral.</param>
	/// <param name="order">Order of polynomials used in the fit.</param>
	/// <param name="boundaries">Extrapolation type, one of "zero", "constant", or "linear".</param>
	/// <param name="check_input">if set to <c>true</c> the function will throw exceptions on invalid input.</param>
	void gaussian_expectation_1d(d_vector& output,
		d_vector const& X, d_vector const& F_X,
		d_vector const& mu,
		double standard_deviation,
		double l, double h,
		size_t order, const std::string& extrapolation,
		bool check_input = true);

	std::string gaussian_expectation_1d_check(d_vector const& X, d_vector const& F_X, double standard_deviation, double l, double h, const std::string& boundaries);

	/// <summary>
	/// Generate a vector of expectations \f$ E[Max(f_{1}(X), f_{2}(X))] \f$  for \f$ X \sim N(\mu, \sigma) \f$
	/// for a corresponding vector of means, with sigma fixed.
	/// The functions are defined by a piecewise-poynomial fitted on the two sets of data provided
	/// </summary>
	/// <param name="output">Output vector of expectations.</param>
	/// <param name="X">Grid points that both piecewise-poynomial functions are fitted on.</param>
	/// <param name="F_X1">The function values for \f$ f_{1}\f$.</param>
	/// <param name="F_X2">The function values for \f$ f_{2}\f$.</param>
	/// <param name="mu">Vector of means.</param>
	/// <param name="standard_deviation">Standard deviation.</param>
	/// <param name="l">Lower limit of integral.</param>
	/// <param name="h">Upper limit of integral.</param>
	/// <param name="order">Order of polynomials used in the fit.</param>
	/// <param name="boundaries">Extrapolation type, one of "zero", "constant", or "linear".</param>
	/// <param name="check_input">if set to <c>true</c> the function will throw exceptions on invalid input.</param>
	void gaussian_expectation_max_1d(d_vector& output,
		d_vector const& X, d_vector const& F_X1, d_vector const& F_X2,
		d_vector const& mu,
		double standard_deviation,
		double l, double h,
		size_t order, const std::string& boundaries,
		bool check_input = true);

	std::string gaussian_expectation_max_1d_check(d_vector const& X, d_vector const& F_X1, d_vector const& F_X2, double standard_deviation, double l, double h, const std::string& boundaries);

	/// <summary>
	/// Given a piecewise polynomial function and vector \f$ \hat x \f$. Output the function evaluated at \f$ \hat x \f$.
	/// </summary>
	/// <param name="s">Piecewise polynomial to evaluate on.</param>
	/// <param name="X">Input vector \f$ \hat x  \f$.</param>
	/// <param name="F_X">Output function values.</param>
	void snap_to_grid(Spline1d& s,
		d_vector const& X, d_vector& F_X);
}