#ifndef _UTrainingImageLITrainingImageES_H_
#define _UTrainingImageLITrainingImageES_H_
//#define USE_MPI


#ifdef USE_MPI
#include "mpi.h"
#endif
////////////
/*Geometry*/
////////////
//#include <tchar.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <stdint.h>
#include <stdlib.h>
#include <map>
//null value is assigned to nodes where the approximation of cpdf cannot be done properly
static const int gNullvalue = -999;
class HosDataManager;
class Grid;
class InfoIn;
class TrainingImage;
class Samples;
class Tools;
class Stats;
struct IntDoubleInt;
typedef  std::vector<bool>                                              Bool1Vec;
typedef  std::vector<int>                                               Int1Vec;
typedef  std::vector< std::vector<int> >                                Int2Vec;
typedef  std::vector<double>                                            Double1Vec;
typedef  std::vector< std::vector<double> >                             Double2Vec;
typedef  std::vector< std::vector< std::vector<double> > >              Double3Vec;
typedef  std::vector< std::vector< std::vector<std::pair<int, int> > > > Int2VecPair;
typedef  std::vector< std::vector< std::vector<int> > >                 Int3Vec;
typedef  std::vector< std::vector< std::vector<std::vector<int> > > >   Int4Vec;
typedef  std::vector<std::string>                                       String1Vec;
typedef  std::vector<std::pair<double, int> >										DoubleIntVec;
typedef  std::vector<IntDoubleInt>										IntDoubleIntVec;

using namespace std;
struct IntPair
{
	int x;
	int order;
};
struct IntDoubleInt
{
	int num;
	double dist;
	int ind;
};
struct SInfo
{
	double m_max, m_min;
	double m_mean;
	int m_n_samples;
	String1Vec m_var_names;
};
//grid information
struct GInfo
{
	double m_x0, m_y0, m_z0; // origin
	int m_nx, m_ny, m_nz; // nb of points in each direction
	double m_dx, m_dy, m_dz; // steps in each direction
	int m_nv; // total number of points  
	//int m_dless;
	String1Vec m_var_names;
};
//neighbors information
struct NInfo
{
	double m_local_max, m_local_min; //minimum and maximum values in local neighborhood
	int m_n_local_samples; //number of neigbors
	Int1Vec m_samples_neighbor; //indexes of neighbors in grid
	Double1Vec m_samples_neighbor_vals; // values of neighbors
	Double1Vec m_samples_distance; //distances to central node
};
//Class for splines
class Spline {
public:
	vector<vector<double> > coefs; //Coeffitients of polynomials for each spline: coeff3*x^3+coeff2*x^2 ..
	vector<vector<double> > coefs_integral; //For integral of spline the coeffients are different. 
	vector<double> coefs_bias; //Precalculated integral of spline pieces  - area under the spline pieces
	vector<double> breaks; // knot points of the spline

	Spline()
	{
	}
	//	void Save_Spline(ofstream& fout);
		//bool Read_Spline(ofstream& fin);
		//Create Spline knowing order of spline ORD
	void Create(int ord);
	//Create spline knowing knots T, ...
	void Create(vector<double> t, int i0, int p, int order);
	double GetBasisVal(double x, int i, int p, double mult);
	//Get value of spline for given X. Flag ingtl=1 is used if integral of spline is needed
	double GetVal(double x, int ingtl = 0);
	//binary searh of element X in sorted array A with given minimum and maximum indexes IMIN IMAX 
	int  binary_search(Double1Vec& A, double x, int imin, int imax);
	//Get value of splines with given index of piece I and coordinate X.Flag ingtl=1 is used if integral of spline is needed
	double GetVal(double x, int i, int ingtl);
	//Normalization of spline. Integral of squared value == 1
	void Normalize();
	//Get Spline startin at knots with index I0. flag WR1=1 is used for testing
	void GetSpline(int i0, bool wr1);
	//Get Legendre polinomials order NN
	void SetLegendre(int nn);
	//Get integral of spline
	void Get_Integral();
	~Spline() {}
private:
	int order; //order of spline
	int nk; //number of knots
	double a, b; //[a,b] - domain where spline is defined
	//Calculate coeffitients of spline in p-form
	void GetPPCoeff(int i, int p, double mult, vector<double> &fortensor, bool wr1);
	//Get value of polinomial  val=coeff0*x^n+coeff1*x^(n-1)+...
	double PolyVal(vector<double> &coeff, double x);
	//void SetOneBreak(int i,double val,vector<int> &fortensor);
	//Cant remember. 
	void SetOneBreak(int i, double mult, vector<double> &fortensor);
	//Transfer linear index IND to sub-indexes SUB knowing size of multiarry NX. Size of multi-array for all dimensions is equal to NX
	void ind2sub(int ind, vector<int> &sub, int Nx);

};
//Orhtogonal Spline Set
class SplineContainer {
public:
	int n_spln;//number of splines
	int m_division;// number of intervals
	int order;// order of splines
	vector<Spline> splines;//array of splines
	Double2Vec Dumpd_vals;// Values of precalcualted kernel
	string f_Dump_name; //Name of file wherer to save precalculated values
	SplineContainer()
	{
		int ssize = 500; //discretization of kernel: 500x500 valyes
		Dumpd_vals.resize(ssize);
		for (int i = 0; i < ssize; i++)
			Dumpd_vals[i].resize(ssize);
	}
	//Create spline basis knowing order ORD, number of intervals M_DIV, knots KNOTS. Flag DUMPD = 1 if kernel responce should be calculated
	void Create(int ord, int m_div, Double1Vec& knots, bool Dumpd);
	//Save kernel values
	void  Write_Dump_Vals_Bin(ofstream& fout);
	//Read kernel values
	bool  Read_Dump_Vals_Bin(ifstream& fin);
	~SplineContainer() {}
private:
	int nk; //number of knots
	double a, b; // domain [a,b] where splines are defined
	vector<vector<double> > tk; //enclosed knot sets
	vector<vector<double> > fast_coeffs; //array needed to calculate faster the coeffitients
	vector<double> gl_t; //all knots
	vector<vector<double> > Lcoeff; //Coeffitients for linear combination of splines in p-form to construct orthogonal spline
	//Get knots
	void Get_split(Double1Vec& knots);
	//Get orthogonal splines 
	void Get_Ortho();
	//Get kernel values
	void Get_Dump_Responce();
	//Form output format of splines
	void Get_Out_Format();
	//Read binary file with kernel values
	bool Read_Dump_Vals_Bin();
	//Read kernel values
	bool Read_Dump_Vals();
	//Write kernel values
	void Write_Dump_Vals();
	//Write binary file with kernel values
	void Write_Dump_Vals_Bin();
	//Get integral of orthogonal spline
	void Get_Integral();
	//Get function Fk from paper Wei et al. 2013
	vector<double> Get_Function(int k);
	//get determinant of first M minor of a matrix B 
	double Determinant(vector<vector<double> > & b, int m);
	//Calculate coeffitients for fast calculation
	void  Get_Fast_coeffs();
	//Crout method for determinant calculation
	void Crout_Cut(vector<vector<double> > & A, vector<vector<double> >  &L, vector<vector<double> > &U, int n, int p_ord);
	//Crout method for determinant calculation
	void Crout(vector<vector<double> > & A, vector<vector<double> >  &L, vector<vector<double> > &U, int n);
	//Cant remember
	vector<double> Get_Coeff(int k, vector<double> f);
	//Derivative of order N for splines
	void diffN(int i, int p, int k, double mult, vector<double> &ncoeff);

};
//class to collect values from parameter file
class InfoExt {
public:
	String1Vec files;	  //file names: [0] - data sample file, [1] - training image, [2] - output name, [3] - debug logging
	int m_nb_locations_stats; //number of replicates
	int m_mx_s; //maximum number of neighbors
	int m_mn_s; //minimum number of neighbors
	int m_order; //order of polynomials or splines
	int m_seed; //seed number for randomization
	int m_mdiv_max; //miximum number of intervals
	GInfo m_template_info; //searching ellipsoid parameters
	std::string par_file_name; //parameter file name
	//constructors
	InfoExt() {
		files.resize(4);
		m_order = gNullvalue;
		m_mx_s = gNullvalue;
		m_mn_s = gNullvalue;
		m_nb_locations_stats = gNullvalue;
		m_seed = gNullvalue;
		m_template_info.m_nx = gNullvalue;
		m_template_info.m_ny = gNullvalue;
		m_template_info.m_nz = gNullvalue;

	}
	~InfoExt() {}
};
//Class of input information
class InfoIn {
public:
	vector<SplineContainer> Lspline_Dump; //Orthogonal Splines
	int m_dimension; // dimension 2D or 3D
	int m_method; // Method of simulation: Legendre polynomials or Splines
	bool m_dynamic_template; // needed dynamic template or not
	bool m_hard_point; //cant remember
	int m_n_revisits; //number of revisiting for node where cdpf cannot be approximated well
	int m_n_hard_point; //number of bad points
	GInfo m_grid_info; // simulation grid info
	GInfo m_ti_info; // training image grid info
	GInfo m_template_info; //searching ellipsoid info
	int m_mdiv_max;//maximum number of intervals
	int m_mx_s, m_mn_s; //maximum and minimum number of neighbors
	int m_mx_s_cur; //current maximum number of neighbors
	//Int1Vec nneighb_pdf; //
	int m_order; // order of splines of polynomials
	int m_index_cat; //temprorary
	int m_verbosity; // verbosity level
	int m_n_realization; // nb of realization to be generated.
	int m_ngrid; // number of multi-grid.
	int m_seed;          // seed number
	String1Vec m_files; //file names: [0] - data sample file, [1] - training image, [2] - output name, [3] - debug logging
	Int2Vec search_template; //Searching spiral indexes. 
	Int1Vec rand_path_in_search; //random_path in local neigborhood. Needed for local stationarity
	int n_search_template; // number of points in spiral searching 
	std::ofstream m_fout_debug; //file stream for debug logging
	Int2Vec m_unsamples_orig; //unsampled locations original
	Int2Vec m_unsamples_curr; //current unsampled locations
	int m_nb_locations_stats; //number of replicated
	//constructors
	InfoIn() {
		m_n_hard_point = 0;
	}
	~InfoIn() {}
	//get searching spiral structure
	void Get_Search_Template();
	//Convert parameters from parameter file to infoin class 
	void ReadExtInfo(int& dimension, int& method,
		double& x0d, double& y0d, double& z0d, int& nxd, int& nyd, int& nzd, double& dxd, double& dyd, double& dzd,
		double& x0t, double& y0t, double& z0t, int& nxt, int& nyt, int& nzt, double& dxt, double& dyt, double& dzt,
		int& nxtl, int& nytl, int& nztl, double& dxtl, double& dytl, double& dztl,
		int& verbosity, int& seed, int& nbr, int& nbg, bool& dynamic_template, int& n_max_levels_x, int& n_max_levels_y, int& n_max_levels_z, int& nb_locations_stats, int& mx_s, int& mn_s, int& m_order, String1Vec& files);
	//Save debug logging
	void WriteDebuggingInfo(Grid& grid, Tools& tools, InfoIn& infoin, int ind);

private: //disabling copy
	InfoIn(const InfoIn &);
	InfoIn & operator=(const InfoIn &);
};


///////////////////////////////
//Class for simulation grid
class Grid {
public:
	Double2Vec m_data; // Coordinates and values. First index is linear index of nodes. Second index is : [0..m_dimension-1]- coordinates, [m_dimension] - value
	Double1Vec m_min; // minimum values
	Double1Vec m_max; //maximum values
	Double1Vec m_mean; //mean values
	Int1Vec m_multigrid_index; //multigrid indexing
	//constructors
	Grid() {}
	~Grid() {}
	//Fill mask array from file
	void Fill_Mask(InfoIn& infoin);
	//Fill coordinates and values from file
	void FillData(InfoIn& infoin);
	//Create grid
	void Grid_Create(InfoIn& infoin);
	//Find neighbors
	void FindSamplesNeighbor(InfoIn& infoin, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats, int calc_type);
	//Assign values of neighbor location at INDEXV to  tools.m_neighbors_info
	void AssignNeigbors( Tools& tools, std::vector<int> indexv);
	//Find neighbors using searching ellipsoid
	std::vector<int> Find_Samples_Within_Template(InfoIn& infoin, TrainingImage& ti, Samples& samples, Tools& tools);
	/*
	private: //disabling copy
	  Grid(const Grid &);
	  Grid & operator=(const Grid &);
	  */
};
//Class of replicates of data event (conditional data configuration)
class Replicates //
{
public:

	//indexing is repl_ind*neib_max+neib_ind;
	Double1Vec m_values; //replicates in format  repl_0_neib1 repl_0_neib2 ... repl_0_neib_max, repl_1_neib1 repl_1_neib2 ... repl_1_neib_max...
	Int1Vec m_indexes; //replicates in format  repl_0_neib1 repl_0_neib2 ... repl_0_neib_max, repl_1_neib1 repl_1_neib2 ... repl_1_neib_max...
	int m_size; //max number of replicates
	int m_shift; //max number neib for all grid cells/ need for indexing including central point
	int m_neib_num;//number neib for current grid cell that used for getting replicates
	Int1Vec m_neibcount_indexes;
	Replicates()
	{

	}
	Replicates(int size_, int neib_max)
	{
		m_size = size_;
		m_shift = neib_max + 1;
		m_values.resize(m_size*m_shift);
		m_indexes.resize(m_size*m_shift);
		m_neibcount_indexes.resize(m_shift);

	}

	~Replicates()
	{

	}
};
struct Replicate
{
	Double1Vec m_value_replicate;
	Int1Vec m_index;
};

///////////////////////////////
//class to work with replicates 
class Stats {
public:
	//int m_cr_replicates;
	Int1Vec m_list_point_stats;//indexes of  locations of replicates
	Int1Vec m_rand_path_num; //random path visiting replicates

	//constructors
	Stats() {}
	~Stats() {}
	//Calculate replicates from hard data
	void Get_Data_Replicates(InfoIn& infoin, Samples& samples, Tools& tools, Double2Vec& m_data, Int2Vec& search_tmp, const Int1Vec& indexv);
	//Create instaces to keep replicates and define random path visition replicates
	void Stats_Create(InfoIn& infoin, TrainingImage& ti, Tools& tools);
	//
	void Build_Local_Templates(InfoIn& infoin, TrainingImage& ti, Tools& tools, const Double2Vec& m_data, const Int1Vec& indexv);
	

private: //disabling copy
	Stats(const Stats &);
	Stats & operator=(const Stats &);
};

///////////////////////////////
class TrainingImage {
public:
	Double2Vec m_data; // training image
	double m_ti_min;
	double m_ti_max;
	//constructors
	TrainingImage() {}
	~TrainingImage() {}

	void FillData(InfoIn& infoin);
	bool FillDataFast(InfoIn& infoin);
	void TrainingImage_Create(InfoIn& infoin, Samples& samples);

private: //disabling copy
	TrainingImage(const TrainingImage &);
	TrainingImage & operator=(const TrainingImage &);
};

/////////////////////////////
class Samples {
public:
	SInfo m_samples_info;
	Double2Vec m_data;
	Double2Vec m_stat_samples;
	int m_n_thres;
	//constructors
	Samples() {}
	~Samples() {}
	void FillData(InfoIn& infoin, Grid& grid, Tools& tools);

	void Samples_Create(InfoIn& infoin, Grid& grid, Tools& tools);
	void Post_min_max(InfoIn& infoin);
private: //disabling copy
	Samples(const Samples &);
	Samples & operator=(const Samples &);
};

class HosDataManager {
public:
	InfoIn m_infoin;
	int m_curr_hard_psim;
	int m_max_hard_psim;

	//constructors
	HosDataManager() {}
	~HosDataManager() {}

	void Intro();
	void FillUnsampledAll(InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats);
	double FillUnsampled(InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats);
	void ReadAll(InfoIn& infoin, InfoExt& infoext);
	InfoExt ReadArgs(int argc, char *argv[]);
	void CreateAll(InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats);
	void PrepareAct(InfoIn& infoin, Grid& grid, Tools& tools, TrainingImage& ti, Samples& samples, int& nt_cr, int& i, double val, int ind);
	static double SimulatePoint(InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats, int calc_type, Tools& dat_tools);

	void SimulateAll(InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats);
	void WriteSolutions(InfoIn& infoin, Grid& grid, double minv, double maxv);
	void WriteSolution_SGEMS(InfoIn& infoin, Grid& grid, double minv, double maxv);
	static bool Read_SGEMS(std::string name, Double2Vec& ti_data, InfoIn& infoin_);
	void WriteStats(InfoIn& infoin, Grid& grid, Samples& samples);
	int rand_int(int& n);
	void WriteTiming(InfoIn& infoin, Tools &tools, double diff);
	static std::string GetBaseFilename(std::string fName);
private: //disabling copy
	static void reverseFLT(float*  &arr, unsigned int length);
	static float reverseFloat(const float inFloat);
	static void reverseINT(uint32_t* &intarr, uint32_t length);
	static void ReadPropBin(ifstream& is, int nfloat, Double2Vec& ddata, int ind, bool is_reverse, double nullvalue);

	HosDataManager(const HosDataManager &);
	HosDataManager & operator=(const HosDataManager &);

};

//class Point_tools
//{
//	public:
//		SplineContainer Lspline;
//		NInfo m_neighbors_info;
//		Double1Vec m_x_Leg_cdf;
//		Int2Vec m_ijk_ref_replicate;
//		Int2Vec m_ijk_ref_replicate;
//		vector<Replicate> repl_TI;
//		vector<Replicate> repl_Dat;
//  ~Point_tools() {
//  
//  }
//
//
//}
class Dump {
public:
	Int1Vec Dump_size;
	int n_values;
	int m_dimension;
	Double2Vec values;
	void Init(int n_data_samples, int m_dim, double nullvalue)
	{
		Dump_size.resize(m_dim, 21);
		m_dimension = m_dim;
		values.resize(n_data_samples);
		n_values = 1;
		if (m_dim < 0 || m_dim>3)
		{
			std::cout << "Check dimension! m_dimension=" << m_dim << std::endl;
			system("pause");
			exit(EXIT_FAILURE);
		}
		for (int i = 0; i < m_dim; i++)
			n_values *= Dump_size[i];

		for (int i = 0; i < values.size(); i++)
			values[i].resize(n_values, nullvalue);

	}
	~Dump() {  }
	int Get_Dump_ind(Int1Vec& coord);
	void Get_XYZ_from_Dump_ind(int ind, Int1Vec& coord);
	void Read_Repl_Dump(int n_samples);
};
class Tools {
public:
	static const int n_min_good_repl = 5;
	string f_save_name;
	SplineContainer Lspline;
	SplineContainer Lspline_cat;
	SplineContainer *Lspline_buf;
	int m_rand_nb_pass;
	static const int m_n_unif_dist = 10;
	int m_n_repl;
	int m_cp;
	int m_loc_val;
	int m_loc_rel;
	int m_real_curr;
	int m_grid_curr;
	int m_rp;
	Double1Vec cat_vals;

	bool m_hardSLater;
	Grid tool_grid;
	Int1Vec m_hardpoints;
	Int1Vec m_path_pass;
	Int1Vec m_null_vec;
	Double2Vec m_sample_multigrid;
	Int2Vec m_sample_index_multigrid;
	Int1Vec m_sample_indicator_orig;
	Int1Vec m_sample_indicator_curr;
	Int1Vec m_samples_orig;
	Int1Vec m_samples_curr;
	Double1Vec m_LegendreMomentsSamples;
	NInfo m_neighbors_info;
	Double2Vec m_stat_grid;
	// Int2VecPair m_stats_map;
	//std::vector< std::vector< std::vector<IntPair> > > m_stats_map;
	Int3Vec  m_stats_map_point;
	Double2Vec m_stats_map_values;
	Int3Vec  m_stats_map_order;
	Double2Vec m_table_cond_legendre;
	static const int m_cdf_samples = 500;//ILNUR
	Double1Vec m_x_Leg_cdf, m_x_real_cdf, m_min_one_one;
	Double1Vec m_pdf, m_cdf;
	Dump Repl_Dump;

	Int2Vec m_ijk_ref_replicate;
	double m_dif_1, m_dif_2, m_dif_3, m_dif_4, m_dif_5;
	double step_x_pdf; //step is constant;
	bool first_node;
	Double1Vec coeff_1D;
	double nug, sill;
	//From stats
   //   Int1Vec m_multi_template;
	Int1Vec count_data_Repl;
	//  std::vector<Replicate>	m_data_value_replicates;
	 // std::vector<Replicate> m_all_value_replicates;
	Replicates m_all_value_replicates;
	Replicates m_data_value_replicates;


	//constructors
	Tools() {
		first_node = true;

	}
	~Tools() {

	}
	//	bool Load_Splines(SplineContainer& spl,int ii);
	  //void Save_Splines(SplineContainer& spl);
	Int1Vec Tools::getSortIndex(Double1Vec & arr);
	void FillMultigrid(InfoIn & infoin, Double1Vec & sampl_data, Double2Vec & distanceToMultigrid, int gp);
	double draw_value_rous();
	void AdjustZeroProbability(Double1Vec& filtred_vals);
	void Prepare_ReplOLD(Double1Vec& coeff_1D_leg, int nneib, Grid& grid, InfoIn& infoin, vector<Replicate>& replicate_vec, vector<bool>& nneib_vec, Replicate& neihbors_replicate, SplineContainer*& L_spline_rat, vector<SplineContainer*>& Lspline_all);
	void Prepare_Repl(Double1Vec& coeff_1D_leg, int nneib, Grid& grid, InfoIn& infoin, Replicates& replicate_vec, vector<bool>& nneib_vec, vector<double>& neihbors_replicate, SplineContainer*& L_spline_rat, vector<SplineContainer*>& Lspline_all);
	int var2mdiv(double varr);
	double Get_dist_elp(InfoIn& infoin, double x, double y, double z);
	double BackConvertVal(double val, int ind_cur);//double BackConvertVal(double val);
	void Get_variogram_par(InfoIn& infoin, TrainingImage& ti);
	double ConvertVal(double val, int ind_cur);
	double variogram_test(double h);
	double covariance_test(double h);
	double kriging_var(Double2Vec Cov, Double1Vec var_b);
	SplineContainer Get_Knots(Double1Vec filtred_vals, double thresh, int m_div, int order_spl);
	void WritePdf(string name, string descrip, Double1Vec& coeff_1D_cur, SplineContainer* &Lspline_cur);
	void WriteCdf(Double1Vec& coeff_1D_cur);

	bool Calc_Cond_PdfOLD(Replicate& replicate, vector<int>& neib_ind_def, vector<int>& neib_ind_undef, Tools& dat_tools, InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Stats& stats);
	bool Calc_Cond_Pdf(Replicates& replicates, int repl_base, vector<int>& neib_ind_def, vector<int>& neib_ind_undef, Tools& dat_tools, InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Stats& stats);
	Double1Vec Get_Filtred_Vals(vector<double>& replicate, Replicates& repl_TI, vector<int>& neib_ind_def, int ind_undef, double thresh, int & max_cnt);
	Double1Vec Get_Filtred_ValsOLD(Replicate& replicate, vector<Replicate>& repl_TI, vector<int>& neib_ind_def, int ind_undef, double thresh, int & max_cnt);
	/*double SimulatePoint_val(Point_tools&  pnt_tools, int calc_type);*/
	void Calc_Cond_Coeff(Replicates& Repl_TI, vector<double>& replicate, vector<int> neib_ind_def, Double1Vec& cond_coef, vector<SplineContainer>& Lspline_all);
	void Calc_Cond_CoeffOLD(vector<Replicate>& Repl_TI, Replicate& replicate, vector<int> neib_ind_def, Double1Vec& cond_coef, vector<SplineContainer>& Lspline_all);
	void Get_Data_Replicate_SplineOLD(Replicate& replicate, vector<int>& neib_ind_def, vector<int>& neib_ind_undef, Tools& dat_tools, InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Stats& stats);
	void Get_Data_Replicate_Spline(Replicates& replicates, int repl_base, vector<int>& neib_ind_def, vector<int>& neib_ind_undef, Tools& dat_tools, InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Stats& stats);
	void Fill_Cond_Spline(int end_ind, vector<double>&neib_replicate, Replicates& replicates, Double1Vec& coeff_1D_leg, vector<bool>& n_neib_max, int ind_repl0, SplineContainer*& L_spline_rat, vector<SplineContainer*>& L_spline_all);
	void Fill_Cond_SplineOLD(int end_ind, Replicate& neib_replicate, vector<Replicate>& replicates, Double1Vec& coeff_1D_leg, vector<bool>& n_neib_max, int ind_repl0, SplineContainer*& L_spline_rat, vector<SplineContainer*>& L_spline_all);
	int rand_int(int n);
	Int2Vec GetAllPermutation(std::vector<int> map, int n_neib);
	Int2Vec UpdateUnsamples(InfoIn& infoin, Double2Vec& m_data, Int1Vec& m_multigrid_index, Int1Vec& unsamples);
	void Fill_Cond_Legendre(int end_ind, vector<double>& neib_replicate, Replicates &replicates, Double1Vec& coeff_1D_leg, vector<bool>& n_neib_max, int ind_repl0, int order);
	void Fill_Cond_LegendreOLD(int end_ind, Replicate& neib_replicate, vector<Replicate>& replicate, Double1Vec& coeff_1D_leg, vector<bool>& n_neib_max, int ind_repl0, int order);
	void ComputeLegendreMomentsPdf(InfoIn& infoin);
	void GetSplines(int order, int m_div, SplineContainer &Lspline_cur);
	int CalcFullNumberCoeff(int min_order, int order, int nsn, int& k, std::vector< std::vector<int> > & vec_map);
	int CalcFullNumberCoeff_NL(int order, int& k, int nsn, std::vector< std::vector<int> >&   vec_map);
	void FindStatsMap(InfoIn& infoin);
	void ComputeXCdf(double& min, double& max);
	bool ComputeCdf(InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats, int calc_type, Tools& dat_tools);
	double Weight_Average(InfoIn& infoin, Grid& grid, TrainingImage& ti, Samples& samples, Tools& tools, Stats& stats);

	double ComputeLegendrePoly(double& p, int& order);
	double draw_value_cdf(double& rr);
	double draw_value_cdf(Double1Vec& cdf_curr, Double1Vec& x_Leg);
	double draw_value_coeff(Double1Vec& coeff1D_cur, SplineContainer*& Lspline_cur);
	double get_cdf_val(double x, Double1Vec& coeff_1D_cur, SplineContainer*& Lspline_cur);
	double get_pdf_val(double x, Double1Vec& coeff_1D_cur, SplineContainer*& Lspline_cur);
	static  Double1Vec Legendre_coeff(int n);
	double bisection(double fval, double a, double b, double fa, double fb, int NMAX, Double1Vec& coeff_1D_cur, SplineContainer*& Lspline_cur);
	void Legendre2Poly(Double1Vec& coeff_1D_leg, Double1Vec& coeff_1D);
	bool Poind2DInsideDomain(InfoIn& infoin, double& x, double& y);
	bool Poind3DInsideDomain(InfoIn& infoin, double& x, double& y, double& z);
	double Dist_P1_P2(double& x1, double& x2);
	double Dist_P1_P2(double& x1, double& y1, double& x2, double& y2);
	double Dist_P1_P2(double& x1, double& y1, double& z1, double& x2, double& y2, double& z2);
	double ComputeLocalLegendreMoments(double& p, int& order);
	Double1Vec ComputeLegendrePolyFull(double& p, int order);
	void ArrangeSol(InfoIn& infoin, Grid& grid, Samples& samples, Tools& tools, int& real_no);
	void ComputeLegendreMomentsSamples(InfoIn& infoin, Tools& tools, Samples& samples);
	int binarySearch(Double1Vec &arr, double key);

	//private: //disabling copy

	  //Tools(const Tools &);
	 // Tools & operator=(const Tools &); 	
	void get_Statistics(vector<Replicate> &data_repl, int nneib);

};


#endif
