#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	win_rect,
	win_welch,
	win_tri,
	win_bartlett,
	win_hanning,
	win_hamming,
	win_blackman,
	win_gauss,
	win_kaiser,
};
#include <event_utils.h>
#include <o8dlg.h>
#include <fft_utils.h>
#include <fftEx_utils.h>

///////////////////////////////////////////////////
// Modification log
/// Justin 2007-06-11 REOMVE_SLIDER
/// Justin 2007-06-11 SET_CORRECT_STATE_OF_CONTROL_EVEN_ERROR
///	Folger 12/19/07 SHOULD_COMPUTE_AND_CHECK_SAMPLING_INTERVAL_WHEN_INITIAL_OR_INPUT_CHANGE
///	Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
/// YuI 10/14/09 QA70-13728-P3 WRONG_AUTOSAMPLING_INTERVAL_IF_OUTPUT_PRODUCES_X_COLUMN
///////////////////////////////////////////////////

static int _get_x_size(TreeNode& trData)
{
	vector<complex> vx;
	if(!trData)
		return 0;
	
	
	okxf_resolve_tree_get_data_into_vector(&trData, &vx);
	
	return vx.GetSize();
	
}

static void _update_grid_hide_show(TreeNode& trGetN)
{
	trGetN.alpha.Show = (trGetN.win.nVal == Gaussian_Win);
	trGetN.beta.Show = (trGetN.win.nVal == Kaiser_Win);	
	
	/// Justin 2007-06-11 REOMVE_SLIDER
	/*
	//sandy change to use slider to control winlen, fftlen, and overlap
	int nSize1 = _get_x_size(trGetN.ix1);
	int nSize2 = _get_x_size(trGetN.ix2);
	int nSize = max(nSize1, nSize2);
	//if(min(nSize1, nSize2) > 2)
	if( nSize > 2)
	{		
	    ///jusitn 2007-03-28 v8.0591 RESET_FFT_WINDOW_OVERLABP_LENTHT_IF_NOT_RIGHT
		String str;
	    str.Format("Slider:%d|%d|%d",2,nSize,nSize);
		trGetN.fftlen.SetAttribute(STR_COMBO_ATTRIB,str);
		if(trGetN.fftlen.nVal > nSize)
		{
			trGetN.fftlen.nVal = nSize;
		}
	    str.Format("Slider:%d|%d|%d",1,trGetN.fftlen.nVal,trGetN.fftlen.nVal);
	    if(trGetN.winlen.nVal > trGetN.fftLen.nVal)
	    	trGetN.winlen.nVal = trGetN.fftLen.nVal;
	    ///End RESET_FFT_WINDOW_OVERLABP_LENTHT_IF_NOT_RIGHT
		trGetN.winlen.SetAttribute(STR_COMBO_ATTRIB,str);
		str.Format("Slider:%d|%d|%d",1,trGetN.winlen.nVal-1,trGetN.winlen.nVal-1);
		trGetN.overlap.SetAttribute(STR_COMBO_ATTRIB,str);
	    ///jusitn 2007-03-28 v8.0591 RESET_FFT_WINDOW_OVERLABP_LENTHT_IF_NOT_RIGHT
		if(trGetN.overlap.nVal >= trGetN.winlen.nVal)
	    	trGetN.overlap.nVal = trGetN.winlen.nVal/2;
	    ///End RESET_FFT_WINDOW_OVERLABP_LENTHT_IF_NOT_RIGHT
	}
	*/
	///END REOMVE_SLIDER	

}

/// Justin 2007-06-11 REOMVE_SLIDER
static bool _auto_set_winlen(TreeNode& trGetN)
{
	int nFFT = trGetN.fftlen.nVal;
	if(0 >= nFFT)
		return false;
	TreeNode trWin = trGetN.winlen;
	if(1 == octree_get_auto_support(&trWin) )
		trWin.nVal = nFFT;
	return true;
}
static bool _auto_set_overlap(TreeNode& trGetN)
{
	int nWin = trGetN.winlen.nVal;
	if(1 >= nWin)
		return false;

	TreeNode trOverLap = trGetN.overlap;
	if(1 == octree_get_auto_support(&trOverLap) )
		trOverLap.nVal = nWin/2;
	return true;	
}

static int _check_fft_win_overlap_size(int nFFTLength, int nWinLength, int nOverLap)
{
	if(nFFTLength < 2)
		return STFT_ERR_FFT_LENGTH_TOO_SMALL;

	if(nWinLength > nFFTLength)
		return STFT_ERR_WIN_LENGTH_TOO_LARGE;
	if(nWinLength < 2)
		return STFT_ERR_WIN_LENGTH_TOO_SMALL;
	
	if( (nWinLength - nOverLap) < 1)
		return STFT_ERR_OVERLAP_TOO_LARGE;
	if( nOverLap < 0 )
		return STFT_ERR_OVERLAP_TOO_SAMLL;
	return 0;
}

///END REOMVE_SLIDER

//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
static	void	_set_output_range_comments(XYRange &oy, const vector& ix1, const vector& ix2)
{
	string strComments;
	strComments.Format("coherence of %s, %s", get_input_data_range_string(ix1.GetSourceDataRange()), get_input_data_range_string(ix2.GetSourceDataRange()));
	oy.SetOutputComment(strComments);
}
//------ End BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS


void cohere(const vector& ix1, const vector& ix2, const double& interval, const int& fftlen, const int& win, const int& winlen, const int& overlap, const double& alpha, const double& beta, XYRange& oy)
{
	
	waitCursor junk;
	vector vSignal1, vSignal2;
	vSignal1 = ix1;
	vSignal2 = ix2;
	int nSize = vSignal1.GetSize();
	int nSize1 = vSignal2.GetSize();
	nSize = max(winlen, max(nSize, nSize1));
	vSignal1.SetSize(nSize);
	vSignal2.SetSize(nSize);
	
	// Check the arguments
	//if(winlen == -1)
		//winlen = nSize;
	//else if(winlen < 1)
		//XF_THROW(XFERR_INVALID_ARG);
	//
	//if(nfft == -1)
		//nfft = nw;
	//else if(nfft < 1)
		//XF_THROW(XFERR_INVALID_ARG);
	//
	//if(noverlap > nw)
		//XF_THROW(XFERR_INVALID_ARG);
		//check variable 
	if( fftlen <= 1 || winlen > fftlen || overlap >= winlen || overlap < 0)
		XF_THROW(XFERR_INVALID_ARG);
	
	// Create a window function
	vector vWindow(winlen);
	int nRet;
	if(nRet = get_window_data(win, winlen, vWindow, alpha, beta))
		XF_THROW(nRet);
	
	int nSelect = fftlen / 2 + 1;
	
	vector vOutX, vOutY;
	vOutY.SetSize(nSelect);
	if(nRet = fft_fft_coherence(nSize, vSignal1, vSignal2, nSelect, vOutY, winlen, vWindow, fftlen, overlap))
		XF_THROW(nRet);
	
	vOutX.Data(0, (nSelect -1)  / (interval * fftlen), 1 / ( interval* fftlen )  );//vOutX.Data(0, vOutY.GetSize() - 1); // Size of vOutY: nfft/2 + 1 ///Justin v8.0591 2007-03-28 SET_FREQUENCY
	if (!oy.SetData(&vOutY, &vOutX))
	{
		XF_THROW(XFERR_FAIL_IN_SET_XYRANGE_DATA);
	}
	
	//Column col;
	//bool bRet = oy.GetXColumn(col);
	//bRet = col.SetLongName(_L("Frequency") ); //bRet = col.SetLongName("Cohere");  ///Justin v8.0591 2007-03-28 SET_FREQUENCY
	//bRet = oy.GetYColumn(col);
	//bRet = col.SetLongName(_L("Cohere") ); //bRet = col.SetLongName("Cohere");  ///Justin v8.0591 2007-03-28 SET_FREQUENCY
	
	//------ Folger 07/23/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
	_set_output_range_comments(oy, ix1, ix2);
	//------
	
}

//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 cohere_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return cohere_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	////if(TRGP_ENUM_LIST != nCntrlType)
		////return false;
	////
	//////printf("nrow = %d, cntrl = %d\n", nRow, nCntrlType);	
	////if(nRow == 2 || nRow < 0) // the method row
	////{
	//trGetN.alpha.Show = false;
	//trGetN.beta.Show = false;
	//if(trGetN.win.nVal == Gaussian_Win || trGetN.win.nVal == Kaiser_Win)
	//{
		////bool bShowA = false;
		////bool bShowB = false;
		//switch(trGetN.win.nVal)
		//{
		//case Gaussian_Win:
			////bShowA = true;
			//trGetN.alpha.Show = true;
			//break;
		//case Kaiser_Win:
			////bShowB = true;
			//trGetN.beta.Show = true;
			//break;
		//}
		////trGetN.alpha.Show = bShowA;
		////trGetN.beta.Show = bShowB;
		//return true;
	//}
	//return false;
	
	//if(nEventID > 0)
	//{
		//return false;	
	//}
	
	///Justin 2007-03-28 v8.591 AUTO_COMPUTE_INTERVAL_WHEN_INITIALIZE
	//if(! (bOKEnable = get_error_for_2_input_double_vector(trGetN.ix1, trGetN.ix2, strErrMsg) ) )
		//return false;
	///Justin 2007-03-28 v8.591 AUTO_COMPUTE_INTERVAL_WHEN_INITIALIZE
	//if(! (bOKEnable = get_error_for_2_input_double_vector(trGetN.ix1, trGetN.ix2, strErrMsg) ) )
		//return false;
		
	///Justin 2007-04-04 ALWAYS_CHECK_AUTO_INTERVAL	
	//if(GETNE_ON_INIT == nEventID || !lstrcmpi(lpcszNodeName, "ix1")) 
	//{
		//strErrMsg = auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval);
		//int nErr =  check_interval(trGetN.interval);
		//if(nErr)
		//{
			//strErrMsg = nErr;
			//bOKEnable = false;
		//}
	//}
	///END ALWAYS_CHECK_AUTO_INTERVAL
	
	_update_grid_hide_show(trGetN);  ///Justin 2007-06-11 SET_CORRECT_STATE_OF_CONTROL_EVEN_ERROR
	
	
	//if(GETNE_ON_INIT == nEventID || !lstrcmpi(lpcszNodeName, "ix1") || !lstrcmpi(lpcszNodeName, "ix2"))
	//{
		if(! get_error_for_2_input_double_vector(trGetN.ix1, trGetN.ix2, strErrMsg)  )
		{
			bOKEnable = false;
			return false; 
		}
		////------ Folger 12/19/07 SHOULD_COMPUTE_AND_CHECK_SAMPLING_INTERVAL_WHEN_INITIAL_OR_INPUT_CHANGE
		//strErrMsg = auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval);
		//if ( atoi(strErrMsg) != 0 )
		//{
			//bOKEnable = false;
			//return false;
		//}
		////------
	//}
	//
	//------ Folger 12/19/07 SHOULD_COMPUTE_AND_CHECK_SAMPLING_INTERVAL_WHEN_INITIAL_OR_INPUT_CHANGE
	/////Justin 2007-04-04 ALWAYS_CHECK_AUTO_INTERVAL	
	//strErrMsg = auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval);
	//------
	/// YuI 10/14/09 QA70-13728-P3 WRONG_AUTOSAMPLING_INTERVAL_IF_OUTPUT_PRODUCES_X_COLUMN
	//	strErrMsg = auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval);
	strErrMsg = auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval, trGetN.oy);
	/// end WRONG_AUTOSAMPLING_INTERVAL_IF_OUTPUT_PRODUCES_X_COLUMN
	int nErr =  check_interval(trGetN.interval);
	if(nErr)
	{
		strErrMsg = nErr; 
		bOKEnable = false;
		return false;
	}
	///END ALWAYS_CHECK_AUTO_INTERVAL
	
	///END AUTO_COMPUTE_INTERVAL_WHEN_INITIALIZE	
	
	///Justin 2007-03-28 v8.591 RESET_FFT_WINDOW_OVERLABP_LENTHT_IF_NOT_RIGHT
	//int nRet;
	//if(!lstrcmpi(lpcszNodeName, "ix1") || !lstrcmpi(lpcszNodeName, "ix2") && nRow >= 0)
	//{
		/////justin 11/21/2006 
		////nRet = auto_compute_sampling_interval_from_InputData(trGetN);
		////if(nRet == CER_INVALID_TREENODE)
			////XF_THROW(CER_INVALID_TREENODE);
		////if(nRet != OE_NOERROR)
		////{
			////XF_TRACE("Warning : Can not compute valid interval by treenode, defalt setting is used!");
		////}
		////strErrMsg = auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval); 	///Justin 2007-03-28 v8.591 AUTO_COMPUTE_INTERVAL_WHEN_INITIALIZE
		/////end 
		//int nSize1 = _get_x_size(trGetN.ix1);
		//int nSize2 = _get_x_size(trGetN.ix2);	
		//int nSize = max(nSize1, nSize2);
		//trGetN.fftlen.nVal = nSize;
		//trGetN.winlen.nVal = trGetN.fftlen.nVal;
		//trGetN.overlap.nVal = trGetN.winlen.nVal/2;
		/////Justin 2007-03-28 v8.591 AUTO_COMPUTE_INTERVAL_WHEN_INITIALIZE
		///////justin 2007-3-23  CHECK_INTERVAL_IS_VALID
		////int nErr =  check_interval(trGetN.interval);
		////if(nErr)
		////{
			////strErrMsg = nErr;
			////bOKEnable = false;
		////}
		/////END CHECK_INTERVAL_IS_VALID
		/////Justin 2007-03-28 v8.591 AUTO_COMPUTE_INTERVAL_WHEN_INITIALIZE
	//
	//}	
	
	//_update_grid_hide_show(trGetN);  ///Justin 2007-06-11 SET_CORRECT_STATE_OF_CONTROL_EVEN_ERROR
	
		
	/// Justin 2007-06-11 REOMVE_SLIDER
	_auto_set_winlen(trGetN);
	_auto_set_overlap(trGetN);
	nErr = _check_fft_win_overlap_size(trGetN.fftlen.nVal, trGetN.winlen.nVal, trGetN.overlap.nVal);
	if(nErr)
	{
		strErrMsg = nErr;	
		bOKEnable = false; 
		return false;
	}
	///END REOMVE_SLIDER
	
	
	//if(lpcszNodeName == "ix1" || lpcszNodeName == "ix2")
	//{
		////Sandy 2006-8-25 for initialize parameters of stft
		//int nSize = _get_x_size(trGetN.ix1);
		//trGetN.fftlen.nVal = min(256, nSize);
		//trGetN.winlen.nVal = trGetN.fftlen.nVal;
		//trGetN.overlap.nVal = trGetN.winlen.nVal/2;
	//}
	
	//bOKEnable = (nRet == -1) ? false : true;	
	
	//auto_compute_params_value(trGetN, "fftlen", "winlen", "overlapp");
	///END RESET_FFT_WINDOW_OVERLABP_LENTHT_IF_NOT_RIGHT
	
	return true;
	

}

int cohere_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 cohere_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_cohere);
	
	if ( (dwCntrl&LTXF_THEME_USED) && nGetNDialog <= 0 )
	{ 
		string strErrMsg;
		if(! get_error_for_2_input_double_vector(trGetN.ix1, trGetN.ix2, strErrMsg) || 0 != check_interval(trGetN.interval) )
			nRet = XFEVT_PROCEED_WITH_DLG; 
	}
	
	if(0 == nGetNDialog || -1 == nGetNDialog)
	{
		///justin 11/21/2006
		//int nRet = auto_compute_sampling_interval_from_InputData(trGetN);
		//if(nRet != 0 && nRet != -1)
			//XF_TRACE("Warning : Time sequences should be monotonic increase!");
		//
		//double dInterval = trGetN.interval.dVal;
		//if(is_missing_value(dInterval))
			//nRet = XFEVT_ABORT;
		///Justin 2007-03-23 CHECK_INTERVAL_IS_VALID
		//int nRet = auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval, false);
		//if(nRet)
			//XF_WARN(nRet);
		/// YuI 10/14/09 QA70-13728-P3 WRONG_AUTOSAMPLING_INTERVAL_IF_OUTPUT_PRODUCES_X_COLUMN
		//	auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval); 
		auto_compute_sampling_interval_from_InputData(trGetN.ix1, trGetN.interval, trGetN.oy); 
		/// end WRONG_AUTOSAMPLING_INTERVAL_IF_OUTPUT_PRODUCES_X_COLUMN
		int nErr = check_interval(trGetN.interval);
		if(nErr)
		{
			XF_WARN(nErr);
			nRet = XFEVT_ABORT;
			return;
		}
		///END CHECK_INTERVAL_IS_VALID
		
			/// Justin 2007-06-11 REOMVE_SLIDER
		_auto_set_winlen(trGetN);
		_auto_set_overlap(trGetN);
		nErr = _check_fft_win_overlap_size(trGetN.fftlen.nVal, trGetN.winlen.nVal, trGetN.overlap.nVal);
		if(nErr)
		{
			XF_WARN(nErr);
			nRet = XFEVT_ABORT;
			return;
		}
	
		///END REOMVE_SLIDER
	
		///end 
		
	}	
}
//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 cohere_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
