/*------------------------------------------------------------------------------*
 * File Name: XMLPackage.c	 													*
 * Purpose: OriginC code to handle Origin Package Builder dialog				*
 * Copyright (c) OriginLab Corp. 2005											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	CPY 12/19/05 USE_ID_COPY_TO_ENSURE_TREE_VALIDITY_ON_LOADING_OPX				*
 * EJP 2007-01-12 v8.0541 QA70-9103 NOTIFY_USER_FILE_ALREADY_IN_PKG				*
 * EJP 2007-06-19 v8.0645 QA70-9103 INSTALL_PKG_FROM_PKGMGR						*
 * EJP 2007-07-11 v8.0658 QA70-9103 EXTRACT_FILES_FROM_OPX						*
 * EJP 2007-10-25 v8.0734 QA70-10570 IMPROVE_PATH_INFO_IN_OPX_PACKAGES			*
 * EJP 2007-12-06 v8.0763 FIX_PKG_MGR_MENU_WHEN_CHANGE_ORIGIN_LANG				*
 * Jasmine 10/23/08 QA80-12442 SHOW_WARNING_WHEN_SAVE_READ_ONLY_FILE			*
 * EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES					*
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
#define BASE_WINDOW MultiPaneDlg
#include "DialogEx.h"
#include "TreeEditEvents.h"

#define STR_DLG_NAME "XMLPackageWindow" 
#define STR_DEFAULT_PKG_FILE_NAME "Untitled"

#define ENABLE_OPK_SUPPORT 1
#define OPK_NAME_SUFFIX " (OPK)"

/// EJP 2007-01-12 v8.0541 QA70-9103 NOTIFY_USER_FILE_ALREADY_IN_PKG
#define SZ_PKG_MGR_NAME		_L("Package Manager")
/// end NOTIFY_USER_FILE_ALREADY_IN_PKG

//////////////////// EJP TEMP: begin temporary code for testing
/*
typedef enum {
	IDE_PKG_ORIGIN_VER_REQ				= 1, // version of Origin required by the package
	IDE_PKG_NAME						= 2, // full name of what is in the package
	IDE_PKG_DESCRIPTION					= 3, // description of what is in the package
	IDE_PKG_VERSION						= 4, // version of what is in the package
	IDE_PKG_AUTHOR						= 5, // who made this package?
	IDE_PKG_TOOLBAR_FILE				= 6, // name of the toolbar file to be installed, optional
	IDE_PKG_CODE_BEFORE					= 7, // code to execute before installation begins, optional
	IDE_PKG_CODE_AFTER					= 8, // code to execute after, and if, installation succeeds, optional
	IDE_PKG_COMPRESSED_FILES			= 9, // this node contains the compressed files

	// All the group/branch nodes
	IDE_PKG_CODE_GROUP					= 500,
	IDE_PKG_INFO_GROUP					= 501,
	IDE_PKG_TOOLBAR_GROUP				= 502,

} IDE_PKG_ID;
*/
//////////////////// EJP TEMP: end temporary code for testing

typedef enum {
	IDE_PKG_TOOLBAR_FILE				= 6, // name of the toolbar file to be installed, optional
	IDE_PKG_SOURCE_PATH					= 11, // where the files to pack come from
} IDE_PKG_ID;

/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
class PackageGridCtrl : public GridListControl // GridListControl derived from public GridControl
{
public:
	enum {
		OUL_NAME_COL = 0,
		OUL_VERSION_COL,
		OUL_DESCRIPTION_COL,
		OUL_AUTHOR_COL,
		OUL_NUM_COLS
	};

	PackageGridCtrl()
	{
	}

	void Init(int nID, WndContainer& dlg)
	{
		GridListControl::Init(nID, dlg);
		SetAlternateRowColors();

		SetupRowsCols(1, 0, 1, 4);
		m_flx.Editable = flexEDKbdMouse;//flexEDNone;
		m_flx.ExtendLastCol = TRUE;
		m_flx.AllowUserResizing = flexResizeColumns;

		m_flx.SelectionMode = flexSelectionByRow;//flexSelectionFree;flexSelectionListBox;flexSelectionByRow
		m_flx.AllowSelection = false;
		
		m_flx.ColWidthMin = 4;
		m_flx.ColWidthMax = 0;

		SetColHeading(OUL_NAME_COL, _L("Name"));
		SetColHeading(OUL_VERSION_COL, _L("Version"));
		SetColHeading(OUL_DESCRIPTION_COL, _L("Description"));
		SetColHeading(OUL_AUTHOR_COL, _L("Author"));

		AutoSize();
	}

	void AutoSize()
	{
		m_flx.AutoSizeMode = flexAutoSizeColWidth;
		m_flx.AutoSize(0, m_flx.Cols - 1, false, 0);
	}

	void ResetContent()
	{
		m_flx.Rows = 1;
	}

	int GetSelCount()
	{
		vector<uint> vnRows;
		GetSelRows(vnRows);
		return vnRows.GetSize();
	}		

	void AddPackage(StringArray& sa, DWORD dwData = 0)
	{
		int i = m_flx.Rows;
		m_flx.Rows = i + 1;
		SetCell(sa[0], flexcpText, i, OUL_NAME_COL); // 0 = name
		SetCell(sa[1], flexcpText, i, OUL_VERSION_COL); // 1 = version
		SetCell(sa[2], flexcpText, i, OUL_DESCRIPTION_COL); // 2 = description
		SetCell(sa[3], flexcpText, i, OUL_AUTHOR_COL); // 3 = author

		SetRowData(i, dwData);
		AutoSize();
	}

	bool GetChildNodeStr(string& strValue, TreeNode& tn, LPCSTR lpcszChildNodeName)
	{
		TreeNode tnChild;
		tnChild = tn.GetNode(lpcszChildNodeName);
		if (tnChild)
		{
			strValue = tnChild.strVal;
			return true;
		}
		return false;
	}

	bool GetChildNodeDouble(double& dValue, TreeNode& tn, LPCSTR lpcszChildNodeName)
	{
		TreeNode tnChild;
		tnChild = tn.GetNode(lpcszChildNodeName);
		if (tnChild)
		{
			dValue = tnChild.dVal;
			return true;
		}
		return false;
	}

	void AddPackage(TreeNode &tnPkg, DWORD dwData = 0)
	{
		TreeNode tnPkgInfo;
		tnPkgInfo = tnPkg.GetNode("Package");
		if (tnPkgInfo)
		{
			StringArray sa;
			sa.SetSize(4);

			if (!GetChildNodeStr(sa[0], tnPkgInfo, "Name"))
				return;

			double dVal;
			if (!GetChildNodeDouble(dVal, tnPkgInfo, "Version"))
				dVal = 0.0;
			sa[1].Format("%f", dVal);

			if (!GetChildNodeStr(sa[2], tnPkgInfo, "Description"))
				sa[2].Empty();


			if (!GetChildNodeStr(sa[3], tnPkgInfo, "Author"))
				sa[3].Empty();

			AddPackage(sa, dwData);
		}
	}

	void AddPackage(LPCSTR lpcszName, DWORD dwData = 0)
	{
		StringArray sa;
		sa.SetSize(4);
		sa[0] = lpcszName;
		AddPackage(sa, dwData);
	}

	bool GetPackage(string& strName, int nRow)
	{
		int i = m_flx.Rows;
		if (nRow < 1 && i < nRow)
			return false;
		strName = GetCell(flexcpText, nRow, OUL_NAME_COL);
		return true;
	}

};
/// end SHOW_INFO_FOR_INSTALLED_PACKAGES


class UninstallPackageDlg : public Dialog
{
public:
	UninstallPackageDlg() : Dialog(IDD_PKG_LIST, "ODlg8")
	{
	}
	
	~UninstallPackageDlg()
	{
	}

	int DoModal(HWND hWndParent=NULL, DWORD dwOptions = 0, LPCSTR OpsName = NULL)
	{
		InitMsgMap();// will be called from internal later
		return Dialog::DoModal(hWndParent, dwOptions, OpsName);
	}

	EVENTS_BEGIN
		ON_INIT(OnInit)
		ON_DESTROY(OnDestroy)

		ON_BN_CLICKED(IDOK, OnClose)
		ON_BN_CLICKED(IDC_PKG_UNINSTALL, OnUninstall)

		/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
		///ON_LBN_SELCHANGE(IDC_PKG_NAME_LIST, OnChangeSelection)
		ON_GRID_SEL_CHANGE(IDC_PKG_LIST, OnChangeSelection)
		/// end SHOW_INFO_FOR_INSTALLED_PACKAGES
	EVENTS_END

protected:
	BOOL OnInit()
	{
		/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
		///m_lbPkgList = GetDlgItem(IDC_PKG_NAME_LIST);
		m_pkgList.Init(IDC_PKG_LIST, *this);
		/// end SHOW_INFO_FOR_INSTALLED_PACKAGES

		m_btnUninstall = GetDlgItem(IDC_PKG_UNINSTALL);

		UpdateList();
		return TRUE;
	}

	BOOL OnDestroy()
	{
		return TRUE;
	}

	BOOL OnClose(Control ctrl)
	{
		return TRUE;
	}

	BOOL OnUninstall(Control ctrl)
	{
		vector<uint> vSel;

		/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
		///m_lbPkgList.GetSelItems(vSel);
		m_pkgList.GetSelRows(vSel);
		/// end SHOW_INFO_FOR_INSTALLED_PACKAGES
		
		String strName;
		int nRet;
		BOOL bIsOPK;

		for( int i = 0; i < vSel.GetSize(); i++ )
		{
			/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
			///m_lbPkgList.GetText(vSel[i], strName);
			m_pkgList.GetPackage(strName, vSel[i]);
			/// end SHOW_INFO_FOR_INSTALLED_PACKAGES
			if( !strName.IsEmpty() )
			{
				/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
				string strMsg = _L("Are you sure you want to uninstall the package\n") + strName;
				if( IDNO == MessageBox(GetSafeHwnd(), strMsg, _L("Uninstall Package"), MB_YESNO) )
					continue;
				/// end SHOW_INFO_FOR_INSTALLED_PACKAGES

#ifdef ENABLE_OPK_SUPPORT
				/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
				///bIsOPK = m_lbPkgList.GetItemData(vSel[i]);
				bIsOPK = m_pkgList.GetRowData(vSel[i]);
				/// end SHOW_INFO_FOR_INSTALLED_PACKAGES
				if( bIsOPK )
					nRet = UninstallOPK(strName);
				else
#endif // ENABLE_OPK_SUPPORT
					nRet = okutil_uninstall_package_file(strName);

				if( nRet )
				{
					String strMsg;
					strMsg.Format(_L("Failed to uninstall package\n%s"), strName);
					MessageBox(GetSafeHwnd(), strMsg, _L("Uninstall Package"));
				}
			}
		}

		UpdateList();
		return TRUE;
	}

	void UpdateList()
	{
		/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
		/*
		StringArray saNames;
		if( okutil_get_installed_package_names(&saNames) )
			out_str("Failed to get names of installed packages.\n");

		int nItem;
		m_lbPkgList.ResetContent();
		for( int n = 0; n < saNames.GetSize(); n++ )
		{
			nItem = m_lbPkgList.AddString(saNames[n]);
#ifdef ENABLE_OPK_SUPPORT
			if( nItem >= 0 )
				m_lbPkgList.SetItemData(nItem, FALSE); // FALSE = is not OPK
#endif // ENABLE_OPK_SUPPORT
		}
		*/
		m_pkgList.ResetContent();

		string strFileName;
		strFileName = GetAppPath() + "OPXList.xml";

		Tree trPackages;
		if (trPackages.Load(strFileName))
		{
			foreach (TreeNode tn in trPackages.Children)
				m_pkgList.AddPackage(tn);
		}
		/// end SHOW_INFO_FOR_INSTALLED_PACKAGES

#ifdef ENABLE_OPK_SUPPORT
		AppendOPKNames();
#endif // ENABLE_OPK_SUPPORT

		UpdateUninstallButton();
	}
	
	/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
	///	BOOL OnChangeSelection(Control ctrl)
	///	{
	///		UpdateUninstallButton();
	///		return TRUE;
	///	}
	void OnChangeSelection(Control cntrl)
	{
		UpdateUninstallButton();
	}
	/// end SHOW_INFO_FOR_INSTALLED_PACKAGES

	void UpdateUninstallButton()
	{
		/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
		///int nSelCount = m_lbPkgList.GetSelCount();
		///m_btnUninstall.Enable = (0 < nSelCount);
		if (m_btnUninstall)
		{
			int nSelCount = m_pkgList.GetSelCount();
			m_btnUninstall.Enable = (0 < nSelCount);
		}
		/// end SHOW_INFO_FOR_INSTALLED_PACKAGES

	}

#ifdef ENABLE_OPK_SUPPORT
	int GetOPKNames(StringArray& saNames)
	{
		double dCount;
		LT_get_var("OPack.Installed#", &dCount);
		int nCount = dCount;
		if( 0 == nCount )
			return 0;

		char szName[MAXFULLPATH];
		string strProp;
		for( int n = 1; n <= nCount; n++ )
		{
			strProp.Format("OPack.Installed%d$", n);
			LT_get_str(strProp, szName, MAXFULLPATH);
			if( lstrlen(szName) > 0 )
				saNames.Add(szName);
		}

		return saNames.GetSize();
	}

	int AppendOPKNames()
	{
		StringArray saNames;
		if( GetOPKNames(saNames) )
		{
			string strName;
			int nItem;
			for( int n = 0; n < saNames.GetSize(); n++ )
			{
				strName = saNames[n] + OPK_NAME_SUFFIX;

				/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
				///nItem = m_lbPkgList.AddString(strName);
				///if( nItem >= 0 )
				///	m_lbPkgList.SetItemData(nItem, TRUE); // TRUE = is OPK
				m_pkgList.AddPackage(strName, 1); // 1 = is OPK
				/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
			}
			return saNames.GetSize();
		}
		return -1; // error
	}

	int UninstallOPK(LPCSTR lpcszName)
	{
		char szName[MAXFULLPATH];
		lstrcpyn(szName, lpcszName, lstrlen(lpcszName) - lstrlen(OPK_NAME_SUFFIX) + 1);
		return LabTalk.OPack.Uninstall(szName);
	}
#endif // ENABLE_OPK_SUPPORT

private:
	/// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
	///ListBox m_lbPkgList;
	PackageGridCtrl m_pkgList;
	/// end SHOW_INFO_FOR_INSTALLED_PACKAGES

	Button m_btnUninstall;
};


class XMLPackageWindow : public TreeEditDlg   
{
public:
	XMLPackageWindow() : TreeEditDlg(IDD_PKG_BUILDER, "ODlg8" )
	{
		m_strPkgFileName = STR_DEFAULT_PKG_FILE_NAME;
		clearChanged();
	}

	EVENTS_BEGIN
		ON_MENU_CMD(IDC_PKG_NEW, OnFileNew)
		ON_MENU_CMD(IDC_PKG_OPEN, OnFileOpen)
		ON_MENU_CMD(IDC_PKG_SAVE, OnFileSave)
		ON_MENU_CMD(IDC_PKG_SAVE_AS, OnFileSaveAs)
		ON_MENU_CMD(IDC_PKG_CLOSE, OnFileExit)

		ON_MENU_CMD(IDC_PKG_BROWSE_INSTALLED, OnUninstallPkg) /// EJP 2009-04-30 QA80-13540 SHOW_INFO_FOR_INSTALLED_PACKAGES
		ON_MENU_CMD(IDC_PKG_INSTALL, OnInstallPkg) /// EJP 2007-06-19 v8.0645 QA70-9103 INSTALL_PKG_FROM_PKGMGR
		ON_MENU_CMD(IDC_PKG_UNINSTALL, OnUninstallPkg)
		ON_MENU_CMD(IDC_PKG_EXTRACT, OnExtractPkg) /// EJP 2007-07-11 v8.0658 QA70-9103 EXTRACT_FILES_FROM_OPX

		ON_INIT(OnInitDialog)
		ON_DESTROY(OnDestroy)
		ON_CANCEL(OnCancel)
		ON_SIZE(OnDlgResize)

		ON_BN_CLICKED(IDOK, OnPackFiles)

		ON_BN_CLICKED(IDC_PKG_ADD_FOLDER, OnAddFolder)
		ON_BN_CLICKED(IDC_PKG_ADD_FILES, OnAddFiles)
		ON_BN_CLICKED(IDC_PKG_REMOVE_FILES, OnRemoveFiles)
		ON_BN_CLICKED(IDC_PKG_REPACK, OnRepackFiles)
		ON_BN_CLICKED(IDC_PKG_SET_TBAR, OnSetToolbar)

		ON_BN_CLICKED(IDC_PKG_SHOW_FILE_LIST, myOnShowBottomPane)
		
		ON_LBN_SELCHANGE(IDC_PKG_FILE_LIST, OnChangeFileSelection)
		
		ON_GETNDLG_MSGS(IDC_PKG_OPTIONS)
		ON_SYSCOMMAND(OnSystemCommand)

		ON_USER_MSG(WM_USER_TREEEDITOR_VALUE_CHANGE, OnAfterValueChange)
	EVENTS_END

	DWORD DoModalEx(HWND hParent)
	{
		InitMsgMap();// will be called from internal later
		int nRet = DoModal(hParent);
		if(IDOK == nRet)
		{
			return 1;
		}
		return 0;
	}
/*
	virtual int Create(HWND hParent = NULL)
	{
		InitMsgMap();
		int nRet = TreeEditDlg::Create(hParent);
		return nRet;
	}
*/
protected:
	BOOL OnInitDialog()
	{
		m_lbFileList = GetDlgItem(IDC_PKG_FILE_LIST);
		m_btnRemoveFiles = GetDlgItem(IDC_PKG_REMOVE_FILES);
		m_btnShowPane = GetDlgItem(IDC_PKG_SHOW_FILE_LIST);
		m_btnRepackFiles = GetDlgItem(IDC_PKG_REPACK);
		m_btnSetToolbar = GetDlgItem(IDC_PKG_SET_TBAR);

		ResizeDialog::OnInitDialog(IDC_PKG_OPTIONS, STR_DLG_NAME);

		/// EJP 2007-12-06 v8.0763 FIX_PKG_MGR_MENU_WHEN_CHANGE_ORIGIN_LANG
		InitToolBar(IDR_PKG_MENU);
		SetLangMenu(IDR_PKG_MENU);
		/// end FIX_PKG_MGR_MENU_WHEN_CHANGE_ORIGIN_LANG

		///Jasmine 10/19/07 QA70-10563 LOCALIZATION_OF_DISPLAY
		vector<string> vstrTipsUpDown;// = {"Show File List", "Hide File List"};
		vstrTipsUpDown.SetSize(2);
		vstrTipsUpDown[0] = _L("Show File List");
		vstrTipsUpDown[1] = _L("Hide File List");
		///End LOCALIZATION_OF_DISPLAY
		TreeEditDlg::OnInitDialog(
			IDC_PKG_OPTIONS,			// id of grid control
			IDC_PKG_SHOW_FILE_LIST,		// id of button used to show/hide bottom pane
			IDC_PKG_FILE_LIST,			// id of bottom control
			vstrTipsUpDown,				// tips for button used to show/hide bottom pane
			STR_DLG_NAME, 0, NULL, false);

		InitPackageTree(); // Init the package tree to be displayed in the tree edit ctrl
		InitTreeEditCtrl(); // Init the tree edit ctrl


		SetInitReady();
		m_treeEditCntrl.SetReady();
		ShowWindow(SW_NORMAL);

		m_lbFileList.ShowWindow(IsBottomPaneShown() ? SW_NORMAL : SW_HIDE);
		UpdateEnableStateOfButtons();

		UpdateDialogTitle();
		return TRUE;
	}

	BOOL OnDestroy(void)
	{
		TreeEditDlg::OnDestroy();
		return TRUE;
	}

	BOOL OnPackFiles(Control ctrl)
	{
		StringArray saFileNames;

		init_fdlog_with_group_name("*.opx");
		if( 0 == GetFDLogBox(saFileNames, FDLOG_TYPE_SAVE_AS) )
			return FALSE;
		
		string strPkgFile = saFileNames[0];

		GetFileNames(saFileNames);
		if( okutil_create_package_file(&m_paramTree, strPkgFile, &saFileNames) )
		{
			printf("Error creating package file.\n");
			return FALSE;
		}

		return TRUE;
	}

	BOOL OnCancel()
	{
		return IsOkayToClosePackage();
	}
	
	BOOL OnDlgResize(int nType, int cx, int cy)
	{
		if( !IsInitReady() )
			return TRUE;
		
		MoveControlsHelper	_temp(this);		//---- CPY 12/14/05 this will help the buttons to redraw better, I also remove OK/Cancel since Eric has File menu now

		uint nIDs[] = {IDC_PKG_REMOVE_FILES, IDC_PKG_ADD_FILES, IDC_PKG_ADD_FOLDER, IDC_PKG_SET_TBAR, IDC_PKG_REPACK, 0};
		MultiPaneDlg::OnDlgResize(nIDs, cx, cy, false);
		return TRUE;
	}

	void InitTreeEditCtrl()
	{
		m_treeEditCntrl.Init(IDC_PKG_OPTIONS, false, true, NULL, *this);
		m_treeEditCntrl.CreateTreeView();
		m_treeEditCntrl.SetReady(false);
		m_treeEditCntrl.Update(m_paramTree, true, true);
	}
	
	void InitPackageTree()
	{
		/*		
		//////////////////// EJP TEMP: begin temporary code for testing
		GETN_TREE(tnPkg);
	
		GETN_BEGIN_BRANCH(PkgInfo, "Package") GETN_ID_BRANCH(IDE_PKG_INFO_GROUP)
			GETN_STR(Name, "Name", "") GETN_ID(IDE_PKG_NAME)
			GETN_STR(Description, "Description", "") GETN_ID(IDE_PKG_DESCRIPTION)
			GETN_NUM(Version, "Version", 1.0) GETN_ID(IDE_PKG_VERSION)
			GETN_STR(Author, "Author", "") GETN_ID(IDE_PKG_AUTHOR)
		GETN_END_BRANCH(PkgInfo)

		double dVer;
		LT_get_var("@V", &dVer);
		GETN_NUM(OriginVerReq, "Origin Version Required", dVer) GETN_ID(IDE_PKG_ORIGIN_VER_REQ)

		GETN_BEGIN_BRANCH(Toolbar, "User Defined Toolbar") GETN_ID_BRANCH(IDE_PKG_TOOLBAR_GROUP) GETN_CHECKBOX_BRANCH(0)
			GETN_BUTTON(ToolbarFile, "Toolbar File", "") GETN_ID(IDE_PKG_TOOLBAR_FILE) GETN_OPTION_EVENT(OnBrowseToolbarFile) 
			///GETN_STR(ToolbarFile, "Toolbar File", "") GETN_ID(IDE_PKG_TOOLBAR_FILE)
		GETN_END_BRANCH(Toolbar)
		//////////////////// EJP TEMP: end temporary code for testing
		*/
		Tree tnPkg;
		okutil_create_package_tree(&tnPkg);
		setPackageTreeViewOptions(tnPkg);
		m_paramTree = tnPkg;
	}

	//---------------------------------------------------------------
	// Button Handlers
	//---------------------------------------------------------------

	BOOL OnAddFolder(Control ctrl)
	{
		string strPath = BrowseGetPath(NULL, _L("Select Folder"));
		if( strPath.IsEmpty() )
			return FALSE;

		/// EJP 2007-10-25 v8.0734 QA70-10570 IMPROVE_PATH_INFO_IN_OPX_PACKAGES
		if( IsSourcePathEmpty() )
			SetSourcePathFromAddPath(strPath);
		/// end IMPROVE_PATH_INFO_IN_OPX_PACKAGES

		if( FALSE == CheckPathWithSourcePath(strPath) )
			return FALSE;

		/// EJP 2007-01-12 v8.0541 QA70-9103 NOTIFY_USER_FILE_ALREADY_IN_PKG
		MessageBox(GetSafeHwnd(),
			_L("If any files are already in the package\nthey will not be added again."),
			SZ_PKG_MGR_NAME, MB_OK);
		/// end NOTIFY_USER_FILE_ALREADY_IN_PKG

		if( okutil_add_folder_to_package(&m_paramTree, strPath) )
			return FALSE;
		StringArray saFileNames;
		okutil_get_packed_file_names(&m_paramTree, &saFileNames);

		UpdateTreeCtrl();
		SetFileNames(saFileNames);
		UpdateEnableStateOfButtons();
		setChanged();
		UpdateDialogTitle();
		return TRUE;
	}

	BOOL OnAddFiles(Control ctrl)
	{
		// call mutli open file dialog
		StringArray saFileNames;
		int nFileCount = GetMultiOpenBox(saFileNames, "[All Files (*.*)] *.*",
			NULL, // default path
			NULL, // default file name
			_L("Add Files To Package"));
		
		if( nFileCount > 0 )
		{
			string strPath = GetFilePath(saFileNames[0]);

			/// EJP 2007-10-25 v8.0734 QA70-10570 IMPROVE_PATH_INFO_IN_OPX_PACKAGES
			if( IsSourcePathEmpty() )
				SetSourcePathFromAddPath(strPath, TRUE); // TRUE = adding files
			/// end IMPROVE_PATH_INFO_IN_OPX_PACKAGES

			if( FALSE == CheckPathWithSourcePath(strPath) )
				return FALSE;

			// When the user adds files lets make sure the bottom pane is visible
			// so they can see that the additional files were added.
			if( !IsBottomPaneShown() )
			{
				// OnShowBottomPane will check the state of the button
				// used to show and hide the pane.  Since the button was
				// not changed by a click we must change the state here
				// before we call OnShowBottomPane.
				m_btnShowPane.Check = true;
				myOnShowBottomPane(m_btnShowPane);
			}

			/// EJP 2007-01-12 v8.0541 QA70-9103 NOTIFY_USER_FILE_ALREADY_IN_PKG
			if( okutil_is_files_in_pkg(&m_paramTree, &saFileNames) )
				MessageBox(GetSafeHwnd(),
					_L("The files already in the package\nwill not be added again."),
					SZ_PKG_MGR_NAME, MB_OK);
			/// end NOTIFY_USER_FILE_ALREADY_IN_PKG

			if( 0 == okutil_add_files_to_package(&m_paramTree, &saFileNames) )
				UpdateFileList();
			UpdateEnableStateOfButtons();
			UpdateTreeCtrl();
			setChanged();
		}
		UpdateDialogTitle();
		return TRUE;
	}
	
	BOOL OnRemoveFiles(Control ctrl)
	{
		StringArray saFileNames;
		GetSelFileName(saFileNames);
		if( saFileNames.GetSize() > 0 )
		{
			if( 0 == okutil_remove_files_from_package(&m_paramTree, &saFileNames) )
				UpdateFileList();
			UpdateEnableStateOfButtons();
			setChanged();
		}
		UpdateDialogTitle();
		return TRUE;
	}

	BOOL OnRepackFiles(Control ctrl)
	{
		printf(_L("Repacking %s...\n"), m_strPkgFileName);
		printf(_L("Files Updated:\n"));
		printf(_L("Old Time                  New Time                  File Name\n"));
		if( okutil_repack_files(&m_paramTree) )
			return FALSE;
		UpdateFileList();
		printf(_L("Done!\n"));
		setChanged();
		UpdateDialogTitle();
		return TRUE;
	}
	
	BOOL OnSetToolbar(Control ctrl)
	{
		StringArray saFileNames;
		GetSelFileName(saFileNames);
		ASSERT(1 == saFileNames.GetSize());
		BOOL bRet = SetToolbarFile(saFileNames[0]);
		UpdateTreeCtrl();
		UpdateDialogTitle();
		return bRet;
	}

	//---------------------------------------------------------------
	// Menu Item Handlers
	//---------------------------------------------------------------

	BOOL OnFileNew()
	{
		if( !IsOkayToClosePackage() )
			return FALSE;

		m_strPkgFileName = STR_DEFAULT_PKG_FILE_NAME;
		InitPackageTree();
		UpdateTreeCtrl();
		UpdateFileList();
		clearChanged();
		UpdateDialogTitle();
		return TRUE;
	}
	
	BOOL OnFileOpen()
	{
		if( !IsOkayToClosePackage() )
			return FALSE;

		string strFileName;
		if( GetOPXFileName(strFileName) )
		{
			Tree tnPkg;
			if( tnPkg.Load(strFileName) )
			{
				m_strPkgFileName = strFileName;

				//---- CPY 12/19/05 USE_ID_COPY_TO_ENSURE_TREE_VALIDITY_ON_LOADING_OPX
				//m_paramTree = tnPkg;
				Tree tnPkgTemp;
				okutil_create_package_tree(&tnPkgTemp);
				tree_copy_values_by_id(tnPkg, tnPkgTemp);
				m_paramTree = tnPkgTemp;
				//-----
				m_treeEditCntrl.SetReady(false);
				m_treeEditCntrl.Update(m_paramTree, true, true);
				UpdateFileList();
				UpdateEnableStateOfButtons();
				clearChanged();
				UpdateDialogTitle();
				return TRUE;
			}
		}
		return FALSE;
	}

	BOOL OnFileSave()
	{
		string strPath = GetFilePath(m_strPkgFileName);
		if( strPath.IsEmpty() )
			return OnFileSaveAs();
		return SavePackageFile();
	}

	BOOL OnFileSaveAs()
	{
		string strFileName;
		if( GetOPXFileName(strFileName, FALSE) )
		{
			m_strPkgFileName = strFileName;
			return SavePackageFile();
		}
		return FALSE;
	}

	BOOL OnFileExit()
	{
		PostMessage(WM_CLOSE); 
		return TRUE;
	}

	/// EJP 2007-06-19 v8.0645 QA70-9103 INSTALL_PKG_FROM_PKGMGR
	BOOL OnInstallPkg()
	{
		string strFileName;
		if( GetOPXFileName(strFileName) )
		{
			if( 0 == okutil_install_package_file(strFileName) )
				return TRUE;
		}
		return FALSE;
	}
	/// end INSTALL_PKG_FROM_PKGMGR

	BOOL OnUninstallPkg()
	{
		UninstallPackageDlg dlg;
		dlg.DoModal(GetSafeHwnd());
		return TRUE;
	}

	/// EJP 2007-07-11 v8.0658 QA70-9103 EXTRACT_FILES_FROM_OPX
	BOOL OnExtractPkg()
	{
		BOOL bSuccess = FALSE;
		string strFileName;
		if( GetOPXFileName(strFileName) )
		{
			string strTargetPath = BrowseGetPath(NULL, _L("Select Target Folder"));
			if( !strTargetPath.IsEmpty() )
			{
				string strMsg;
				if( okutil_extract_package_files(strFileName, strTargetPath) )
				{
					strMsg = _L("Package failed to extract.");
					bSuccess = FALSE;
				}
				else
				{
					strMsg = _L("Package extracted successfully.");
					bSuccess = TRUE;
				}
				MessageBox(GetSafeHwnd(), strMsg, SZ_PKG_MGR_NAME, MB_OK);
			}
		}
		return bSuccess;
	}
	/// end EXTRACT_FILES_FROM_OPX

	//---------------------------------------------------------------
	// Other Control Handlers
	//---------------------------------------------------------------

	BOOL OnChangeFileSelection(Control ctrl)
	{
		UpdateEnableStateOfButtons();
		return TRUE;
	}
	
	BOOL myOnShowBottomPane(Control ctrl)
	{
		BOOL bRet = OnShowBottomPane(ctrl);
		UpdateEnableStateOfButtons();
		return bRet;
	}

	void UpdateDialogTitle()
	{
		string strDlgName = SZ_PKG_MGR_NAME;

		string strDlgTitle;
		strDlgTitle.Format("%s - %s", strDlgName, m_strPkgFileName);

		if(isChanged())
			strDlgTitle += '*';
		
		m_wndDlg.Text = strDlgTitle;
	}

	bool isChanged()
	{
		return m_bChanged;
	}
	void clearChanged()
	{
		m_bChanged = false;
	}
	void setChanged()
	{
		m_bChanged = true;
	}

	void OnAfterValueChange(int nRow, int nCol)
	{
		m_bChanged = true;
		UpdateDialogTitle();
	}

private:
	string m_strPkgFileName;
	ListBox m_lbFileList;
	Button m_btnRemoveFiles;
	Button m_btnShowPane;
	Button m_btnSetToolbar;
	Button m_btnRepackFiles;
	bool m_bChanged;

	void UpdateTreeCtrl()
	{
		m_treeEditCntrl.SetReady(false);
		m_treeEditCntrl.Update(m_paramTree, true, true);
	}
	
	BOOL SavePackageFile()
	{
		if( okutil_create_package_file(&m_paramTree, m_strPkgFileName, NULL) )
		{
			popup_errmsg_save_readonly_file( m_strPkgFileName, GetSafeHwnd() );///Jasmine 10/23/08 QA80-12442 SHOW_WARNING_WHEN_SAVE_READ_ONLY_FILE
			return FALSE;
		}

		// Here we should set dialog title to contain file name.
		clearChanged();
		UpdateDialogTitle();
		return TRUE;
	}

	void UpdateEnableStateOfButtons()
	{
		BOOL bRemove = FALSE;
		BOOL bSetTbar = FALSE;
		BOOL bRepack = FALSE;

		if( IsBottomPaneShown() )
		{
			if( 0 < m_lbFileList.GetCount() )
			{
				bRepack = TRUE;

				int nSelCount = m_lbFileList.GetSelCount();
				if( 0 < nSelCount )
				{
					bRemove = TRUE;
					if( 1 == nSelCount )
						bSetTbar = TRUE;
				}
			}
		}

		m_btnRemoveFiles.Enable = bRemove;
		m_btnSetToolbar.Enable = bSetTbar;
		m_btnRepackFiles.Enable = bRepack;
	}
	
	void setPackageTreeViewOptions(TreeNode& tr)
	{
		GETN_USE(tr)
		GETN_OPTION_GRIDLINE(flexGridFlatVert)
		GETN_OPTION_EDIT_ALIGN("0|0|0")
	}

	bool IsOkayToClosePackage()
	{
		if( isChanged() )
		{
			string strMsg;
			strMsg.Format(_L("Save changes to %s?"), m_strPkgFileName);
			int ii = MessageBox(GetSafeHwnd(), strMsg, SZ_PKG_MGR_NAME, MB_YESNOCANCEL);
			if( ii == IDCANCEL )
				return false;
			if( ii == IDYES )
				return OnFileSave();
		}
		return true;
	}

	void UpdateFileList()
	{
		StringArray saFileNames;
		okutil_get_packed_file_names(&m_paramTree, &saFileNames);
		SetFileNames(saFileNames);
	}

	void GetSelFileName(StringArray& saFileNames)
	{
		saFileNames.SetSize(0);
		string strFileName;
		vector<uint> vnSelItems;
		m_lbFileList.GetSelItems(vnSelItems);
		for( int n = 0; n < vnSelItems.GetSize(); n++ )
		{
			m_lbFileList.GetText(vnSelItems[n], strFileName);
			saFileNames.Add(strFileName);
		}
	}

	void GetFileNames(StringArray& saFileNames)
	{
		saFileNames.SetSize(0);
		string strItem;
		for( int n = 0; n < m_lbFileList.GetCount(); n++ )
		{
			m_lbFileList.GetText(n, strItem);
			saFileNames.Add(strItem);
		}
	}
	
	void SetFileNames(const StringArray& saFileNames)
	{
		m_lbFileList.ResetContent();
		for( int n = 0; n < saFileNames.GetSize(); n++ )
			m_lbFileList.AddString(saFileNames[n]);
	}
	
	BOOL GetOPXFileName(string& strFileName, BOOL bOpen = TRUE)
	{
		StringArray saFileNames;
		int nType = (bOpen ? FDLOG_TYPE_OPEN_SINGLE : FDLOG_TYPE_SAVE_AS);

		init_fdlog_with_group_name("*.opx");
		if( 0 == GetFDLogBox(saFileNames, nType) )
			return FALSE;
		
		strFileName = saFileNames[0];
		return TRUE;
	}
	
	BOOL IsPathInSourcePath(LPCSTR lpcszPath)
	{
		string strSrcPath;
		GetSourcePath(strSrcPath);
		int nSrcLen = strSrcPath.GetLength();
	
		if( 0 == nSrcLen )
		{
			strSrcPath = lpcszPath;
			return SetSourcePath(strSrcPath);
		}

		string strPath = lpcszPath;
		if( strPath.GetLength() > nSrcLen )
			strPath = strPath.Left(nSrcLen);

		if( 0 == strPath.CompareNoCase(strSrcPath) )
			return TRUE;

		return FALSE;
	}
	BOOL CheckPathWithSourcePath(LPCSTR lpcszPath)
	{
		if( IsPathInSourcePath(lpcszPath) )
			return TRUE;
		MessageBox(GetSafeHwnd(), _L("Only files within the Source Path can be added."), SZ_PKG_MGR_NAME, MB_OK);
		return FALSE;
	}

	//---------------------------------------------------------------
	// Get/Set Tree Nodes
	//---------------------------------------------------------------

	BOOL GetNode(TreeNode& tn, int nDataID)
	{
		tn = m_paramTree.FindNodeByAttribute("DataID", nDataID);
		return tn.IsValid();
	}

	BOOL GetSourcePath(string& strSrcPath)
	{
		TreeNode tnSrcPath;
		if( !GetNode(tnSrcPath, IDE_PKG_SOURCE_PATH) )
			return FALSE;
		strSrcPath = tnSrcPath.strVal;
		return TRUE;
	}
	
	BOOL SetSourcePath(LPCSTR lpcszSrcPath)
	{
		TreeNode tnSrcPath;
		if( !GetNode(tnSrcPath, IDE_PKG_SOURCE_PATH) )
			return FALSE;
		tnSrcPath.strVal = lpcszSrcPath;
		return TRUE;
	}

	/// EJP 2007-10-25 v8.0734 QA70-10570 IMPROVE_PATH_INFO_IN_OPX_PACKAGES
	BOOL IsSourcePathEmpty()
	{
		string strSrcPath;
		if( GetSourcePath(strSrcPath) )
			return strSrcPath.IsEmpty();
		return FALSE;
	}

	BOOL SetSourcePathFromAddPath(LPCSTR lpcszAddFolder, BOOL bAddingFiles = FALSE)
	{
		string strAddFolder = lpcszAddFolder;

		// If packing a folder from the User Files Folder then make the
		// User Files Folder the Source Path.
		string strSrcPath = GetOriginPath(ORIGIN_PATH_USER);
		if( strAddFolder.Find(strSrcPath) == 0 )
			return SetSourcePath(strSrcPath);

		// If packing a folder from the System Folder then make the
		// System Folder the Source Path.
		strSrcPath = GetOriginPath();
		if( strAddFolder.Find(strSrcPath) == 0 )
			return SetSourcePath(strSrcPath);

		// The Add Folder is not in the User Files Folder nor the System Folder.

		if( bAddingFiles )
			return SetSourcePath(strAddFolder);

		// Make the Add Folder's parent the Source Path.
		int nSlashAfterDrive = strAddFolder.Find('\\', 2);
		int nLastSlash = strAddFolder.ReverseFind('\\');
		if( nSlashAfterDrive < nLastSlash )
		{
			strAddFolder.Delete(nLastSlash); // Delete last slash
			nLastSlash = strAddFolder.ReverseFind('\\');
			strSrcPath = strAddFolder.Left(nLastSlash + 1);
		}
		else
			strSrcPath = strAddFolder;
		return SetSourcePath(strSrcPath);
	}
	/// end IMPROVE_PATH_INFO_IN_OPX_PACKAGES

	BOOL SetToolbarFile(LPCSTR lpcszFile)
	{
		TreeNode tnSrcPath;
		if( !GetNode(tnSrcPath, IDE_PKG_TOOLBAR_FILE) )
			return FALSE;
		tnSrcPath.strVal = lpcszFile;
		return TRUE;
	}
};

bool DoXMLPackageDialog()
{
	XMLPackageWindow dlg;
	int nRet = dlg.DoModalEx(GetWindow());
	if(IDCANCEL != nRet)
		return true;
	return false;
}

bool InstallXMLPackage(const string strPkgFile)
{
	if( okutil_install_package_file(strPkgFile) )
	{
		printf("Failed to install package.\n");
		return false;
	}
	return true;
}

bool UninstallXMLPackage(const string strPkgName)
{
	if( okutil_uninstall_package_file(strPkgName) )
	{
		printf("Failed to uninstall package.\n");
		return false;
	}
	return true;
}

int ImportXMLPackage(Page &pgTarget, TreeNode &trFilter, LPCSTR lpcszFile, int nFile)
{
	string strPkgFile = lpcszFile;
	if( InstallXMLPackage(strPkgFile) )
		return 0; // success
	return 1; // error
}
