/*------------------------------------------------------------------------------*
 * File Name: XYZ2Mat.h	 														*
 * Creation: Sim 02-27-2009														*
 * Purpose: OriginC Header H file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION	*
 *	Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD			*
 *	Sim 09-27-2009 QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED			*
 *	Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
 *------------------------------------------------------------------------------*/

#ifndef XYZ2MAT_H
#define XYZ2MAT_H

enum{
		XYZ2MAT_REPLACE_BY_EXTRAPOLATE = 0,
		XYZ2MAT_REPLACE_BY_NONUM,
		XYZ2MAT_REPLACE_BY_ZERO,
		XYZ2MAT_REPLACE_BY_MIN,
		XYZ2MAT_REPLACE_BY_MAX,
		XYZ2MAT_REPLACE_BY_MEAN,
		XYZ2MAT_REPLACE_BY_CUSTOM_VALUE
};

enum {
		//XYZ2MAT_METHOD_AUTO = -1,
		XYZ2MAT_METHOD_REGULAR = 0,
		XYZ2MAT_METHOD_SPARSE,
		XYZ2MAT_METHOD_RANDOM_RENKA_CLINE,
		XYZ2MAT_METHOD_RANDOM_SHEPARD,
		XYZ2MAT_METHOD_RANDOM_TPS,
		XYZ2MAT_METHOD_RANDOM_KRIGING,
		XYZ2MAT_METHOD_WEIGHTED_AVERAGE,
		
		XYZ2MAT_METHOD_AUTO = 1000, // as can't be -1, vc tree copy value will skip -1 as "Use" attribute, we have to set very large number
};

//////////////////////////////////////////////////////////////////////////////////////////
class XYZGriddingDataExaminationSettings
{
public:
	XYZGriddingDataExaminationSettings()
	{
		///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
		//dPrecision = 1.0E-8;
		//nRemoveDuplicate = 0;
		//dXStepTol = 1;
		//dYStepTol = 1;
		dXPrecision = 1.0E-8;
		dYPrecision = 1.0E-8;
		nRemoveDuplicate = 0;
		///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	}
	
public:
	void	UpdateGUI(TreeNode& trGUI, bool bToGUI);
	
public:
	///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	//double	dPrecision; // "Tolerance", 1.0E-8
	//int		nRemoveDuplicate; // "Replace Duplicates With", 5, "Mean|Median|Minimum|Maximum|Sum|None"
	//double	dXStepTol; // "X Even Spacing Tolerance (Multiple of Deviation)", 1
	//double	dYStepTol; // "Y Even Spacing Tolerance (Multiple of Deviation)", 1
	double	dXPrecision; // "X Tolerance", 1.0E-8
	double	dYPrecision; // "Y Tolerance", 1.0E-8
	int		nRemoveDuplicate; // "Replace Duplicates With", 5, "Mean|Median|Minimum|Maximum|Sum|None"
	///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
};

class XYZGriddingMethodSettings
{
public:
	XYZGriddingMethodSettings()
	{
		nMethod = XYZ2MAT_METHOD_AUTO;
		nColumns = 20;
		nAutoColumns = 1;
		nRows = 20;
		nAutoRows = 1;
		nQILF = 18;
		nWFLF = 9;
		dSearchRadius = 2.0;
		dAverageRadius = 2.0;
		nMinPoints = 10;
		nMaxPoints = 100; ///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
		nAutoMaxPoints = -1; ///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
		dCorrelationSmoothing = 1.0;
		dTPSSmoothing = 0.0;
		nExtrapolation = 0;
		dOutsideValue = 0.0;
		dTolerance = 5E-3;
	}
	
public:
	void	UpdateGUI(TreeNode& trGUI, bool bToGUI);
	
protected:
	void	UpdateShow(TreeNode& trConvertToMatrix);
	
public:
	int		nMethod; // "Gridding Method", 3, "Regular|Sparse|Random (Renka Cline)|Random (Shepard)|Random (Thin Plate Spline)|Random (Kriging Correlation)|Random (Weighted Average)"
	int		nColumns; // 20, auto
	int		nAutoColumns;
	int		nRows; // 20, auto
	int		nAutoRows;
	int		nQILF; // "Quadratic Interpolant Locality Factor", 18
	int		nWFLF; // "Weight Function Locality Factor", 9
	double	dSearchRadius; // "Search Radius", 2.0
	double	dAverageRadius; // "Average Radius", 2.0
	int		nMinPoints; // "Minimum Points", 10
	///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
	int		nMaxPoints; // "Maximum Points", 100
	int		nAutoMaxPoints; ///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
	///---END QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
	double	dCorrelationSmoothing; // "Smoothing", 1.0
	double	dTPSSmoothing; // "Smoothing", 0.0
	int		nExtrapolation; // "Extrapolation", 0, "Extrapolate|Missing Values|Zero|Mimimum|Maximum|Mean|Custom Value"
	double	dOutsideValue; // "Outside Value", 0.0
	double	dTolerance; // "Tolerance", 5E-3
};

class XYZGriddingRangeRestrictionSettings
{
public:
	XYZGriddingRangeRestrictionSettings()
	{
		bUse = 0;
		
		dXMin = 0;
		nAutoXMin = 1;
		dXMax = 0;
		nAutoXMax = 1;
		dYMin = 0;
		nAutoYMin = 1;
		dYMax = 0;
		nAutoYMax = 1;
	}
	
public:
	void	UpdateGUI(TreeNode& trGUI, bool bToGUI);
	
public:
	bool	bUse;
	
	double	dXMin; // "X Minimum", 0
	int		nAutoXMin;
	double	dXMax; // "X Maximum", 0
	int		nAutoXMax;
	double	dYMin; // "Y Minimum", 0
	int		nAutoYMin;
	double	dYMax; // "Y Maximum", 0
	int		nAutoYMax;
};

class XYZGriddingPreviewSettings
{
public:
	XYZGriddingPreviewSettings()
	{
		nPreviewPlotType = 1;
	}
	
public:
	void	UpdateGUI(TreeNode& trGUI, bool bToGUI);
	
public:
	int 	nPreviewPlotType; // "Preview Plot Type", 1, "3D Color Map Surface|Contour - Color Fill|3D Wire Frame"
};

class XYZGrdiddingDataInfo
{
public:
	int		nDataType;
	int		nSize;
	double	dXMin; // "X Minimum", 0
	double	dXMax; // "X Maximum", 0
	double	dYMin; // "Y Minimum", 0
	double	dYMax; // "Y Maximum", 0
	double	dXStep; // "X Step", 0
	double	dYStep; // "Y Step", 0
};

enum{
	XYZ_CHANGE_INIT,
	XYZ_CHANGE_DATA,
	XYZ_CHANGE_EXAM,
	XYZ_CHANGE_COLUMN_AND_ROW,
	XYZ_CHANGE_SEL_RANGE_USE,
	XYZ_CHANGE_SEL_RANGE,
	
	XYZ_CHANGE_METHOD,
	XYZ_CHANGE_METHOD_PARAMS,
	XYZ_CHANGE_PREVIEW_PLOT_TYPE,
	
	XYZ_CHANGE_OTHER,
};
class XYZGriddingSettings
{
public:
	void	UpdateGUI(TreeNode& trGUI, bool bToGUI);
	
	void	OnChange(int nType, XYZGrdiddingDataInfo *pDataInfo);

public:
	XYZGriddingDataExaminationSettings		settingDataExamination;
	XYZGriddingMethodSettings				settingMethod;
	XYZGriddingRangeRestrictionSettings		settingRangeRestriction;
	XYZGriddingPreviewSettings				settingPreview;
	
private:
	void	updateMatrixRowAndColFromStep(XYZGrdiddingDataInfo *pDataInfo);
	void	updateMatrixStepFromRowAndCol(XYZGrdiddingDataInfo *pDataInfo);
	void	smartUpdateMatrixRowColStep(XYZGrdiddingDataInfo *pDataInfo);
	
	void	updateRangeRestrictionFromMatrixRange(XYZGrdiddingDataInfo *pDataInfo);
	//void	updateMatrixRangeFromRangeRestriction(XYZGrdiddingDataInfo *pDataInfo);
	
	void	updateMethodFromDataType(XYZGrdiddingDataInfo *pDataInfo);
};

//////////////////////////////////////////////////////////////////////////////////////////
class XYZGriddingMathLib
{
public:
	int		DoGridding(const vector& vX, const vector& vY, const vector& vZ, Matrix& Mat, const XYZGriddingSettings *pSettings);
	
	virtual int		DoGridding(const vector& vXInput, const vector& vYInput, const vector& vZInput, matrix& mat, const XYZGriddingSettings *pSettings);
	//virtual bool	UpdateDataInfo(XYZGrdiddingDataInfo* pDataInfo, const vector& vX, const vector& vY, const vector& vZ, const XYZGriddingDataExaminationSettings *pDataExamination);
	virtual bool	UpdateDataInfo(XYZGrdiddingDataInfo* pDataInfo, const vector& vX, const vector& vY, const vector& vZ, const XYZGriddingSettings *pSettings);
	virtual int		PreprocessData(vector& vX, vector& vY, vector& vZ, const XYZGriddingSettings *pSettings);

public:
	bool	CreateGridLine(vector& vXLine, vector& vYLine, double dXBegin, double dXEnd, double dYBegin, double dYEnd, double dStep, bool bVertical);
	///---Sim 09-27-2009 QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED
	//bool	CreateStepsStat(vector& vSteps, vector& vCounts, const vector& vPoints);
	bool	CreateStepsStat(vector& vSteps, vector& vCounts, const vector& vPoints, bool bHideNoStep = false);
	///---END QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED
	int		FindXYInRect(int nSize, const vector& vX, const vector& vY, vector<uint>& vnIndices, double dXMin, double dYMin, double dXMax, double dYMax);
	void	IncreaseIncludedSize(double &dXMin, double& dXMax, double& dYMin, double& dYMax);
	bool	IsLargeDataSet(const XYZGriddingSettings *pSettings, const XYZGrdiddingDataInfo* pDataInfo);
	bool	SetMatrixXYInfo(Matrix& Mat, const XYZGrdiddingDataInfo* pDataInfo);
protected:
	bool	TrimMissingData(vector& vX, vector& vY, vector& vZ);
	bool	TrimUnSelectedData(vector& vX, vector& vY, vector& vZ, const XYZGriddingRangeRestrictionSettings *pRangeRestriction);
	bool	TrimDuplicatedData(vector& vX, vector& vY, vector& vZ, const XYZGriddingDataExaminationSettings *pDataExamination);
	
	bool	CreateGridLine(vector& vA, vector& vB, double dABegin, double dAEnd, double dBBegin, double dBEnd, double dAStep);
};

enum{
	DIRTY_XYZ_GRID_RESULT		= 0x0001,
	DIRTY_XYZ_GRID_PRE_PROCESS	= 0x0001,
	DIRTY_XYZ_GRID_DATA_INFO	= 0x0001,
	
	DIRTY_XYZ_GRID_ALL			= 0xFFFF,
};

class XYZGriddingMathLibCache : public XYZGriddingMathLib
{
public:
	XYZGriddingMathLibCache();
public:
	void	SetDirty(DWORD dwDirtyBits = DIRTY_XYZ_GRID_ALL);
	int		DoGridding(const vector& vX, const vector& vY, const vector& vZ, Worksheet& wks, const XYZGriddingSettings *pSettings);	///Sophy 9/6/2010 ORG-849 SUPPORT_PLOT_XYZ_FROM_WORKSHEET_WITH_GRIDDING
	// only for call base class overload function with param Matrix& Mat, else will incorrectly go to which one with param matrix& mat
	int		DoGridding(const vector& vX, const vector& vY, const vector& vZ, Matrix& Mat, const XYZGriddingSettings *pSettings);
	
	virtual int		DoGridding(const vector& vX, const vector& vY, const vector& vZ, matrix& mat, const XYZGriddingSettings *pSettings);
	virtual bool	UpdateDataInfo(XYZGrdiddingDataInfo* pDataInfo, const vector& vX, const vector& vY, const vector& vZ, const XYZGriddingSettings *pSettings);
	virtual int		PreprocessData(vector& vX, vector& vY, vector& vZ, const XYZGriddingSettings *pSettings);
protected:
	matrix	m_mat;
	bool	m_bDirtyGridding;
	
	vector	m_vXPreprocessed;
	vector	m_vYPreprocessed;
	vector	m_vZPreprocessed;
	bool	m_bDirtyPreprocess;
	
	XYZGrdiddingDataInfo	m_datainfo;
	bool					m_bDirtyDataInfo;
};

XYZGriddingMathLibCache* get_xyz_gridding_cache_pointer();
#define XYZGRIDDING_MATH(_CALL) get_xyz_gridding_cache_pointer()->_CALL

//////////////////////////////////////////////////////////////////////////////////////////
class ErrorInfo
{
public:
	void		Clear() {bHasNoError = true; strErrMsg.Empty();}
	
	bool		bHasNoError;
	string		strErrMsg;
};

class XYZGridding
{
public:
	bool	SetInput(const XYZRange& drXYZ);
	bool	GetOutput(matrix& mat);
	int		DoGridding();
	
	void	OnChange(int nType, ErrorInfo& err);
	
	bool	GetData(vector& vX, vector& vY, vector& vZ, bool bOriginal = true);
	
	XYZGriddingSettings* GetXYZGriddingSettings() { return &m_Settings; }
	XYZGrdiddingDataInfo* GetXYZGrdiddingDataInfo() { return &m_DataInfo; }

protected:
	//void	UpdateDataInfo();
	
	int		GetPreprocessData(vector& vX, vector& vY, vector& vZ);

private:
	int		getSourceData(const XYZRange& drXYZ, vector& vX, vector& vY, vector& vZ);
	
	void	checkInput(ErrorInfo& err, const XYZRange& drXYZ);
	void	checkValidSetting(ErrorInfo& err, XYZGriddingSettings& settings);
	
protected:
	XYZGriddingSettings			m_Settings;
	XYZGrdiddingDataInfo		m_DataInfo;
	
private:
	vector		m_vX;
	vector		m_vY;
	vector		m_vZ;
	
	matrix		m_mat;
	
	ErrorInfo	m_errInput;
	ErrorInfo	m_errSetting;
};

#endif //XYZ2MAT_H
