/*------------------------------------------------------------------------------*
 * File Name: tree_utils.c	 													*
 * Creation: May 07, 2003														*
 * Purpose: define tree utility functions										*
 * Copyright (c)2003 OriginLab Corp.											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *------------------------------------------------------------------------------*/
 
#include <origin.h> // main Origin C header that is precompiled and already include most headers 

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

#define PAGE_INFO_EXPORT		"Export"

////////////////////////////////////////////////////////////////////////////////////
// start your functions here

TreeNode tree_get_ini_section(TreeNode &trIni, LPCSTR lpcszSection)
{
	if( !trIni || NULL == lpcszSection )
		return false;
	TreeNode trIniSection;
	foreach(trIniSection in trIni.Children)
	{
		if( trIniSection.Name.IsValid() && 0 == lstrcmpi(lpcszSection, trIniSection.Name.strVal) )
			return trIniSection;
	}
	TreeNode trNull; // return invalid tree node
	return trNull;
}

bool tree_read_ini(TreeNode &trIni, LPCSTR lpcszFile)
{
	if( !trIni || NULL == lpcszFile )
		return false;
	INIFile iniFile(lpcszFile);
	return tree_read_ini(trIni, iniFile);
}

bool tree_read_ini(TreeNode &trIni, INIFile &iniFile)
{
	if( !trIni )
		return false;
	StringArray saIniSections;
	iniFile.GetSectionNames(saIniSections);
	for( int i = 0; i < saIniSections.GetSize(); i++ )
		tree_read_ini_section(trIni, iniFile, saIniSections[i]);
	return true;
}

bool tree_read_ini_section(TreeNode &trIni, LPCSTR lpcszFile, LPCSTR lpcszSection)
{
	if( !trIni || NULL == lpcszFile || NULL == lpcszSection )
		return false;
	INIFile iniFile(lpcszFile);
	return tree_read_ini_section(trIni, iniFile, lpcszSection);
}

bool tree_read_ini_section(TreeNode &trIni, INIFile &iniFile, LPCSTR lpcszSection)
{
	if( !trIni || NULL == lpcszSection )
		return false;
	
	string str = lpcszSection;
	str.MakeValidCName('S');
	
	TreeNode trIniSection = tree_get_ini_section(trIni, str);
	if( trIniSection )
	{
		trIniSection.Reset();
	}
	else // section not found
	{
		trIniSection = trIni.AddNode(str);
	}
	if( !trIniSection )
		return false;

	// If section name is not a valid identifier name
	// then store the original name in the label attribute.
	if( str.Compare(lpcszSection) )
	{
		trIniSection.SetAttribute(STR_LABEL_ATTRIB, lpcszSection);
	}
	
	TreeNode trIniKey;
	StringArray saIniKeyNames;
	iniFile.GetKeyNames(saIniKeyNames, lpcszSection);
	for( int i = 0; i < saIniKeyNames.GetSize(); i++ )
	{
		str = saIniKeyNames[i];
		str.MakeValidCName('K');

		trIniKey = trIniSection.AddNode(str);
		if( trIniKey )
		{
			if( str.Compare(saIniKeyNames[i]) )
				trIniKey.SetAttribute(STR_LABEL_ATTRIB, saIniKeyNames[i]);
			trIniKey.strVal = iniFile.ReadString(lpcszSection, saIniKeyNames[i]);
		}
	}
	return true;
}

bool tree_write_ini(TreeNode &trIni, LPCSTR lpcszFile, bool bClearSections)
{
	if( !trIni || NULL == lpcszFile )
		return false;
	INIFile iniFile(lpcszFile);
	return tree_write_ini(trIni, iniFile, bClearSections);
}

bool tree_write_ini(TreeNode &trIni, INIFile &iniFile, bool bClearSections)
{
	if( !trIni )
		return false;
	TreeNode trIniSection;
	foreach(trIniSection in trIni.Children)
		tree_write_ini_section(trIniSection, iniFile, bClearSections);
	return true;
}

bool tree_write_ini_section(TreeNode &trIniSection, INIFile &iniFile, bool bClearSection)
{
	if( !trIniSection )
		return false;

	string strSection;
	if( !trIniSection.GetAttribute(STR_LABEL_ATTRIB, strSection) || strSection.IsEmpty() )
		strSection = trIniSection.tagName;

	if( bClearSection )
		iniFile.WriteString(strSection, NULL, NULL); // delete ini file section

	string strKey;
	TreeNode trIniKey;
	foreach(trIniKey in trIniSection.Children)
	{
		if( !trIniKey.GetAttribute(STR_LABEL_ATTRIB, strKey) || strKey.IsEmpty() )
			strKey = trIniKey.tagName;
		iniFile.WriteString(strSection, strKey, trIniKey.strVal);
	}
	return true;
}

bool tree_write_ini_section(TreeNode &trIniSection, LPCSTR lpcszFile, bool bClearSection)
{
	if( !trIniSection || NULL == lpcszFile )
		return false;
	INIFile iniFile(lpcszFile);
	return tree_write_ini_section(trIniSection, iniFile, bClearSection);
}

///////////////////////////////////////
///// read/write image export settings
///////////////////////////////////////

bool tree_read_image_export_settings(TreeNode &trSettings, LPCSTR lpcszFormat)
{
	string str(lpcszFormat);;
	LabTalk.Image.Export.GetIni("a", "b", str);
	char szFile[MAX_PATH], szSec[MAX_PATH];
	if( !LT_get_str("%a", szFile, MAX_PATH) || !LT_get_str("%b", szSec, MAX_PATH) )
		return false;
	bool bRet;
	if( szSec[0] ) // if ini section specified
		bRet = tree_read_ini_section(trSettings, szFile, szSec);
	else
		bRet = tree_read_ini(trSettings, szFile);
	return bRet;
}

bool tree_write_image_export_settings(TreeNode &trSettings, LPCSTR lpcszFormat, bool bClearSections)
{
	string str(lpcszFormat);;
	//LabTalk.Image.Export.GetIni("a", "b", lpcszFormat);
	LabTalk.Image.Export.GetIni("a", "b", str);
	char szFile[MAX_PATH], szSec[MAX_PATH];
	if( !LT_get_str("%a", szFile, MAX_PATH) || !LT_get_str("%a", szSec, MAX_PATH) )
		return false;
	bool bRet;
	if( szSec[0] ) // if ini section specified
		bRet = tree_write_ini_section(trSettings, szFile, bClearSections);//, szSec);
	else
		bRet = tree_write_ini(trSettings, szFile, bClearSections);
	return bRet;
}

bool tree_get_page_image_export_settings(TreeNode &trSettings, Page &pg, LPCSTR lpcszFormat)
{
	/* This old code used page's ini storage
	pg.Info.Add(PAGE_INFO_EXPORT);
	storage st;
	st = pg.GetStorage(PAGE_INFO_EXPORT);
	if( st && st.GetSection(lpcszFormat, trSettings) )
		return true;
	return false;
	*/
	string str;
	str.Format(PAGE_INFO_EXPORT"%s", lpcszFormat);
	vector<byte> vb;
	if( pg.GetMemory(str, vb) )
	{
		if( str.SetBytes(vb) )
		{
			trSettings.XML = str;
			return true;
		}
	}
	return false;
}

bool tree_set_page_image_export_settings(TreeNode &trSettings, Page &pg, LPCSTR lpcszFormat, bool bClearSection)
{
	/* This old code used page's ini storage
	pg.Info.Add(PAGE_INFO_EXPORT);
	storage st;
	st = pg.GetStorage(PAGE_INFO_EXPORT);
	if( st )
	{
		if( bClearSection )
		{
			//---temp code until st.RemoveSection is implemented
			string strSection = lpcszFormat;
			pg.Info.Export.RemoveSection(strSection);
			//---
			//st.RemoveSection(lpcszFormat);
		}
		if( st.SetSection(lpcszFormat, trSettings) )
			return true;
	}
	return false;
	*/
	string str = trSettings.XML;
	vector<byte> vb;
	if( str.GetBytes(vb) )
	{
		str.Format(PAGE_INFO_EXPORT"%s", lpcszFormat);
		return pg.SetMemory(str, vb);
	}
	return false;
}

///////////////////////////////////////
///// general tree related utilities
///////////////////////////////////////

bool out_tree(TreeNode& tr, int nLevel) // = 0
{
	if(NULL==tr)
		return false;
	
	for(int ii = 0; ii < nLevel; ii++)
		printf("  ");
	
	if(tr.GetNodeCount() > 0) // branch node
	{
		printf("%s\n", tr.tagName);
		foreach(TreeNode cNode in tr.Children)
			out_tree(cNode, nLevel+1);
	}
	else // leaf node
		printf("%s = %s\n", tr.tagName, tr.Text);

	return true;
}

static string get_tree_node_attribute_as_str(const TreeNode& tr)
{
	vector<string> vsKnownAttributes = {
		STR_ENABLE_ATTRIB, STR_SHOW_ATTRIB, STR_ID_ATTRIB, STR_COMBO_ATTRIB, STR_LABEL_ATTRIB
	};
	string strRet;
	string strTemp;
	for(int ii = 0; ii < vsKnownAttributes.GetSize(); ii++)
	{
		if(tr.GetAttribute(vsKnownAttributes[ii], strTemp))
		{
			if(!strRet.IsEmpty())
				strRet += ",";
			strRet += vsKnownAttributes[ii] + "=" + strTemp;
		}
	}
	if(strRet.IsEmpty())
		return strRet;
	// add ()
	strTemp = "(" + strRet + ")";
	return strTemp;
}
	
			
static bool dump_tree(const TreeNode& tr, LPCSTR lpcsz, int nOutput, int nLevel)
{
	if(NULL==tr)
		return false;
	
	string strTemp = lpcsz;
	if(0==nLevel && lpcsz)
		strTemp.WriteLine(nOutput);
		
	for(int ii = 0; ii < nLevel; ii++)
	{
		strTemp = "  ";
		strTemp.Write(nOutput);
	}
	//--- attributes
	string strAttrib = get_tree_node_attribute_as_str(tr);
	
	if(tr.GetNodeCount() > 0) // branch node
	{
		strTemp = tr.tagName;
		strTemp += strAttrib;
		strTemp.WriteLine(nOutput);
		foreach(TreeNode cNode in tr.Children)
			dump_tree(cNode, NULL, nOutput, nLevel+1);
	}
	else // leaf node
	{
		strTemp.Format("%s%s = %s", tr.tagName, strAttrib, tr.Text);
		strTemp.WriteLine(nOutput);
	}

	return true;
}

bool tree_dump(const TreeNode& tr, LPCSTR lpcsz, int nOutput) // = NULL, WRITE_SCRIPT_WINDOW
{
	return dump_tree(tr, lpcsz, nOutput, 0);
}


static void treeNode_count(TreeNode& trNode, int& nLeafs, int& nBranches)
{	
	if(trNode.GetNodeCount() > 0 || trNode.ID == ONODETYPE_BRANCH) // branch node
	{
		int nSubBranches = 0;
		nBranches++;
		nLeafs += tree_count_items(trNode, &nSubBranches);
		nBranches += nSubBranches;
	}
	else
	{
		DWORD dwID = trNode.ID;
		DWORD dwBranchBits = ONODETYPE_BRANCH | ONODETYPE_BRANCH_COMPOSITE | ONODETYPE_BRANCH_DIALOG;
		if(dwID && (dwID & dwBranchBits)) // skip branch nodes
		{
			//out_int("skipped ", dwID);
			return;
		}
		//else
		//	out_int("not skipped ", dwID);
		nLeafs++;
	}
}

// count number of leafs in the given tree
// if lpnSections given, then count the number of branches that contain these leafs
int tree_count_items(TreeNode& tr, int* lpnSections)// = NULL);
{
	if(NULL==tr)
		return -1;
	
	int nLeafs = 0;
	//
	if(NULL==lpnSections)
	{
		if(tr.GetAttribute(THEME_COUNT_NAME, nLeafs))
			return nLeafs;
		
	}
	
	int nBranches = 0;
	foreach(TreeNode trN in tr.Children)
	{
		treeNode_count(trN, nLeafs, nBranches);
	}
	if(lpnSections)
		*lpnSections = nBranches;
	
	return nLeafs;
}


// consider a linearized tree and return node at given row number, with nRow = 0 to return the root
TreeNode tree_get_node(TreeNode& trRoot, int nRow, int* lpInc) // = NULL
{
	TreeNode cNode = trRoot.FirstNode;
	if(!cNode)
		return cNode;//NULL
	
	int nIndex = (lpInc)? *lpInc : 0;
	foreach(TreeNode trN in trRoot.Children)
	{
		if(nIndex == nRow)
			return trN;
		
		nIndex++;
		if(trN.GetNodeCount() > 0) // branch node
		{
			cNode = tree_get_node(trN, nRow, &nIndex);
			if(cNode)
				return cNode;
		}
	}

	if(lpInc)
		*lpInc = nIndex;
	
	// we cannot return NULL treeNode yet
	//return NULL;
	TreeNode trJunk;
	return trJunk;
}

int tree_copy_values(const TreeNode& trSrc, TreeNode& trDest, WORD wOptions)// = TREE_COPY_SKIP_HIDDEN | TREE_COPY_ATTRIB_ENABLE
{
	bool bSkipHidden = (wOptions & TREE_COPY_SKIP_HIDDEN) ? true : false;
	bool bCopyEnable = (wOptions & TREE_COPY_ATTRIB_ENABLE) ? true : false;
	int nCount = 0;
	foreach( TreeNode trSN in trSrc.Children )
	{
		TreeNode trDN = trDest.GetNode(trSN.tagName);
		if( trDN )
		{
			if( trSN.GetNodeCount() > 0 ) // branch node
				nCount += tree_copy_values(trSN, trDN, wOptions);
			else
			{
				if( !bSkipHidden || trSN.Show != 0 )
				{
					trDN.strVal = trSN.strVal;
					if( bCopyEnable )
						trDN.Enable = trSN.Enable;

					nCount++;
				}
			}
		}
	}
	return nCount;
}

//---- CPY 5/30/03 QA70-4577 EVENT_HANDLER_NEED_DIALOG_AND_VALUE_UPDATE

/**
	walk all tree nodes to delete specified attribute
	Parameters:
		tr = TreeNode to walk
		lpcszAttribute = attribute name to delete
	Returns:
		total number of nodes the specified attribute is deleted	
*/
int tree_remove_attribute(TreeNode& tr, LPCSTR lpcszAttribute)
{
	int nCount = 0;
	foreach(TreeNode cNode in tr.Children)
	{
		if(cNode.RemoveAttribute(lpcszAttribute))
			nCount++;
			
		
		if(cNode.GetNodeCount() > 0) // branch node
			nCount += tree_remove_attribute(cNode, lpcszAttribute);
	}
	return nCount;
}

// if bSet, then NULL will clear changed
bool tree_node_changed(TreeNode& trNode, bool bSet, LPCSTR lpcszOldValue) // = false, = NULL
{
	if(bSet)
	{
		if(lpcszOldValue)
			trNode.SetAttribute(STR_CHANGED_ATTRIB, lpcszOldValue);
		else
			trNode.RemoveAttribute(STR_CHANGED_ATTRIB);
		
		return true;
	}
	else // get
	{
		string strOldVal;
		if(trNode.GetAttribute(STR_CHANGED_ATTRIB, strOldVal))
			return true;
		
		return false;
	}
	return false;
}

static void tree_node_get_value(TreeNode& trNode, string& strVal)
{
	if(trNode.GetNodeCount() > 0) // branch node
		strVal.Empty();
	else
		strVal = trNode.strVal;
}
	
// vs is assumed to be empty on top level call
void tree_get_values(TreeNode& tr, vector<string>& vs)
{
	string strVal;
	foreach(TreeNode cNode in tr.Children)
	{		
		tree_node_get_value(cNode, strVal);
		vs.Add(strVal);
		if(cNode.GetNodeCount() > 0) // branch node
			tree_get_values(cNode, vs);
	}
}


/**
	 set numeric value as well as putting a descriptive string to the node
	Parameters:
		tr = TreeNode to set
		dVal = a numerical value to set
		lpcszLabel = a text label to associate
	Example:
		tree_node_set_value(trCalculation.t, tvalue, "t-Value");	
	Returns:
		false if tr is invalid
bool tree_node_set_double(TreeNode& tr, double dVal, LPCSTR lpcszLabel)
*/
	
/**
	 get both the numeric value of a tree node as well as its associated label
	Parameters:
		tr = TreeNode to get
		strLabel = the text label if present, otherwise the tagName
		dDefault = default value in case node is not a valid node
*/
double tree_node_get_value(TreeNode& tr, string& strLabel, double dDefault)// = _ONAN);
{
	strLabel.Empty();
	if(!tr.IsValid())
		return dDefault;
	
	if(!tr.GetAttribute(STR_LABEL_ATTRIB, strLabel))
		strLabel = tr.tagName;
	
	return tr.dVal;
}

int tree_node_get_int(TreeNode& tr, int nDefault)// = -1)
{
	if(tr)
		return tr.nVal;
	
	return nDefault;
}

// compare values in tree with those in vector and if diff, add attribute to remember
// return index into vs, which this function will increment according to the number of nodes
static int tree_count_and_update_changes(TreeNode& tr, const vector<string>& vs, int& nChanged, int nIndex = 0 )
{
	string strVal;
	foreach(TreeNode cNode in tr.Children)
	{		
		tree_node_get_value(cNode, strVal);
		if(strVal.Compare(vs[nIndex]) != 0)
		{
			tree_node_changed(cNode, true, vs[nIndex]);
			nChanged++;
		}
		else
			tree_node_changed(cNode, true);
		
		nIndex++;
		if(cNode.GetNodeCount() > 0) // branch node
			nIndex = tree_count_and_update_changes(cNode, vs, nChanged, nIndex);
	}
	return nIndex;
}

/**
	walk tree and store attribute "OldValue" into all the nodes that has different value then the specified string
	Parameters:
		tr = TreeNode to walk
		vs = a linearized array of string values that should map to every tree node
	Returns:
		total number of nodes that has OldValue attributes added (changed)
	Remark:
		the vs array can be obtained by tree_get_values.
		
*/
int tree_update_changes(TreeNode& tr, const vector<string>& vs)
{
	int nChanged = 0;
	tree_count_and_update_changes(tr, vs, nChanged);
	return nChanged;
}
//---- end CPY 5/30/03 
	
///////////////////////////////////////////////////////////
// page.info and tree 
///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
////////// Info Variables and TreeNode utilities ////////////
/////////////////////////////////////////////////////////////
#define STR_USER	"User"
#define STR_VARS	"Variables"
static string make_link_var_str(string& strStorage, string& strSection, string& strItem, int nPlotInLayer)
{
	string str;
	if(nPlotInLayer < NPLOT_FOR_WKS)
	{
		if(strStorage.CompareNoCase(STR_USER) == 0 && strSection.CompareNoCase(STR_VARS) == 0)
			str.Format("%%(%d, @W,%s)", nPlotInLayer, strItem);
		else
			str.Format("%%(%d, @W,%s.%s.%s)", nPlotInLayer, strStorage, strSection, strItem);
	}
	else
	{
		if(strStorage.CompareNoCase(STR_USER) == 0 && strSection.CompareNoCase(STR_VARS) == 0)
			str.Format("%%(%%H, @W,%s)", strItem);
		else
			str.Format("%%(%%H, @W,%s.%s.%s)", strStorage, strSection, strItem);
	}		
	return str;
}

//nPlotInLayer >=0 will add Data attribute into node for labtalk substition notation,
static bool tree_info_add_section(TreeNode& trNode, TreeNode& trSrc, string& strStorage, string& strSection, int nPlotInLayer)
{
	string strFolder = strStorage + "." + strSection;
	
	TreeNode trList = trNode.AddNode(strFolder);
	foreach(TreeNode trSrcItem in trSrc.Children)
	{
		string strItem = trSrcItem.tagName;
		string strStorageItem = strItem;
		int nID;
		if(trSrcItem.GetAttribute(STR_ID_ATTRIB, nID) && TRGP_STR == nID)
			strStorageItem += "$";
			
		TreeNode tr1;
		tr1 = trList.AddTextNode(trSrcItem.strVal, strItem);
		if(nPlotInLayer >= 0)
			tr1.SetAttribute(STR_DATA_ATTRIB, make_link_var_str(strStorage, strSection, strStorageItem, nPlotInLayer));
	}
	return true;
}

//bool tree_add_info(TreeNode& trNode, const OriginObject& orgObj, const string& strName, const string& strLabel, int nPlotInLayer) // = -1
bool tree_add_info(TreeNode& trNode, const OriginObject& orgObj, LPCSTR lpcszObjName, LPCSTR lpcszObjLabel, int nObjIndex ) // = NULL, = NULL, = -1
{
	if(!orgObj)
		return false;
	TreeNode trPage;
	string strName = lpcszObjName;
	if(!strName.IsEmpty())
	{
		string strLabel = lpcszObjLabel;
		
		trPage = trNode.AddNode(strName);
		trPage.SetAttribute(STR_LABEL_ATTRIB, strLabel);
	}
	else
		trPage = trNode;
	
	
	vector<string> vsStoreNames;
	if(orgObj.GetStorageNames(vsStoreNames))
	{
		for(int ii = 0; ii < vsStoreNames.GetSize(); ii++)
		{
			storage st;
			st = orgObj.GetStorage(vsStoreNames[ii]);
			vector<string> vsSectionNames;
			if(st.GetSectionNames(vsSectionNames))
			{
				for(int jj = 0; jj < vsSectionNames.GetSize(); jj++)
				{
					Tree trTemp;
					if(st.GetSection(vsSectionNames[jj], trTemp))
						tree_info_add_section(trPage, trTemp, vsStoreNames[ii], vsSectionNames[jj], nObjIndex);
				}
			}
		}
		return trPage.GetNodeCount()> 0? true : false;
	}
	return false;
}

////////////////////////////////////////////////////////////////////////
/////////// Saving and Loading of settings /////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
#define	STR_DEFAULT_SETTINGS_FILE_EXTENSION			"xml"
static string get_default_settings_folder_name(int nCategory)
{
	// must match enum {SETTINGS_MAIN, SETTINGS_GUI};
	vector<string> vsCategorys = {"", "GUI"};
	string strSubFolder;
	if(nCategory >= 0 && nCategory < vsCategorys.GetSize())
		strSubFolder = vsCategorys[nCategory];
	
	string strFolder = "DefaultSettings";
	if(!strSubFolder.IsEmpty())
		strFolder += "\\" + strSubFolder;
	
	return strFolder;  
}

void	save_default_settings(TreeNode& tr, LPCSTR lpcszClassName, int nCategory)
{
	string	strPath = GetAppPath() + get_default_settings_folder_name(nCategory);
	if( CheckMakePath(strPath) )
	{
		ASSERT(strPath.IsPath());
		string strFileName;
		strFileName.Format("%s\\%s.%s", strPath, lpcszClassName, STR_DEFAULT_SETTINGS_FILE_EXTENSION);
		Tree trTemp;
		trTemp = tr;
		tree_remove_attribute(trTemp, STR_COMBO_ATTRIB);//CPY 5/31/03, this will make the xml file smaller and easier to read
		trTemp.Save(strFileName);
	}
}

BOOL	load_default_settings(Tree& tr, LPCSTR lpcszClassName, int nCategory)
{
	string	strPath = GetAppPath() + get_default_settings_folder_name(nCategory);
	string strFileName;
	strFileName.Format("%s\\%s.%s", strPath, lpcszClassName, STR_DEFAULT_SETTINGS_FILE_EXTENSION);
	if( strFileName.IsFile() )
	{
		tr.Load(strFileName);
		return TRUE;
	}
	
	return FALSE;
}

/////////// dialog check boxes settings are stored in registry
static 	DWORD byte_array_to_bits(const vector<byte>& vn)
{
	DWORD dwTemp = 0;
	for(int ii = 0; ii < vn.GetSize(); ii++)
	{
		if(vn[ii] > 0)
			dwTemp += 1 << ii;
	}
	return dwTemp;
}
static void bits_to_byte_array(DWORD dw, vector<byte>& vn)
{
	vn.SetSize(0);
	DWORD dwTest = 1;
	for(int ii = 0; ii < 32; ii++)
	{
		if(dw & dwTest)
			vn.Add(1);
		else
			vn.Add(0);
		
		dwTest<<=1;
	}
}
#define STR_REG_DIALOGS "\\Dialogs\\"
#define STR_REG_CHECKBOX_KEY "CheckBoxes"

bool dlg_save_to_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, DWORD dwVal)
{
	Registry reg(HKEY_CURRENT_USER);
	string strKey = GetRegKey() + STR_REG_DIALOGS;
	strKey+= lpcszSecName;

	reg.SetValue(strKey, lpcszValName, dwVal);
	return true;
}
bool dlg_load_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, DWORD& dwVal)
{
	Registry reg(HKEY_CURRENT_USER);
	string strKey = GetRegKey() + STR_REG_DIALOGS;
	strKey+= lpcszSecName;
	dwVal = 0;
	if(reg.GetValue(strKey, lpcszValName, dwVal))
		return true;

	return false;
}
//save the given array of boolean values into a single DWORD in the registry
bool save_default_checkboxes(LPCSTR lpcszDlgName, const vector<byte>& vbValues, LPCSTR lpcszValName) // = NULL
{
	string strValName = lpcszValName;
	if(strValName.IsEmpty())
		strValName = STR_REG_CHECKBOX_KEY;
	
	return dlg_save_to_registry(lpcszDlgName, strValName, byte_array_to_bits(vbValues));
}
//retrive a array of boolean values saved by save_default_checkboxes in the registry
bool load_default_checkboxes(LPCSTR lpcszDlgName, vector<byte>& vbValues, LPCSTR lpcszValName) // = NULL
{
	string strValName = lpcszValName;
	if(strValName.IsEmpty())
		strValName = STR_REG_CHECKBOX_KEY;
	
	DWORD dwVal = 0;
	if(dlg_load_registry(lpcszDlgName, strValName, dwVal))
	{
		bits_to_byte_array(dwVal, vbValues);
		return true;
	}
	return false;
}


