#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>

//------ Modification Log -----------------//
// CPY 5/28/2007 ADD_MORE_OPTIONS

//put additional include files here
#include <GetNbox.h>
enum{
	filter_size_range,
	filter_time_range
};


//put your own support static functions here
static void _add_path(vector<string>& vsFiles, LPCSTR lpcszPath)
{
	string strPath = lpcszPath;
	strPath.TrimRight('\\');
	strPath += '\\';
	for(int ii = 0; ii < vsFiles.GetSize(); ii++)
	{
		string str = strPath;
		str += vsFiles[ii];
		vsFiles[ii] = str;
	}
}
//---- CPY 5/28/2007 ADD_MORE_OPTIONS
static void _remove_path(vector<string>& vsFiles)
{
	for(int ii = 0; ii < vsFiles.GetSize(); ii++)
	{
		string str = GetFileName(vsFiles[ii]);
		vsFiles[ii] = str;
	}
}
//---
	
static void _get_filter_range_by_str_format(const string& strFilter, string& strFilterLowerBound, string& strFilterUpperBound, bool& bOneSideBound)
{
	int nPos = strFilter.Find('-');
	if(nPos < 0)
	{
		strFilterLowerBound = strFilter;
		strFilterUpperBound = strFilterLowerBound;
	}
	else
	{
		strFilterLowerBound = strFilter.GetToken(0, '-');
		strFilterUpperBound = strFilter.Right(strFilter.GetLength()-nPos-1);
	}
	
	if(strFilterLowerBound.IsEmpty() || strFilterUpperBound.IsEmpty())
		bOneSideBound = true;
	
	//removes newline, space, and tab characters
	strFilterLowerBound.TrimLeft();
	strFilterUpperBound.TrimLeft();
	strFilterLowerBound.TrimRight();
	strFilterUpperBound.TrimRight();
}

static void _check_filter_range(LPCSTR lpcszFilterName, double& dFilterLowerBound, double& dFilterUpperBound, bool& bFilter, bool bOneSideBound)
{
	string strFilterName(lpcszFilterName);

	//if all is missing, filter is invalid, just find files without filter 
	bFilter = (is_missing_value(dFilterLowerBound) && is_missing_value(dFilterUpperBound)) ? false : true;
	if(!bFilter)
		///Cheney 2007-6-18 UPDATE_XF_ERR_THROW
		//warning_msg_box(strFilterName + " range is invalid, will not use this filter", false);
		warning_msg_box(XFWARN_FINDFILE_RANGE_INVALID_NOT_USE_FILTER, strFilterName, false);
		///end UPDATE_XF_ERR_THROW
	
	//if dFilterLowerBound is missing, set it to 0. 
	//if dFilterUpperBound = 0, will set it to -1 first, then adjust it later. 
	if(bFilter && is_missing_value(dFilterLowerBound))
	{		
		dFilterLowerBound = 0.;
		
		if(!bOneSideBound)
			///Cheney 2007-6-18 UPDATE_XF_ERR_THROW
			//warning_msg_box(strFilterName + " lower bound is invalid, will set it to 0", false);
			warning_msg_box(XFWARN_FINDFILE_LOWER_BOUND_INVALID_SET_TO_0, strFilterName, false);
			///end UPDATE_XF_ERR_THROW
	}
	
	if(bFilter && is_missing_value(dFilterUpperBound))
		dFilterUpperBound = -1.;
	
	if(!bOneSideBound && dFilterUpperBound < dFilterLowerBound)
		///Cheney 2007-6-18 UPDATE_XF_ERR_THROW
		//warning_msg_box(strFilterName + " upper bound is invalid, will set it to infinite", false);
		warning_msg_box(XFWARN_FINDFILE_UPPER_BOUND_INVALID_SET_TO_INF, strFilterName, false);
		///end UPDATE_XF_ERR_THROW
}

static bool _is_filter_file(double dFileData, double dFilterLowerBound, double dFilterUpperBound, int nFilterType = filter_size_range)
{
	//if dFilterUpperBound < dFilterLowerBound, dFilterUpperBound will be invalid, no need to check as a rule
	if(dFilterUpperBound < dFilterLowerBound)
		dFilterUpperBound = (nFilterType == filter_size_range) ? dFileData : dFileData + 1.;
	
	if(nFilterType == filter_size_range)
		return (dFilterLowerBound > dFileData || dFilterUpperBound < dFileData) ? true : false;
	else
		return (dFilterLowerBound > dFileData || dFilterUpperBound <= dFileData) ? true : false;
}

static double _date_string_to_double(string& strDate)
{
	if(is_str_numeric_integer(strDate)) 
	{
		//must be 6 digits, else set to NANUM
		return (strDate.GetLength() == 6) ? str_to_date(strDate, LDF_YYMMDD) : NANUM;
	}
	else
	{
		return str_to_date(strDate, LDF_SHORT);
	}
}


void findFiles(const string& path, const string& ext, const string& size, const string& time, const int& addpath, string& fname)
{
	fname.Empty();
	
	if(!path.IsPath())
		XF_THROW(CER_INVALID_FILEPATH);
	
	//check input range whether is valid or not 
	bool bFilterSize = false;
	bool bFilterTime = false;
	
	//if input time range like 010203-, -060908, bTimeOneSideBound will be true.
	bool bSizeOneSideBound = false;
	bool bTimeOneSideBound = false;
	
	//get file size range
	double dSizeLowerBound, dSizeUpperBound;
	if(!size.IsEmpty())
	{
		string strSizeLowerBound, strSizeUpperBound;
		_get_filter_range_by_str_format(size, strSizeLowerBound, strSizeUpperBound, bSizeOneSideBound);
		dSizeLowerBound = atof(strSizeLowerBound, true);
		dSizeUpperBound = atof(strSizeUpperBound, true);
		_check_filter_range("size", dSizeLowerBound, dSizeUpperBound, bFilterSize, bSizeOneSideBound);
	}
	
	//get file modified date time range
	double dTimeLowerBound, dTimeUpperBound;
	if(!time.IsEmpty())		
	{
		string strTimeLowerBound, strTimeUpperBound;
		_get_filter_range_by_str_format(time, strTimeLowerBound, strTimeUpperBound, bTimeOneSideBound);
		//support YYMMDD(Must 6 digits) or YY/MM/DD or YYYY/MM/DD
		dTimeLowerBound = _date_string_to_double(strTimeLowerBound);
		dTimeUpperBound = _date_string_to_double(strTimeUpperBound) + 1; //if 6/8/7 - 06/8/8, should be 060807 00:00:00 - 060808 23:59:59
		_check_filter_range("time", dTimeLowerBound, dTimeUpperBound, bFilterTime, bTimeOneSideBound);
	}
	
	StringArray saFileNames;
	okutil_find_files_from_name_or_ext(&saFileNames, path, ext);
	StringArray saNamesOnly;
	saNamesOnly = saFileNames; //---- CPY 5/28/2007 ADD_MORE_OPTIONS
	_add_path(saFileNames, path);
	
	//if no such filter or filter rule is wrong, output all files' name 
	if((size.IsEmpty() && time.IsEmpty()) || (!bFilterSize && !bFilterTime))
	{
		if(addpath)
			file_name_array_to_str(fname, saFileNames);
		//---- CPY 5/28/2007 ADD_MORE_OPTIONS
		else 
			file_name_array_to_str(fname, saNamesOnly);
		//----
	}	
	//filtered some files by file size or modified date time
	else  
	{
		StringArray saFileNamesFiltered;
		for(int ii = 0; ii < saFileNames.GetSize(); ii++)
		{
			bool bFilterFile = false;
			if(!size.IsEmpty())
			{
				uint wFileSize;
				GetFileSize(saFileNames[ii], &wFileSize);	
				bFilterFile = _is_filter_file((double)wFileSize, dSizeLowerBound, dSizeUpperBound, filter_size_range);
			}
			
			if(!time.IsEmpty() && !bFilterFile)
			{
				double dLastWriteTime;
				if(!get_file_last_write_time_as_julian(saFileNames[ii], &dLastWriteTime))
					XF_THROW(XFERR_FAILED_GET_FILE_LAST_WRITE_TIME);
				
				bFilterFile = _is_filter_file(dLastWriteTime, dTimeLowerBound, dTimeUpperBound, filter_time_range);
			}
			
			if(!bFilterFile)
				saFileNamesFiltered.Add(saFileNames[ii]);
		}
		//---- CPY 5/28/2007 ADD_MORE_OPTIONS
		if(0==addpath)
			_remove_path(saFileNamesFiltered);
		//----
		file_name_array_to_str(fname, saFileNamesFiltered);
	}
	//----- CPY 5/28/2007 ADD_MORE_OPTIONS
	// caller can examine the result fname, so should not add message box inside
	/*
	if(fname.IsEmpty())
		warning_msg_box("No such file exists", false);
	*/
	//-----
	
}

//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 findFiles_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return findFiles_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	bOKEnable = true;
	//if change theme to factory default and not set path$, path will be empty, should set value
	///Cheney 2007-3-19 CMD_WIN_ALSO_NEED_SUPPORT_DEFAULT_PATH 
	//if((nEventID == GETNE_ON_INIT || nEventID == GETNE_ON_THEME) && trGetN.path.strVal.IsEmpty())
	if(trGetN.path.strVal.IsEmpty())
	///end CMD_WIN_ALSO_NEED_SUPPORT_DEFAULT_PATH
		trGetN.path.strVal = get_current_working_directory();
	
	if(!trGetN.path.strVal.IsEmpty() && !trGetN.path.strVal.IsPath())
	{
		strErrMsg = CER_INVALID_FILEPATH;
		bOKEnable = false;
	}
	
	return bOKEnable;

}

int findFiles_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 findFiles_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	//------- CPY 5/28/2007 ADD_MORE_OPTIONS
	// this is not really needed as this XF is mainly to be used from LT
	/*
	///Cheney 2007-3-19 CMD_WIN_ALSO_NEED_SUPPORT_DEFAULT_PATH 
	if(nGetNDialog > -1)
	{
		if(trGetN.path.strVal.IsEmpty())
			trGetN.path.strVal = get_current_working_directory();
	}
	///end CMD_WIN_ALSO_NEED_SUPPORT_DEFAULT_PATH*/
	//-------
}
//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 findFiles_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
