/*------------------------------------------------------------------------------*
 * File Name:	FBFilter.h	 													*
 * Creation: 	Danice															*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * DG 3/17/05 v8.0204 CREATE													*
 * Forest 3/25/05 NEW_FILTER_GUI_DESIGN											*
 * DG 8/23/05 LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXISTED_FILTER					*
 * DG 9/14/05 QA70-7345	v8.0306 CLEAR_ALL_FOR_NO_FILTER							*
 * Jasmine 09/17/05 v8.0308 SET_AND_GET_THEME_FILE_NAME							*
 *	ML 2/14/2007 QA70-9374 BAD_EVENT_HANDLER_DWORDS_IN_TREENODES				*
 *------------------------------------------------------------------------------*/
 

#ifndef _FB_FILTER_H
#define _FB_FILTER_H

#include <GetNBox.h>
//#include "GetNDlg.h"
#include "theme_utils.h"
#define	STR_TYPE_FILE_NAME	okutil_get_origin_path(SYS_FOLDER) + "Help\\OCtypes.xml"
#define	STR_GF_INDEX_FILE_NAME	okutil_get_origin_path(SYS_FOLDER) + "Help\\OCGFindex.xml"
#define HOUR_GLASS					waitCursor junk;
#define	STR_FB_THEME_CLASS			"FunctionBrowser"
#define STR_FILTER_DLG_NAME 		"Function Browser Filter"
//#define STR_FIRST_EMPTY_LABEL		" "
#define	STR_CATEGORY_ATTRIB	"CT"
#define	STR_ALL_CATEGORY	"<All Categories>"
#define	STR_NO_FILTER		"<No Filter>"

enum{FB_QUREY_VALUE_ALL = 0, FB_QUREY_VALUE_ANY};
enum{FB_QUERY_EX_ALL_NOT_INCLUDE = 0, FB_QUERY_EX_ALL, FB_QUERY_EX_ANY};
//these IDs are shared by Parser
enum
{
	IDST_FB_FUNCTION = 0x2000,
	IDST_FB_ARGU_TYPE = 0x4000,
	IDST_FB_RETURN_TYPE
};

///---DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXISTED_FILTER : id too big, out of theme id ranges
/*
///Forest 3/25/05 NEW_FILTER_GUI_DESIGN
enum
{
	IDST_FB_ARGU_INCLUDE_START = 0x11200000,
	IDST_FB_ARGU_EXCLUDE_START = 0x11201000,
	IDST_FB_RETURN_START = 0x11202000
};
///End NEW_FILTER_GUI_DESIGN
*/
enum
{
	IDST_FB_ARGU_INCLUDE_START = 0x00110000,
	IDST_FB_ARGU_EXCLUDE_START = 0x00111000,
	IDST_FB_RETURN_START = 0x00112000
};
///---end LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXISTED_FILTER

typedef	struct
{
	//conditions for return type
	vector<string> vsIncludeRet;
	vector<string> vsExcludeRet;
	//conditions for argument type
	int		nIncludeMode;
	int		nExcludeMode;
	vector<string> vsIncludeArgu;
	vector<string> vsExcludeArgu;
}FBFilterOptions;

///Forest 04/01/05 ADD_ALL_DATA_TYPES
static bool get_all_data_types(vector<string>& vsTypes)
{	
	Tree	tr;
	if(!tr.Load(STR_TYPE_FILE_NAME))
		return	false;
	vsTypes.SetSize(0);
	foreach(TreeNode trItem in tr.Children)
		vsTypes.Add(trItem.strVal);
	return	true;
}
///End ADD_ALL_DATA_TYPES

void ConstructTypes(TreeNode& trBranch, int nIDstart)
{
	vector<string> vsDataTypes;
	get_origin_c_data_types(vsDataTypes);
	///Forest 04/06/05 ADD_POINTER_TYPE_FOR_TESTING
	vsDataTypes.Add("double*");
	vsDataTypes.Sort();
	///End ADD_POINTER_TYPE_FOR_TESTING
	for(int ii = 0; ii < vsDataTypes.GetSize(); ii++)
	{
		string strName = "T" + ii;
		TreeNode trType = trBranch.AddNumericNode(0, strName, TRGP_CHECK);
		trType.SetAttribute(STR_LABEL_ATTRIB, vsDataTypes[ii]);
		trType.SetAttribute(STR_DATAID_ATTRIB, nIDstart + ii + 2);
		//set event handler
		PEVENT_FUNC __dfn;
		if(nIDstart == IDST_FB_ARGU_INCLUDE_START)
			__dfn = _on_change_include_selection;
		else if(nIDstart == IDST_FB_ARGU_EXCLUDE_START)
			__dfn = _on_change_exclude_selection;
		else
			continue;
		DWORD _dw_fn = (DWORD)__dfn;
		if(_dw_fn)
		{
			string strTemp = _dw_fn;
			trType.SetAttribute(STR_ATTRIB_HANDLER, strTemp);
		}
	}
}

/*
///Forest 4/6/05 CHECK_POINTER
static void _pointer_type_change(TreeNode& tr, bool bChangeInclude)
{
	TreeNode trIn, trEx, trNode;
	if(bChangeInclude)
	{
		foreach(trIn in tr.ArguInclude.Children)
		{
			if(!_is_checkbox(trIn))
				continue;
			string strLabel;
			trIn.GetAttribute(STR_LABEL_ATTRIB, strLabel);
			if(strLabel.Find('*') >= 0)
			{
				if(trIn.nVal == 1)
				{
					strLabel = strLabel.Left(strLabel.GetLength() - 1);//remove "*"
					trNode = tr.ArguInclude.FindNodeByAttribute(STR_LABEL_ATTRIB, strLabel);
					if(trNode)
						trNode.nVal = 1;
				}
			}
			else if(trIn.nVal == 0)
			{
				strLabel += "*";
				trNode = tr.ArguInclude.FindNodeByAttribute(STR_LABEL_ATTRIB, strLabel);
				if(trNode)
					trNode.nVal = 0;
			}
		}
	}
	else
	{
		foreach(trEx in tr.ArguExclude.Children)
		{
			if(!_is_checkbox(trEx))
				continue;
			string strLabel;
			trEx.GetAttribute(STR_LABEL_ATTRIB, strLabel);
			if(strLabel.Find('*') >= 0)
			{
				if(trEx.nVal == 0)
				{
					strLabel = strLabel.Left(strLabel.GetLength() - 1);//remove "*"
					trNode = tr.ArguExclude.FindNodeByAttribute(STR_LABEL_ATTRIB, strLabel);
					if(trNode)
						trNode.nVal = 0;
				}
			}
			else if(trEx.nVal == 1)
			{
				strLabel += "*";
				trNode = tr.ArguExclude.FindNodeByAttribute(STR_LABEL_ATTRIB, strLabel);
				if(trNode)
					trNode.nVal = 1;
			}
		}
		
	}
}
///End CHECK_POINTER	
*/
static void _on_change_selection(TreeNode& tr, bool bChangeInclude)
{
	TreeNode trIn, trEx;
	//_pointer_type_change(tr, bChangeInclude);///Forest 4/6/05 CHECK_POINTER
	int iExMode = tr.ArguExclude.FindAll.nVal;
	for(trIn = tr.ArguInclude.FirstNode, trEx = tr.ArguExclude.FirstNode;
		trIn && trEx; trIn = trIn.NextNode, trEx = trEx.NextNode)
	{
		if(_is_checkbox(trIn))
		{
			if(iExMode == FB_QUERY_EX_ALL_NOT_INCLUDE && bChangeInclude)
			{
				trEx.nVal = 1 - trIn.nVal;
			}
			else if(trIn.nVal == 1 && trEx.nVal == 1)
			{		
				if(bChangeInclude)
					trEx.nVal = 0;
				else
					trIn.nVal = 0;
			}
		}
	}	
}

static bool _on_change_include_selection(TreeNode& tr, int nRow, int nType, Dialog& theDlg)
{
	_on_change_selection(tr, true);
	return	true;
}

static bool _on_change_exclude_selection(TreeNode& tr, int nRow, int nType, Dialog& theDlg)
{
	_on_change_selection(tr, false);
	return	true;
}

void	ConstructFBFilterGUI(TreeNode& tr)
{
	tr.Reset();	///DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER
	
	TreeNode trGUI = tr.AddNode("GUI");
	GETN_USE(trGUI);
	
	GETN_BEGIN_BRANCH(ArguInclude, "Arguments Include") GETN_ID_BRANCH(IDST_FB_ARGU_INCLUDE_START)
		GETN_LIST(FindAll, "", 1, "All of the following|Any of the following") GETN_ID(IDST_FB_ARGU_INCLUDE_START + 1)	///DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER : change default value from 0 to 1
	GETN_END_BRANCH(ArguInclude)	
	
	GETN_BEGIN_BRANCH(ArguExclude, "Arguments Exclude") GETN_ID_BRANCH(IDST_FB_ARGU_EXCLUDE_START)
		GETN_LIST(FindAll, "", 2, "Any Not in Include List|All of the following|Any of the following") GETN_ID(IDST_FB_ARGU_EXCLUDE_START + 1)	///DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER : change default value from 0 to 2
			GETN_OPTION_EVENT(_on_change_ex_mode) 
	GETN_END_BRANCH(ArguExclude)
	
	GETN_BEGIN_BRANCH(Return, "Return") GETN_ID_BRANCH(IDST_FB_RETURN_START)
		GETN_STR(FindAll, "", "Any of the following") GETN_ID(IDST_FB_RETURN_START + 1)
	GETN_END_BRANCH(Return)
	
	ConstructTypes(trGUI.Return, IDST_FB_RETURN_START);
	ConstructTypes(trGUI.ArguInclude, IDST_FB_ARGU_INCLUDE_START);
	ConstructTypes(trGUI.ArguExclude, IDST_FB_ARGU_EXCLUDE_START);
	trGUI.Return.FindAll.Enable = false;
	///------Forest 04/06/05, find node by attribute
	//trGUI.ArguInclude.double.nVal = 1;//default is to filter double return and double argu
	//trGUI.Return.double.nVal = 1;
	TreeNode trIncludeDouble = trGUI.ArguInclude.FindNodeByAttribute(STR_LABEL_ATTRIB, "double");
	trIncludeDouble.nVal = 1;
	TreeNode trReturnDouble = trGUI.Return.FindNodeByAttribute(STR_LABEL_ATTRIB, "double");
	trReturnDouble.nVal = 1;
	///------End
	
	trGUI.SetAttribute(STR_THEME_TYPE_ATTRIB, THTYPE_FB_FILTER);
	trGUI.SetAttribute(STR_CLASS_OPTION_NAME_ATTRIB, STR_FB_THEME_CLASS);
	theme_set_commment_to_gui_tree(trGUI, "Description");	
}

static bool _on_change_ex_mode(TreeNode& tr, int nRow, int nType, Dialog& theDlg)
{
	bool bEnable = true;
	if(tr.ArguExclude.FindAll.nVal == FB_QUERY_EX_ALL_NOT_INCLUDE)
	{
		bEnable = false;
		vector<int> vnSelections;
		foreach(TreeNode trIncludeArgu in tr.ArguInclude.Children)
		{
			if(_is_checkbox(trIncludeArgu))
				vnSelections.Add(trIncludeArgu.nVal);
		}
		int ii = 0;
		foreach(TreeNode trExcludeArgu in tr.ArguExclude.Children)
		{
			if(_is_checkbox(trExcludeArgu))
				trExcludeArgu.nVal = 1 - vnSelections[ii++];
		}
	}
	_set_checkbox_in_branch(tr.ArguExclude, bEnable);	
	return	true;
}

static void _set_checkbox_in_branch(const TreeNode& trBranch, bool bEnable)
{
	foreach(TreeNode tr in trBranch.Children)
	{
		if(_is_checkbox(tr))
			tr.Enable = bEnable;
	}
}

static bool _is_checkbox(const TreeNode& tr)
{
	int nID;
	if(!tr)
		return	false;
	return tr.GetAttribute(STR_ID_ATTRIB, nID) && nID == TRGP_CHECK;
}

static bool _is_checkbox_selected(const TreeNode& tr)
{
	return 	_is_checkbox(tr) && tr.nVal == 1;
}

class OCFBFilter
{
public:
	///DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER : Construct GUI one time is enough
	OCFBFilter()
	{
		ConstructFBFilterGUI(m_trGUI);
	}
	///end LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER
	
	void	SetSource(const TreeNode& trSource)
	{
		HOUR_GLASS
		m_trSource = trSource;
	}
	
	bool	GetResult(TreeNode& trResult)
	{
		HOUR_GLASS
		trResult = m_trResult;
		return	true;
	}
	
	bool	OpenGUI(LPCSTR lpcstr)
	{
		HOUR_GLASS
		//ConstructFBFilterGUI(m_trGUI);	///DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER
		string strTheme = lpcstr;
		
		///DG CLEAR_ALL_FOR_NO_FILTER
		/*
		//if(strTheme.Compare(STR_NO_FILTER) != 0)	///DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER : if using No Filter, we also want to clear the theme to no filter
			LoadThemeToGUI(lpcstr);
		*/
		if(strTheme.Compare(STR_NO_FILTER) != 0)
			LoadThemeToGUI(lpcstr);
		else
			ClearFilter();
		///end CLEAR_ALL_FOR_NO_FILTER
			
		///---DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER
		//if(!GetNBox(m_trGUI.GUI, STR_FILTER_DLG_NAME, "Please specify filter conditions", NULL, NULL, GetWindow(OGW_DB_ACTIVE_DLG), true, true))
		Window wnd=GetWindow(OGW_DB_ACTIVE_DLG);
		if(!GetNBox(m_trGUI.GUI, STR_FILTER_DLG_NAME, "Please specify filter conditions", NULL, NULL, wnd.GetSafeHwnd(), true, true))
		///---end LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER
			return	false;
		
		///Forest 04/06/04 SAVE_TO_LAST_USED_THEME
		//current last used mechanism is based on operation, use theme utility functions to implement it
		string strLastUsedTheme = okutil_theme_construct_filename(THEME_FILENAME_LAST_USED, THTYPE_FB_FILTER, ORIGIN_PATH_USER, THTYPESCOPE_ANALYSIS_CLASS, STR_FB_THEME_CLASS); 
		theme_save_settings(m_trGUI.GUI, strLastUsedTheme);
		///End SAVE_TO_LAST_USED_THEME
		return	DoFilter();
	}
	
	bool	SetFilterName(LPCSTR lpcstr)
	{
		HOUR_GLASS
		string strDispName = lpcstr;
		if(strDispName.Compare(STR_NO_FILTER) == 0)//no filter
		{
			m_trResult = m_trSource;
			return true;
		}
		//ConstructFBFilterGUI(m_trGUI);	///DG LOAD_COMBO_FILTER_BUG_WHEN_EDIT_EXIST_FILTER
		if(!LoadThemeToGUI(lpcstr))
			return	false;
		return	DoFilter();
	}
	//get last used theme name	
	bool	GetThemeName(string& strDispName)
	{
		///Forest 04/06/04 SAVE_TO_LAST_USED_THEME
		//return	theme_get_display_name(m_trGUI.GUI, strDispName);
		theme_get_display_name(m_trGUI.GUI, strDispName);
		if(strDispName.IsEmpty())
			strDispName = STR_LAST_USED;
		return	true;
		///End SAVE_TO_LAST_USED_THEME
	}
private:	
	bool	LoadThemeToGUI(LPCSTR	lpcstr)
	{
		///---Forest 04/04/05, use centralized code to init filter GUI
		/*
		string strDispName = lpcstr;
		string strFileName = theme_get_settings_file(strDispName, STR_FB_THEME_CLASS, THTYPE_FB_FILTER);
		return	theme_load_settings(m_trGUI.GUI, strFileName);
		*/
		string strClassOption = STR_FB_THEME_CLASS;
		theme_apply_and_set_attribute(m_trGUI.GUI, lpcstr, strClassOption, true);
		return	true;
		///---End
	}
	///DG CLEAR_ALL_FOR_NO_FILTER
	bool	ClearFilter()
	{
		string strNULL;
		TreeNode trGUI;
		trGUI=m_trGUI.GUI;
		//tree_set_file_name(trGUI, strNULL);	//clear for no filter///Jasmine 09/17/05 v8.0308 SET_AND_GET_THEME_FILE_NAME
		tree_set_theme_file_name(trGUI, strNULL);
		tree_clear_all_value(trGUI);
		return true;
	}
	///end CLEAR_ALL_FOR_NO_FILTER
	bool	DoFilter()
	{
		HOUR_GLASS
		GetFilterOptions();
		
		//filter return type
		Tree	trAfterFilterReturn;
		if( !tree_copy_by_filter(trAfterFilterReturn, m_trSource, IDST_FB_FUNCTION,
								TCF_INCLUDE_ANY, IDST_FB_RETURN_TYPE, m_sFilterOptions.vsIncludeRet,
								TCF_EXCLUDE_ANY, IDST_FB_RETURN_TYPE, m_sFilterOptions.vsExcludeRet))
			return false;
		if( !tree_copy_by_filter(m_trResult, trAfterFilterReturn, IDST_FB_FUNCTION,
								m_sFilterOptions.nIncludeMode, IDST_FB_ARGU_TYPE, m_sFilterOptions.vsIncludeArgu,
								m_sFilterOptions.nExcludeMode, IDST_FB_ARGU_TYPE, m_sFilterOptions.vsExcludeArgu))
			return false;
		return	true;
	}

	void	GetFilterOptions()	
	{
		//return type
		m_sFilterOptions.vsIncludeRet.SetSize(0);
		m_sFilterOptions.vsExcludeRet.SetSize(0);
		m_sFilterOptions.vsIncludeArgu.SetSize(0);
		m_sFilterOptions.vsExcludeArgu.SetSize(0);
		string strLabel;
		foreach(TreeNode trReturnType in m_trGUI.GUI.Return.Children)
		{
			if(_is_checkbox_selected(trReturnType))
			{
				trReturnType.GetAttribute(STR_LABEL_ATTRIB, strLabel);
				m_sFilterOptions.vsIncludeRet.Add(strLabel);
			}
		}
		//arguments
		m_sFilterOptions.nIncludeMode = m_trGUI.GUI.ArguInclude.FindAll.nVal;
		foreach(TreeNode trArguIncludeType in m_trGUI.GUI.ArguInclude.Children)
		{
			if(_is_checkbox_selected(trArguIncludeType))
			{
				trArguIncludeType.GetAttribute(STR_LABEL_ATTRIB, strLabel);
				m_sFilterOptions.vsIncludeArgu.Add(strLabel);
			}
		}
		
		m_sFilterOptions.nExcludeMode = m_trGUI.GUI.ArguExclude.FindAll.nVal;
		foreach(TreeNode trArguExcludeType in m_trGUI.GUI.ArguExclude.Children)
		{
			if(_is_checkbox_selected(trArguExcludeType))
			{
				trArguExcludeType.GetAttribute(STR_LABEL_ATTRIB, strLabel);
				m_sFilterOptions.vsExcludeArgu.Add(strLabel);
			}
		}
	}

private:
	Tree		m_trGUI;
	TreeNode	m_trSource;
	Tree		m_trResult;
	FBFilterOptions m_sFilterOptions;
};

#endif //_FB_FILTER_H



