/*------------------------------------------------------------------------------*
 * File Name: Tree_utils.h														*
 * Creation: CPY 3/17/03														*
 * Purpose: Origin C header for Tree and vsFlexGrid utilities that are 		 	*
 *	implemented in GetNBox.c													*
 * Copyright (c) OriginLab Corp.2003											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	RVD 9/3/2003 QA70-5078 v7.0682 PLOT_RANGE_APPLY								*
 *	CPY 10/21/03 QA70-4680 v7.5727 TREE_BRANCHESOPEN_CLOSE_REMEMBERED			*
 *------------------------------------------------------------------------------*/

#ifndef _TREE_UTILS.H
#define _TREE_UTILS.H

#include <Tree.h>
#include <settings.h>
#include <storage.h>

// const used in GetNBox for general purpose data type const
#define	TRGP_CHECK 		ONODETYPE_CHECKBOX
#define TRGP_ENUM_COMBO	ONODETYPE_DROPDOWN_NUMERIC_FLOAT
#define TRGP_STR_LIST	ONODETYPE_DROPLIST_STRINGS
#define TRGP_STR		ONODETYPE_EDIT_BOX_ONELINE_TEXT
#define TRGP_DOUBLE		ONODETYPE_EDIT_BOX_NUMERIC_FLOAT
#define TRGP_COLOR		ONODETYPE_DROPLIST_COLORS
#define TRGP_RANGE		ONODETYPE_EDIT_RANGE
#define TRGP_BRANCH		ONODETYPE_BRANCH

/** >Basic I/O
		quick display of a tree, only the tagName and Text are shown
	Parameters:
		tr = TreeNode to dump to output
		nLevel = 0, this function is called recursively inside, so there is no need to use this parameter from your code
	Returns:
		TRUE if given tree is a valid TreeNode
	See Also:
		tree_dump	
*/
bool out_tree(TreeNode& tr, int nLevel = 0);

/** >Basic I/O
		dump a tree to a specified output, also show standard attributes if any
	Parameters:
		tr = TreeNode to dump to output
		lpcsz = optional string to diplay before the dump
		nOutput = one of the constants defined in oc_const.h,
		enum {WRITE_SCRIPT_WINDOW, WRITE_STATUS_BAR, WRITE_OUTPUT_LOG, WRITE_MESSAGE_BOX, WRITE_COMPILER_OUTPUT};
		nLevel = 0, this function is called recursively inside, so there is no need to use this parameter from your code
	Returns:
		TRUE if given tree is a valid TreeNode
	See Also:
		out_tree	
*/
bool tree_dump(const TreeNode& tr, LPCSTR lpcsz = NULL, int nOutput = WRITE_SCRIPT_WINDOW); // = NULL, 0, 0

/** >Tree
	count number of leafs in the given tree
	Parameters:
		tr = TreeNode to count
		lpnSections = if given, then count the number of branches that contain these leafs
	Returns:
		total number of leafs
*/
int tree_count_items(TreeNode& tr, int* lpnSections = NULL);

/** >Tree
*/
TreeNode tree_get_node(TreeNode& trRoot, int nRow, int* lpInc = NULL);

enum {TREE_COPY_SKIP_HIDDEN = 0x0001, TREE_COPY_ATTRIB_ENABLE = 0x0002};

/** >Tree
*/
int tree_copy_values(TreeNode& trSrc, const TreeNode& trDest, WORD wOptions = TREE_COPY_SKIP_HIDDEN | TREE_COPY_ATTRIB_ENABLE);

/** >Tree
	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);

#define STR_ENABLE_ATTRIB		"Enable"
#define	STR_SHOW_ATTRIB		"Show"
#define STR_CHANGED_ATTRIB	"OldValue"
/// RVD 9/3/2003 QA70-5078 v7.0682 PLOT_RANGE_APPLY
#define	STR_PLOT_VIEW		"View"
#define	STR_PLOT_SETUP_DLG	"PlotSetupDlg"
/// end PLOT_RANGE_APPLY

/** >Tree
	if bSet, then NULL will clear changed
*/
bool tree_node_changed(TreeNode& trNode, bool bSet = false, LPCSTR lpcszOldValue = NULL);

/** >Tree
	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);

/**
	 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);
*/

/** >Tree
	 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_double(TreeNode& tr, string& strLabel, double dDefault = _ONAN);

/** >Tree
	 get int value from a tree node, whether it is valid or not
	Parameters:
		tr = TreeNode to get
		nDefault = default value in case node is not a valid node
*/
int tree_node_get_int(TreeNode& tr, int nDefault = 0);

/** >Tree
	walk tree and copy all the values into given string vector
	Parameters:
		tr = TreeNode to walk
		vs = a linearized array of string values that should map to every tree node
*/
void tree_get_values(TreeNode& tr, vector<string>& vs);

#ifdef _ORGOBJ_H

/** >Tree
	add all Info storage into given treenode
	Parameters:
		trNode = tree node to add info storage
		orgObj = Origin object, can be Page, Layer, Column
		lpcszObjName = name of the Origin object, if NULL, will use GetName
		lpcszObjLabel = label of the Origin object, if NULL, will use GetLabel
		nObjIndex = index >= 0 for additional info to be stored in the StrData of the tree node for each item, use NPLOT_FOR_WKS if this is for text label display in a worksheet
	Return:
		TRUE for success
*/
bool tree_add_info(TreeNode& trNode, const OriginObject& orgObj, LPCSTR lpcszObjName = NULL, LPCSTR lpcszObjLabel = NULL, int nObjIndex = -1);
#define NPLOT_FOR_WKS 100000	// a large enough number that is impossible for plot index

#endif //_ORGOBJ_H

// For reading/writing to/from ini files
#define SZ_TREE_INI_SECTION_NODE_PREFIX "section"
#define SZ_TREE_INI_KEY_NODE_PREFIX "key"

/** >Tree
	Get the tree node that represents a specified ini section.
	Parameters:
		trIni = tree node that represents an ini file
		lpcszSection = pointer to an ini section name
	Return:
		If a tree node representing the specified ini section then it is returned, else an invalid tree node is returned.
*/
TreeNode tree_get_ini_section(TreeNode &trIni, LPCSTR lpcszSection);

/** >Tree
	Read an ini file into a tree node.
	Parameters:
		trIni = tree node to receive the ini file
		lpcszSection = pointer to an ini file name
	Return:
		true for success, false for error
*/
bool tree_read_ini(TreeNode &trIni, LPCSTR lpcszFile);

/** >Tree
	Read an ini file into a tree node.
	Parameters:
		trIni = tree node to receive the ini file
		iniFile = the ini file to read from
	Return:
		true for success, false for error
*/
bool tree_read_ini(TreeNode &trIni, INIFile &iniFile);

/** >Tree
	Read an ini section into a tree node.
	Parameters:
		trIni = tree node to receive the ini section
		lpcszFile = pointer to an ini file name
		lpcszSection = pointer to an ini section name
	Return:
		true for success, false for error
*/
bool tree_read_ini_section(TreeNode &trIni, LPCSTR lpcszFile, LPCSTR lpcszSection);

/** >Tree
	Read an ini section into a tree node.
	Parameters:
		trIni = tree node to receive the ini section
		iniFile = the ini file to read from
		lpcszSection = pointer to an ini section name
	Return:
		true for success, false for error
*/
bool tree_read_ini_section(TreeNode &trIni, INIFile &iniFile, LPCSTR lpcszSection);

/** >Tree
	Write a tree node, that represents an ini file, to an ini file.
	Parameters:
		trIni = tree node representing an ini file
		lpcszFile = pointer to an ini file name
	Return:
		true for success, false for error.
*/
bool tree_write_ini(TreeNode &trIni, LPCSTR lpcszFile, bool bClearSections=false);

/** >Tree
	Write a tree node, that represents an ini file, to an ini file.
	Parameters:
		trIni = tree node representing an ini file
		iniFile = ini file to be written to
	Return:
		true for success, false for error
*/
bool tree_write_ini(TreeNode &trIni, INIFile &iniFile, bool bClearSections=false);

/** >Tree
	Write a tree node, that represents an ini section, to an ini file.
	Parameters:
		trIniSection = tree node representing an ini section
		iniFile = ini file to be written to
	Return:
		true for success, false for error
*/
bool tree_write_ini_section(TreeNode &trIniSection, INIFile &iniFile, bool bClearSection=false);

/** >Import Export
	Read the export settings, for a specified format, into a tree node.
	Parameters:
		trSettings = tree node to receive the settings
		lpcszFormat = pointer to the image format whose settings are to be read
	Return:
		true for success, false for error
*/
bool tree_read_image_export_settings(TreeNode &trSettings, LPCSTR lpcszFormat);

/** >Import Export
	Write the export settings, for a specified format, into a tree node.
	Parameters:
		trSettings = tree node containing the settings
		lpcszFormat = pointer to the image format whose settings are to be written
	Return:
		true for success, false for error
*/
bool tree_write_image_export_settings(TreeNode &trSettings, LPCSTR lpcszFormat, bool bClearSections=false);

/** >Import Export
	Get the image export settings from a page.
	Parameters:
		trSettings = tree node to receive the settings
		pg = page to get the settings from
		lpcszFormat = pointer to the image format
	Return:
		true for success, false for error
*/
bool tree_get_page_image_export_settings(TreeNode &trSettings, Page &pg, LPCSTR lpcszFormat);

/** >Import Export
	Set the image export settings into a page.
	Parameters:
		trSettings = tree node containing the settings
		pg = page to set the settings into
		lpcszFormat = pointer to the image format
	Return:
		true for success, false for error
*/
bool tree_set_page_image_export_settings(TreeNode &trSettings, Page &pg, LPCSTR lpcszFormat, bool bClearSection=false);


/**#
		It dumps into the appropriate output (output log and/or note window) according to the
		settings in the tree the trRep.Contents.Header.Table branch.
	Returns:
		true if OK, otherwise false.
*/
bool	tree_header_table_report(TreeNode &trRep);


/**#
		It retrieves the information from trRep.Settings about where the report should go
		(output log and/or a Note window) and how, and creates, if needed, the Note window
		for output.
	Paramaters:
		trRep=the Reporting branch.
		dwTarget=(output) it receives the information about where the report should go as a
					combination of bits:
					enum {
						TYPETARGET_NAMED_WINDOW			= 0x00000002UL,		// to the particular Notes window
						TYPETARGET_OUTPUTLOG			= 0x00000004UL,		// to output log
					};
		strNoteWnd=the name of the note window
		pbAppendToNote=the address of a BOOL to optionally return the information whether the report should
						be appended to the note window or the current contents of the note window should be replaced.

*/
bool	tree_reporting_prepare_targets(TreeNode &trRep, DWORD &dwTarget, string &strNoteWnd, BOOL *pbAppendToNote = NULL);

enum {SETTINGS_MAIN, SETTINGS_GUI};

/**# >Operation
*/
void 	save_default_settings(TreeNode& tr, LPCSTR lpcszClassName, int nCategory = SETTINGS_MAIN);

/**# >Operation
*/
BOOL	load_default_settings(Tree& tr, LPCSTR lpcszClassName, int nCategory = SETTINGS_MAIN);

/** >System
		Save the given array of boolean values into a single DWORD in the registry.
	Parameters:
		lpcszDlgName = name of the dialog, this is used as the section name in the registry under /Dialogs/lpcszDlgName
		vbValues = array of 1 and 0 that each will be assigned to a bit in the DWORD value saved into registry
		lpcszValName = Value name in registry to save, if not specified, CheckBoxes will be used
	Return:
		True for success, false for error.
*/
bool save_default_checkboxes(LPCSTR lpcszDlgName, const vector<byte>& vbValues, LPCSTR lpcszKey = NULL);

/** >System
		Setrive a array of boolean values saved by save_default_checkboxes in the registry.
	Parameters:
		lpcszDlgName = name of the dialog, this is used as the section name in the registry under /Dialogs/lpcszDlgName
		vbValues = array of 1 and 0 that each will represent each bit in the DWORD value saved into registry
		lpcszValName = Value name in registry to save, if not specified, CheckBoxes will be used
	Return:
		True for success, false if lpcszDlgName section does not have the item in registry.
*/
bool load_default_checkboxes(LPCSTR lpcszDlgName, vector<byte>& vbValues, LPCSTR lpcszValName = NULL);

/**#
*/
bool dlg_save_to_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, DWORD dwVal);
/**#
*/
bool dlg_load_registry(LPCSTR lpcszSecName, LPCSTR lpcszValName, DWORD& dwVal);


//---- CPY 10/21/03 QA70-4680 v7.5727 TREE_BRANCHESOPEN_CLOSE_REMEMBERED
// following class written by Xuan Sun

/** >Utility
	This Class can be used to compress byte vectors (1 and 0s) to hex strings, and to decompress
	hex strings back to byte vectors.
	
	Note: Since it converts every 4 bits to a hex char, so if there is less than 4 bits, 
	0's will be filled in. For example {1,0,1,0,1,1} will be converted to "AC", because 
	1010=10=A, and 1100=12=C, notice that two 0's are filled at the end in "1100". "AC"
	will be decompressed to {1,0,1,0,1,1,0,0}
*/
class BitsHex
{
public:

	/**
		convert a vector of 1's and 0's to a hex string
	*/
	bool BitsToHexStr(const vector<byte>& vn, string& strHex)
	{
		byte bb=0;
		byte bTemp=0;
		int jj=0;
		strHex.Empty();
		for(int ii=0;ii<vn.GetSize();ii++)
		{
			bTemp=vn[ii];
			bTemp<<=(7-jj);
			bb=bb|bTemp;
			jj+=1;
			
			//Convert every 4 bytes to one hex char
			if(jj>=4 || ii==(vn.GetSize()-1))
			{
				strHex += byteToHex(bb);
				jj=0;
				bb=0;
			}
		}
		
		return true;
	}
	
	/**
		convert a hex string to a vector of 1's and 0's
	*/
	bool HexStrToBits(const string& strHex, vector<byte>& vn)
	{	
		int nHex;
		char cHex;
		byte bTest;
		vn.SetSize(0);
		for(int ii=0; ii<strHex.GetLength(); ii++)
		{
			cHex = strHex[ii];
			
			// convert the hex to int first
			nHex = hexToInt(cHex);
			
			if (nHex<0)
				return false;
			
			bTest=1;
			bTest<<=3;
			for(int jj=0; jj<4; jj++)
			{
				//put 1's and 0's in the vector
				vn.Add((nHex&bTest)?1:0);
				bTest>>=1;
				//printf("%d",vn[vn.GetSize()-1]);
			}
		}
		//printf("\n");
		return true;
	}

	/**
		a little utility function
	*/
	void vector_out(const vector<byte>& vn)
	{
		for(int ii = 0; ii < vn.GetSize(); ii++)
			printf("%d", vn[ii]);
		printf("\n");
	}
private:

	/**
		convert a hex to an int(0 to 15), if error return -1
	*/
	int hexToInt(char cHex)
	{
		int nInt;
		if(cHex>='0' && cHex<='9')
			nInt = cHex - '0';
		
		else if(cHex>='a' && cHex<='z')
			nInt = cHex - 'a' + 10;
		
		else if(cHex>='A' && cHex<='Z')
			nInt = cHex - 'A' + 10;
		
		else
			return -1;
		
		return nInt;
	}

	/**
		use the high four bits to convert to a hex char
	*/
	char byteToHex(byte bb)
	{
		char cHex;
		byte bTest = 1;
		bTest<<=4;
		int nConvert=0;
		
		for(int ii=0; ii<4; ii++)
		{
			if(bTest&bb)
			{
				// convert byte to int first
				nConvert += 1<<ii;
			}
			
			bTest<<=1;
		}
		
		if(nConvert<=9)
		{
			cHex = '0'+ nConvert;
		} 
		else
		{
			cHex = 'A'+ (nConvert-10);
		}
		
		return cHex;
	}

};
//---- end TREE_BRANCHESOPEN_CLOSE_REMEMBERED
#endif //_TREE_UTILS.H
