#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	type_haar,
	type_db2,
	type_db3,
	type_db4,
	type_db5,
	type_db6,
	type_db7,
	type_db8,
	type_db9,
	type_db10,
	type_b11,
	type_b13,
	type_b15,
	type_b22,
	type_b24,
	type_b26,
	type_b28,
	type_b31,
	type_b33,
	type_b35,
	type_b37,
};
enum{
	ext_periodic,
	ext_pad0,
};
enum{
	thrt_custom,
	thrt_sqtwolog,
};
#include <GetNbox.h>
#include <..\OriginLab\wavelet_utils.h>
#include <event_utils.h>
#include <o8dlg.h>

/***************************************************************************************
/// Modification Log :
///	Folger 07/28/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
/// Folger 11/27/08 QA80-12356 v8.0980 MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
/// Kyle 07/28/2009 QA80-14026 FIX_WRONG_LEGEND_FOR_PREVIEW
///	Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
***************************************************************************************/

//put your own support static functions here
//enum {
	//CREATE_WAVELET_FILTER_ERROR = XF_LOCAL_ERR_BEGIN,
	//EXTEND_MODE_INVALID,
	//MULTI_DWT_FAILED,
	//MULTI_IDWT_FAILED,
//};


//put your own support static functions here
enum {
	CUSTOM = 0,
	SQTWOLOG,
};

static string _create_levels_list(int nLevel)
{

	string strList;
	strList = (string)(1);
	for(int ii = 2; ii <=nLevel; ii++)
	{
		strList += "|"+ (string)(ii); 
	}
	
	return strList;
}

//------ Folger 07/28/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
static	void	_set_output_range_comments(XYRange& oy, const XYRange& iy, int nLevel, double rThrd, int nThreType, int nType)
{
	string	strRange = get_input_data_range_string(iy);
	string	strComments;
	if ( nThreType == thrt_custom )
		strComments.Format("%d level(s) %g%% threshold %s denoise of %s", nLevel, rThrd, get_wavelet_type_string(nType), strRange);
	else
		strComments.Format("%d level(s) sqtwolog threshold %s denoise of %s", nLevel, get_wavelet_type_string(nType), strRange);
	
	oy.SetOutputComment(strComments);
}
//------ End BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS

static bool _check_input_settings(TreeNode& trGetN, string& strErrMsg, TreeNode& trNode = NULL)
{
	int nSize;
	TreeNode trInput= trGetN.iy;
	XYRange xyi;
	
	if(!get_error_for_input_xyrange(trInput, strErrMsg, nSize, xyi))
		return false;
	
	trGetN.thrd.Show = (trGetN.thrt.nVal == SQTWOLOG)? false: true;
	
	int nLevel=min(7,(int)(log10(nSize)/log10(2)));	
	if(trGetN.ext.nVal == 0)
		nLevel -=1;
	
	if(trNode && trNode.tagName == "iy" || trGetN.level.nVal>nLevel)
	{
		trGetN.level.nVal = nLevel;
	}
	
	string strAttr = _create_levels_list(nLevel);
	trGetN.level.SetAttribute(STR_COMBO_ATTRIB, strAttr);
	
	return true;
}

static bool s_bInit = false;
static string s_strErrMsg = "";

static void	_run_wtdenoise_on_current_data(TreeNode& trGetN, PageBase& pgTemp, Worksheet& wksTemp)
{
	XYRange xy, xyResult;	

	if(!init_preview_graph(trGetN.iy, pgTemp, wksTemp, NULL, &xy, &xyResult))
		return;
	
	int type = trGetN.type.nVal;
	int ext = trGetN.ext.nVal;
	int thrt = trGetN.thrt.nVal;
	int level = trGetN.level.nVal;
	double thrd = trGetN.thrd.dVal;

	try {
		wtdenoise( xy, type, ext, xyResult, thrt, level, thrd);
	}
	catch(int nErr)
	{
	}

	GraphPage gp = pgTemp;
	
}


void wtdenoise(const XYRange& iy, const int& type, const int& ext, XYRange& oy, const int& thrt, const int& level, const double& thrd)
{
	waitCursor junk;
	vector vX;
	vector x;
	//------ Folger 11/27/08 QA80-12356 v8.0980 MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
	//iy.GetData(x, vX);
	vector<int>		vnMissingValsIndices;
	iy.GetData(x, vX, NULL, 0, DRR_BAD_WEIGHT_TREATMENT, &vnMissingValsIndices);
	//------ End MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
	
	//wavelet type
	//vector<Nag_WavType> vWavType = {Nag_Haar, Nag_DB4, Nag_DB6, Nag_DB8, Nag_DB10, Nag_DB12, Nag_DB14, Nag_DB16, Nag_DB18, Nag_DB20, Nag_Bior1_1, Nag_Bior1_3, Nag_Bior1_5, Nag_Bior2_2, Nag_Bior2_4, Nag_Bior2_6, Nag_Bior2_8, Nag_Bior3_1, Nag_Bior3_3, Nag_Bior3_5};
	
	//vector<Nag_WavType> vWavType= {
						    //Nag_Haar,
						    //Nag_DB2,
						    //Nag_DB3,
						    //Nag_DB4,
						    //Nag_DB5,
						    //Nag_DB6,
						    //Nag_DB7,
						    //Nag_DB8,
						    //Nag_DB9,
						    //Nag_DB10,
						    //Nag_Bior1_1,
						    //Nag_Bior1_3,
						    //Nag_Bior1_5,
						    //Nag_Bior2_2,
						    //Nag_Bior2_4,
						    //Nag_Bior2_6,
						    //Nag_Bior2_8,
						    //Nag_Bior3_1,
						    //Nag_Bior3_3,
						    //Nag_Bior3_5,
						    //Nag_Bior3_7
						  //} ;
	Nag_WavFilt filter;
	if(ext <0 || ext > 1 )
	{
		nag_free_wavfilter(&filter);
		XF_THROW(XFERR_WT_EXTEND_MODE_INVALID);
	}
	
	//Nag_WavType wavname = vWavType[t];
	Nag_WavModeType mode = g_nWaveModes[ext];
	/* Read end extension mode */ 
	//vector<string> vWaveMode = {"Periodic", "Zero-padded"};
	
	
	
	int i, n, nc, nLevel;
	//compute the max level
	int nSignalLen=x.GetSize();
	
	nLevel=min(7,(int)(log10(nSignalLen)/log10(2)));
	
	///Sandy 2006-11-29 when using perodic mode, should now decompose to the lowest level.
	if(mode == Nag_PerWavExt)
		nLevel -=1;
	
	
	n = get_enough_length_to_be_decompose(nSignalLen, nLevel);
	//n=pow(2,nLevel);
	//if(nSignalLen>n)
	//{
		//n=nSignalLen/128+(nSignalLen%128!=0?1:0);
		//n=n*128;
	//}
	
	x.SetSize(n);
	//double maxerr;
	//NagError fail;
	////INIT_FAIL
	//fail.code = NE_NOERROR;
	//fail.print = 0;
	
	/* Initialise filter coefficients */
	if(!create_wavelet_filter(g_nWaveletType[type], filter))
		XF_THROW(XFERR_WT_FAILED_TO_CREATE_FILTER);
	//nag_wavfilter(wavname, &filter, &fail);
	//
	//if (fail.code != NE_NOERROR)
	//{
		//printf(fail.message);
	//}
	
	//if (!strcmp("Periodic",vWaveMode[ext]))
	//{
	  //mode = Nag_PerWavExt;
	//}
	//else if (!strcmp("Zero-padded",vWaveMode[ext]))
	//{
	  //mode = Nag_ZeroWavExt;
	//}
	//else
	//{
	  //printf("mode type not recognised\n"); 
	  //goto END; 
	//}
	
	vector vC,vL;	
	if(!multi_scale_dwt(nLevel,mode,x,filter,vC,vL))
	{
		nag_free_wavfilter(&filter);
		XF_THROW(XFERR_WT_MULTI_DWT_FAILED);
		//goto END;
	}
	
	//compute threshold
	int nWholeLen=vL.GetSize();
	//int len=vL[nWholeLen-level];
	vector cd;
	//cd.SetSize(len);
	int nl=vL[0];
	if(level>nLevel)
		XF_THROW(CER_INPUT_OPTION_OUT_OF_RANGE);
	for(i=0;i<(nLevel-level);i++)
	{
		nl+=vL[i+1];
	}
	//vC.GetSubVector(cd, nl, nl+len-1);
	vC.GetSubVector(cd, nl, -1);
	
	vector vabs;
	vabs = fabs(cd);
	double dMin, dMax;
	vabs.GetMinMax(dMin, dMax);
	
	
	double thr;
	switch(thrt)
	{
		case SQTWOLOG:
			/*'sqtwolog' threshold*/
			//	threshold = log10(length of signal)//sqrt(2);//*
			//thr = sqrt(2*log10(x.GetSize())); 
			//	threshold = log10(length of detail)//sqrt(2);//*
			thr = sqrt(2*log10(cd.GetSize())); 
			break;
			
		case CUSTOM:
			//if(thrv)
				//thr = thrv[0];
			//break;
			thr = thrd * dMax / 100.0;
			
		default:
		    break;		
		
	}
	
	/*discard the small data of cd with theshold */
	cd.Replace(thr,0,MATREPL_USE_ABSOLUTE_VALUE_IN_TEST|MATREPL_TEST_LESSTHAN);
	vC.SetSubVector(cd, nl);
	
	vector y;
	y.SetSize(x.GetSize());
	if(!multi_scale_idwt(nLevel,mode,y,filter,vC,vL))
	{
		//goto END;
		nag_free_wavfilter(&filter);
		XF_THROW(XFERR_WT_MULTI_IDWT_FAILED);
	}
	
	y.SetSize(nSignalLen);
	
	// Place results in the newly created output data range 
	///--Sandy 2008-11-21 when output has input x, should protect the source x
	//if (oy.SetData(&y, &vX))
	//------ Folger 11/27/08 QA80-12356 v8.0980 MORE_TOOLS_NEED_TO_HANDLE_INPUTS_WITH_MISSING_VALUE
	//if( !set_xyrange_data_ex(oy, &y, &vX, 0, iy) ) 
	if( !set_xyrange_data_ex(oy, &y, &vX, 0, iy, &vnMissingValsIndices) ) 
	//------
	{
		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	}
	else
	{
		///Arvin 08/16/07 QA70-10073 KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
		//DataPlot dp;
		// If user started from a graph, plot it.
		//dp = oy.MakePlot(iy);
		//LT_execute("legend -s");
		//dp.SetColorRGB(0xFF, 0x00, 0x00, TRUE);
		xf_check_plot_output_rng_in_source_rng_graph(iy, oy);
		///end KEEP_OUTPUT_CURVE_CUSTOMIZATION_AFTER_RECALCULATE_FOR_XF
		
		//Column col;
		//bool bRet = oy.GetXColumn(col);
		//bRet = col.SetLongName("WT Denoise");
		//bRet = oy.GetYColumn(col);
		//bRet = col.SetLongName("WT Denoise");		
	}
	
	
	  //END:
	
	nag_free_wavfilter(&filter);
	
	//------ Folger 07/28/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
	_set_output_range_comments(oy, iy, level, thrd, thrt, type);
	//------	
}

//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int wtdenoise_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return wtdenoise_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	return true;

}

int wtdenoise_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	return false;
}
//nGetNDialog = 0,1,2, corresponding to the XF GetN dropdown, 0 = dialog is not used
//you can change nRet to be one of XFEVT_PROCEED (defualt), XFEVT_ABORT, XFEVT_PROCEED_NO_DLG or XFEVT_PROCEED_WITH_DLG(when nGetNDialog = 0)
//nGetNDialog = -1 when Ok on GetN dialog to allow handler to preocess <auto> etc variables
//dwCntrl is combination of bits
//LTXF_FROM_GUI_MENU, LTXF_FROM_GUI_PROMPT, LTXF_FROM_AUTO_UPDATE, LTXF_FROM_FUNCTION, LTXF_THEME_USED, LTXF_CHANGE_PARAM
void wtdenoise_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	//------ fisher 11/16/07 ADD_MAP_ID_TO_CHM
	if(is_use_origin_chm())
		trGetN.SetAttribute(STR_HELPID_ATTRIB, IDD_XF_wtdenoise);
	
	if ( (dwCntrl&LTXF_THEME_USED) && nGetNDialog <= 0 )
	{
		int nSize;
		TreeNode trInput= trGetN.iy;
		XYRange xyi;	
		string strErrMsg;
		if ( true != get_error_for_input_xyrange(trInput, strErrMsg, nSize, xyi) )
			nRet = XFEVT_PROCEED_WITH_DLG;
	}
}
//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int wtdenoise_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}


// put your grid initialization here
// you may also initialize wksTemp here
static void GetNGraphPreview_OnInitGrid(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF, as requested in OnDialogSetup 
DWORD& dwUpdateGraph,  // default to 0, UPDATE_GRAPH_CHANGED to cause graphs to be updated, UPDATE_GRAPH_INVALID to disable preview button
DWORD& dwUpdateGrid, // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRAPH
	DECLARE_UPDATE_GRID

	bUpdateGraph = true;
	
	bOKEnable = _check_input_settings(trGetN, strErrMsg);
	
	//if ok, set data to temp worksheet
	///Kyle 07/28/2009 QA80-14026 FIX_WRONG_LEGEND_FOR_PREVIEW, always init the temp worksheet
	//if(bOKEnable)
	bUpdateGraph = bOKEnable;
	///End FIX_WRONG_LEGEND_FOR_PREVIEW
	{
		Worksheet wks = wksTemp;
		wks.SetSize(-1, 2, WSS_CLEAR_DATA);
		wks.SetColDesignations("XY");
		///Kyle 07/28/2009 QA80-14026 FIX_WRONG_LEGEND_FOR_PREVIEW
		//wks.Columns(1).SetLongName("avecurves");
		wks.Columns(1).SetLongName("WT Denoise");
		///End FIX_WRONG_LEGEND_FOR_PREVIEW
	}

	s_bInit = false;
	s_strErrMsg = strErrMsg; //keep the err message for OnInitGraph;

}

///////////////////////////////////////////////////////

// pgTemp is the graph for preview or control
// wksTemp is the the temp wks created to hold data to plot into pgTemp
static void GetNGraphPreview_OnInitGraph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF, as requested in OnDialogSetup  
DWORD& dwUpdateGrid, // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRID

	strErrMsg = s_strErrMsg; 
	///Jasmine 08/13/2010 ORG-172-S2 CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL
	//GraphPage gp = pgTemp;
	//page_load(gp, "NonePreview"); 	
	//
	//load_text_for_nonepreview_graphpage(gp, TEMPLATE_NONE_PREVIEW_CONTENT, TEMPLATE_NONE_PREVIEW_HINTS);
	xf_load_nopreview(pgTemp);
	///End CENTRALIZE_NOCLICK_BIT_FOR_PREVIEW_IN_OC_TOOL

}

///////////////////////////////////////////////////////

static void GetNGraphPreview_OnUpdateGraph(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp, PictureControl& pict)
{
	Worksheet wks = wksTemp;
	if(!s_bInit)
	{
		Worksheet wks = wksTemp;
		wks.SetSize(0,-1, true);

		init_preview_graph(trGetN.iy, pgTemp, wks, "CurvePreview");

		GraphPage gp = pgTemp;
		gp.Refresh(true);
		s_bInit = true;
	}

	_run_wtdenoise_on_current_data(trGetN, pgTemp, wks);

}

///////////////////////////////////////////////////////

static void GetNGraphPreview_OnChange(TreeNode& trGetN, TreeNode& trNode, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF that might be present, as requested in OnDialogSetup  
bool bChangedByGraph, // called when graph has been modified by user, like dragging a vertical line
DWORD& dwUpdateGraph,  // default to 0, UPDATE_GRAPH_CHANGED to cause graphs to be updated, UPDATE_GRAPH_INVALID to disable preview button
DWORD& dwUpdateGrid,  // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,	// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRAPH
	DECLARE_UPDATE_GRID
	
	bOKEnable = _check_input_settings(trGetN, strErrMsg, trNode);
	
	if (trNode && trNode.tagName =="iy")
	{
		s_bInit = false;
	}

	
	if(!bOKEnable)
		dwUpdateGraph = UPDATE_GRAPH_INVALID; //nUpdateGraph = UPDATE_GRAPH_ERROR;
	else
		bUpdateGraph = bOKEnable;


}

// called from OnInitDialog to allow options on setting up of dialog
// dwOptions = 0 (default) will create a line graph with data in a temp worksheet
// dwOptions = XFGSETUP_IMAGEGRAPH_CNTRL to create an image graph with data in a temp matrix book
// dwOptions = XFGSETUP_MATRIX_CNTRL to have a MatrixControl with data in a temp matrix book
// dwOptions = XFGSETUP_2_TABS | XFGSETUP_EMF_1ST to have a PictureControl on 1st tab and a GraphControl on 2nd tab
// vsTabTitles is empty on entering the event, but you can put tab title strings in this array.
static void GetNGraphPreview_OnDialogSetup(TreeNode& trGetN, WndContainer& theDlg, DWORD& dwOptions, vector<string>& vsTabTitles)
{

}

// called when dialog is being destroyed, either as OK button or as Cancel button being pressed
static void GetNGraphPreview_OnDestroy(TreeNode& trGetN, PageBase& pgTemp, Datasheet& wksTemp, PictureControl& pict)
{

}
//------------
//
static void GetNGraphPreview_OnCustomButton(TreeNode& trGetN, int nButton, PageBase& pgTemp, Datasheet& wksTemp,
PictureControl& pict, // optional tab for showing an image or EMF that might be present, as requested in OnDialogSetup  
bool bChangedByGraph, // called when graph has been modified by user, like dragging a vertical line
DWORD& dwUpdateGraph,  // default to 0, UPDATE_GRAPH_CHANGED to cause graphs to be updated, UPDATE_GRAPH_INVALID to disable preview button
DWORD& dwUpdateGrid,  // default to 0, set to UPDATE_GRID_SIMPLE to update the DynaControl grid, UPDATE_GRID_RESET to reset DynaControl grid
DWORD& dwEnables,	// bOKEnable, bBTN1Enable, bBTN2Enable and bBTN3Enable :default to true, can set to false to disable buttons
string& strErrMsg) // optional err msg to be shown on dialog
{
	DECLARE_BUTTON_ENABLES
	DECLARE_UPDATE_GRAPH
	DECLARE_UPDATE_GRID

}
//


///////////////////////////////////////////////////////
	
int GetNGraphBox_wtdenoise(TreeNode& trGetN, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg, PageBase& pgTemp, Datasheet& wksTemp, PictureControl& pict)
{
	return xf_GetNPreviewDlg_event_handler(trGetN, nRow, nCol, trNode, dwCntrl, nType, theDlg, pgTemp, wksTemp, pict,
	GetNGraphPreview_OnInitGrid, GetNGraphPreview_OnInitGraph,
	GetNGraphPreview_OnChange, GetNGraphPreview_OnUpdateGraph, GetNGraphPreview_OnDialogSetup, GetNGraphPreview_OnDestroy,
	GetNGraphPreview_OnCustomButton);	
}


//This file is the template for GetNEvent4

///////////////////////////////////////////////////////

