/*------------------------------------------------------------------------------*
 * File Name: themes_utils.c			 										*
 * Purpose: functions that are related to Themes and Copy/Paste formats			*
 * Copyright (c)2003 OriginLab Corp.											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	CPY 8/12/03 QA70-4999 v7.5656 FILENAME_WITH_DOT_SUPPORT						*
 *	RVD 9/15/2003 QA70-5179 v7.0695 THEME_SPECIAL_CONTEXT_MENU					*
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
//#include <Project.h>
#include <Dialog.h>
#include <TreeEditor.h>
#include "theme_utils.h" // some theme related utility functions, will move into separate utils file later

//////////////////////////////////////////////////////////
/////////// Theme Support Functions //////////////////////
//////////////////////////////////////////////////////////

string theme_get_system_theme_file_name(int nThemeType)// = THEME_APPLY_LOAD_TEMPLATE);
{
	Tree trTemp;
	trTemp.AddNode("Themes");
	
	theme_find_all_theme_files(trTemp.FirstNode);

	TreeNode tn = trTemp.FirstNode;
	tn = tn.FirstNode;
	string str, strFilename, strThemeName;
	
	while(tn)
	{
		int nType, nRow;
		tn.GetAttribute(THEME_TYPE_ATTRIBUTE, nType);
		bool bIsEXEpath = (nType == THTYPE_SYSTEM)? true:false;
		
		strThemeName = tn.strVal;
		if(theme_system_getset(strThemeName))
		{
			strFilename = theme_get_theme_file_name(strThemeName, bIsEXEpath);
			break;
		}
		tn = tn.NextNode;
	}
	
	return strFilename
}

string	theme_get_system_theme()
{
	INIFile ini;
	
	string strThemeSection = THEME_INI_SECTION;
	string strThemeItem = THEME_INI_ITEM;
	string strSysTheme = ini.ReadString(strThemeSection, strThemeItem);
	return strSysTheme;
}

bool theme_system_getset(string strThemeName, bool bSet, bool bSetAs, bool bIsEXEPath) // = false, = false, =false  if not set, then test
{
	INIFile ini;
	
	string strThemeSection = THEME_INI_SECTION;
	string strThemeItem = THEME_INI_ITEM;
	string strSysTheme = ini.ReadString(strThemeSection, strThemeItem);
	
	if(strSysTheme.CompareNoCase(strThemeName) == 0 && !(bSet && !bSetAs))
		return true; // nothing to do in any case
	
	if(bSet)
	{
		if(bSetAs) // don't worry about EXE path for now
			ini.WriteString(strThemeSection, strThemeItem, strThemeName);
		else
			ini.WriteString(strThemeSection, strThemeItem, "");// to Clear it
	
		return true;
	}
	else
		return false;
}

string theme_get_theme_file_name(string strThemeName, bool bIsEXEpath) //= false
{
	//------ CPY 8/12/03 QA70-4999 v7.5656 FILENAME_WITH_DOT_SUPPORT
	//	// make sure there is no dot in file name
	//	int nDotPos = strThemeName.ReverseFind('.');
	//	if(nDotPos > 0)
	//		strThemeName = strThemeName.Left(nDotPos);
	//	//
	//	return theme_get_path(bIsEXEpath) + strThemeName + "." + THEME_FILE_EXT;
	string strFilename = theme_get_path(bIsEXEpath) + strThemeName;
	add_file_extension(strFilename, THEME_FILE_EXT);
	return strFilename;
	//------
}

bool theme_rename(string strThemeName, string strOldName, bool bIsEXEpath)
{
	bool bWasSysemTheme = theme_system_getset(strOldName)? true : false;
	string strOldFile = theme_get_theme_file_name(strOldName, bIsEXEpath);
	string strNewFile = theme_get_theme_file_name(strThemeName, bIsEXEpath);
	if(strNewFile.IsFile())
		return false;
	if(bWasSysemTheme)
		theme_system_getset(strThemeName, true, bWasSysemTheme , bIsEXEpath);

	return RenameFile(strNewFile, strOldFile);
}

string theme_get_path(bool bEXEpath)// = false)
{
	string strPath = GetAppPath(bEXEpath);
	
	strPath += THEME_SUB_FOLDER + "\\";
	
	return strPath;
}

int		theme_count_properties(LPCSTR lpcszThemeFilename, int* lpnSections)// = NULL);
{
	Tree trTheme(lpcszThemeFilename);
	if(trTheme)
		return tree_count_items(trTheme, lpnSections);
	else
		return -1;
}

bool theme_is_in_clipboard()
{
	int nCFStyles = GetOriginClipboardFormat();
	if(nCFStyles == 0 || !OpenClipboard(NULL))
		return FALSE;
	
	if(!IsClipboardFormatAvailable(nCFStyles))
	{
		CloseClipboard();
		return FALSE;
	}
	CloseClipboard();
	return TRUE;
}

//add a theme file (fullpath) to given TreeNode
TreeNode theme_add_one_theme_file(TreeNode& trNode, const string& strFilename, bool bUser)// = true)
{
	string strAttrib = THTYPE_SYSTEM;
	if(bUser)
		strAttrib = THTYPE_USER;
	
	TreeNode tnTemp = trNode.AddTextNode(GetFileName(strFilename, TRUE), THEME_FILE_NODE_NAME);
	tnTemp.SetAttribute(THEME_TYPE_ATTRIBUTE, strAttrib);
	return tnTemp;
}

uint theme_find_all_theme_files(TreeNode& trNode)
{
	StringArray sa;
	string strSysPath = theme_get_path(TRUE);
	FindFiles(sa, strSysPath, THEME_FILE_EXT);
	int ii, jj;
	
	for(ii = 0; ii < sa.GetSize(); ii++)
		theme_add_one_theme_file(trNode, sa[ii], false);

	string strUserPath = theme_get_path(FALSE);
	if(strUserPath.CompareNoCase(strSysPath) == 0)
		return ii;
		
	sa.SetSize(0);
	FindFiles(sa, strUserPath, THEME_FILE_EXT);

	for(jj = 0; jj < sa.GetSize(); jj++)
		theme_add_one_theme_file(trNode, sa[jj], true);
	
	return ii + jj;
}

bool theme_get_next_file_name(string& strFilename, bool bCheckCreatePath)//=true)
{
	int nn = 1;
	string strThemePath = theme_get_path();
	if(bCheckCreatePath && !CheckMakePath(strThemePath))
		return false;
		
	do
	{
		strFilename = strThemePath + "Theme" + nn + "." + THEME_FILE_EXT;
		nn++;
	} while (strFilename.IsFile());
	
	return true;
}

//////////////////////////////////////////////////////////
/////////// Copy Format Functions   //////////////////////
//////////////////////////////////////////////////////////
bool	theme_copy_format(DWORD dwPropertiesFilter, DWORD dwObjFilter)//=FPB_ALL,  = FOB_ALL
{
	if( Selection.Objects.Count() > 0 )
	{
		return Selection.Objects(0).CopyFormat(dwPropertiesFilter, dwObjFilter);
	}
	else
	{
		GraphPage gPage = Project.Pages();
		if( gPage )
			return gPage.CopyFormat(dwPropertiesFilter, dwObjFilter);
	}
	
	return false;
}

bool	theme_copy_format_to_file(LPCSTR lpcszFilename, DWORD dwPropertiesFilter, DWORD dwObjFilter)//=FPB_ALL,  = FOB_ALL
{
	Tree trTheme;
	if( Selection.Objects.Count() > 0 )
	{
		trTheme = Selection.Objects(0).GetFormat(dwPropertiesFilter, dwObjFilter);
	}
	else
	{
		GraphPage gPage = Project.Pages();
		if( gPage )
			trTheme = gPage.GetFormat(dwPropertiesFilter, dwObjFilter);
	}
	if(trTheme.FirstNode)
	{
		trTheme.Save(lpcszFilename);
		return true;
	}
	return false;
}

bool	theme_combine_filter_bits(int nType, DWORD& dwProperties, DWORD& dwObjects)
{
	static const DWORD l_arrObjectFilter[] =
	{
		FOB_ALL,									// SAVETHEME_ALL
		FOB_ALL & ~(FOB_DIMENSION|FOB_SCALE),		// SAVETHEME_ALL_STYLES
		FOB_ALL,									// SAVETHEME_COLORS
		FOB_ALL,									// SAVETHEME_FONTS
		FOB_ALL,									// SAVETHEME_DIMS
		FOB_ALL,									// SAVETHEME_SCALES
		FOB_ALL,									// SAVETHEME_TEXT
		FOB_BACKGROUND|FOB_LABELS|FOB_GLOBAL,		// SAVETHEME_BACKGROUND
		FOB_ALL & ~FOB_BACKGROUND					// SAVETHEME_PLOTS
	};
	
	static const DWORD l_arrPropertyFilter[] =
	{
		FPB_ALL,									// SAVETHEME_ALL
		FPB_STYLE|FPB_OTHER|FPB_SHOW,				// SAVETHEME_ALL_STYLES
		FPB_STYLE_COLOR_MASK,						// SAVETHEME_COLORS
		FPB_STYLE_FONT|FPB_STYLE_SIZE,				// SAVETHEME_FONTS
		FPB_DIMENSION,								// SAVETHEME_DIMS
		FPB_SCALE,									// SAVETHEME_SCALES
		FPB_TEXT,									// SAVETHEME_TEXT
		FPB_STYLE_BORDER|FPB_STYLE_COLOR_MASK|FPB_STYLE_LINE|FPB_STYLE_FILL|FPB_OTHER,	// SAVETHEME_BACKGROUND
		FPB_STYLE_SYMBOL_MASK|FPB_STYLE_LIST_MASK|FPB_STYLE_LINE|FPB_STYLE_FILL|FPB_STYLE_SIZE|FPB_STYLE_FONT	// SAVETHEME_PLOTS
	};
	
	if( nType < 0 || nType >= SAVETHEME_TOTAL )
		return false;

	dwProperties |= l_arrPropertyFilter[nType];
	dwObjects |= l_arrObjectFilter[nType];

	return true;
}

bool theme_copy_format_menu(int nType)// = SAVETHEME_ALL)
{
	DWORD dwObjects = 0;
	DWORD dwProperties = 0;

	return
		theme_combine_filter_bits(nType, dwProperties, dwObjects) &&
		theme_copy_format(dwProperties, dwObjects);
}

bool	CopyFormat()
{
	return theme_copy_format_menu(SAVETHEME_ALL); 
}

bool	CopyFormatAllStyles()
{
	return theme_copy_format_menu(SAVETHEME_ALL_STYLES); 
}

bool	CopyFormatColors()
{
	return theme_copy_format_menu(SAVETHEME_COLORS); 
}

bool	CopyFormatFonts()
{
	return theme_copy_format_menu(SAVETHEME_FONTS); 
}

bool	CopyFormatScales()
{
	return theme_copy_format_menu(SAVETHEME_SCALES); 
}

bool	CopyFormatDimensions()
{
	return theme_copy_format_menu(SAVETHEME_DIMS); 
}

bool	CopyFormatText()
{
	return theme_copy_format_menu(SAVETHEME_TEXT); 
}

bool	CopyFormatBackground()
{
	return theme_copy_format_menu(SAVETHEME_BACKGROUND); 
}

bool	CopyFormatPlot()
{
	return theme_copy_format_menu(SAVETHEME_PLOTS); 
}

/// RVD 9/15/2003 QA70-5179 v7.0695 THEME_SPECIAL_CONTEXT_MENU
bool	CopyFormatSpecial(int nIndex)
{
	return theme_copy_format(FPB_NONE, nIndex & FOB_SPECIAL);
}
/// end THEME_SPECIAL_CONTEXT_MENU

static	bool theme_apply_to_graphpage(GraphPage gPage, string& strFile)
{
	if( !gPage )
	{
		out_str("Not a graph page");
		return true;
	}

	printf("Applying theme to page %s\n", gPage.GetName());
	return gPage.ApplyFormat(strFile);
}

bool	theme_apply(int nTo, string strFile)
{
	bool bResult = false;

	UndoBlock ub;

	switch( nTo )
	{
	case THEMEAPPLY_SELECTION:
		foreach(OriginObject obj in Selection.Objects)
		{
			bResult = obj.ApplyFormat(strFile) && bResult;
		}
		break;

	case THEMEAPPLY_ACTIVE:
		bResult = theme_apply_to_graphpage(Project.Pages(), strFile);
		break;

	case THEMEAPPLY_FOLDER:
		foreach(PageBase page in Project.ActiveFolder().Pages)
		{
			bResult = theme_apply_to_graphpage(page, strFile) && bResult;
		}
		break;

	case THEMEAPPLY_PROJECT:
		foreach(GraphPage gPage in Project.GraphPages)
		{
			bResult = theme_apply_to_graphpage(gPage, strFile) && bResult;
		}
		break;
	}

	return bResult;
}

//////////////////////////////////////////////////////////
/////////// Theme and TreeEditor related /////////////////
//////////////////////////////////////////////////////////
//////////////////////////////////////////////
void theme_update_tree_list_view(Dialog& theDlg, int nListViewCheckID, int nTreeID, bool bShowEmpty, bool bShowCollection) //=false,=false
{
	Button btnListView = theDlg.GetItem(nListViewCheckID);//oCntrl;
	
	DWORD dwViewSettings = VIEWFLT_PROPERTY_ALL;
	
	if(btnListView.Check)
		dwViewSettings |= VIEWFLT_FULL_PATHS_IN_LABELS;
	else
	{
		dwViewSettings |= VIEWFLT_BRANCH_NON_COLLECTION;
		if(bShowEmpty)
			dwViewSettings |= VIEWFLT_BRANCH_EMPTY;
		if(bShowCollection)
			dwViewSettings |= VIEWFLT_BRANCH_COLLECTION;
	}
	
	TreeEditor tree = theDlg.GetItem(nTreeID);
	
	tree.View = dwViewSettings;
}

/////////////////////////////////////////////
// if nTreeID given, we assume that lpcszFilename is a temp file that we can save the Theme tree into
// to update it before we do the counting
void theme_update_size(Dialog& theDlg, LPCSTR lpcszFilename, int nSizeID, int nTreeID) //=0
{
	if(nTreeID)
	{
		TreeEditor tree = theDlg.GetItem(nTreeID);
		tree.Save(lpcszFilename);
	}
	int nCount = 0;
	Tree themeTree(lpcszFilename);
	if(themeTree)
		nCount = tree_count_items(themeTree);
	
	Control cTreeLeafCounts = theDlg.GetItem(nSizeID);
	cTreeLeafCounts.Text = nCount;
}
/////////////////////////////////////////////

typedef bool (* P_THEME_FILTER)(LPCSTR lpcszThemeFilename, HWND hWndParent);
// return true if the Theme Tree specified by nIDTree has been filtered
bool theme_filter_dialog(Dialog& dlgParent, int nIDListView, int nIDTree)
{
	string strTempThemeFile;
	if(!GetTempFileName(strTempThemeFile))
		return false;
	
	bool bRet = false;

	P_THEME_FILTER fnThemeFilter = Project.FindFunction("ThemeFilter");
	if(fnThemeFilter)
	{
		TreeEditor tree = dlgParent.GetItem(nIDTree);
		//if(!tree.IsValid())
		//	return false;
		
		tree.Save(strTempThemeFile);
		if(fnThemeFilter(strTempThemeFile, dlgParent.GetWindow().GetSafeHwnd()))
		{
			tree.Load(strTempThemeFile);
			theme_update_tree_list_view(dlgParent, nIDListView, nIDTree);
			bRet = true;
		}
		if(strTempThemeFile.IsFile())
			DeleteFile(strTempThemeFile);
	}
	return bRet;
}

// set_color_map_z_levels
// returns true/false for success/failure
// dp is a 3-D dataplot object with colormap, e.g. contour plot
// vZs is a vecor containing the desired values for color levels
// bLogScale, when true, will set the color levels to follow a log scale
#define DENOM_MIN 1E-99
bool set_color_map_z_levels(DataPlot &dp, vector& vZs, bool bLogScale)
{
	if(NULL == dp)
		return false;
	vector ZLevels;
	ZLevels = vZs;
	ZLevels.Sort();
    int nLevels = ZLevels.GetSize();
    if(nLevels < 2)
   		return false;
	double dMin = ZLevels[0];
	double dMax = ZLevels[nLevels - 1];
	double dDenom = (dMax - dMin);
	if(dDenom < DENOM_MIN)
		return false;
	ZLevels = ZLevels - dMin;
	ZLevels = ZLevels/dDenom;
	ZLevels = ZLevels*100;
	
   Tree tr; 
   tr = dp.Surface; // get the internal Surface branch of Format
   tr.ColorMap.Details.Remove(); //So we can change nLevels
   tr.ColorMap.Count.nVal = nLevels;
   tr.ColorMap.LogScale.nVal = bLogScale ? 1: 0;
   tr.ColorMap.Min.dVal = dMin;
   tr.ColorMap.Max.dVal = dMax;
   tr.ColorMap.Details.Levels.dVals = ZLevels;
   dp.Surface = tr;
   
   return true; 
}

/*
//////////////////////////////////////////////////////////
/////////// general dialog utilities     /////////////////
//////////////////////////////////////////////////////////
// return the gap between controls that might be used by caller
// for repositioning of other controls
int dlg_resize_buttons_relative_to_main_item(Dialog& dlg, uint nButtonIDs[], uint nMainItemID, int cx, int cy)
{
	Window wndDlg = dlg.GetWindow();
	RECT r1, r2;
	Button btnClose = dlg.GetItem(nButtonIDs[0]);
	btnClose.GetWindowRect(&r1);
	int nBtnWidth = r1.right - r1.left;
	int nBtnHeight= r1.bottom - r1.top;
	wndDlg.ScreenToClient(&r1);
	int nEdge = r1.top;
	
	Control cMainItem = dlg.GetItem(nMainItemID);
	cMainItem.GetWindowRect(&r1);
	wndDlg.ScreenToClient(&r1);
	r1.bottom = cy - nEdge;
	r1.right = cx - nBtnWidth - 2*nEdge;
	
	cMainItem.MoveWindow(&r1);
	
	int ii = 0;
	r2.left = r1.right + nEdge;
	r2.top = nEdge;
	r2.right = r2.left + nBtnWidth;
	r2.bottom = r2.top + nBtnHeight;
	while(nButtonIDs[ii] > 0)
	{
		Button btn = dlg.GetItem(nButtonIDs[ii]);
		if(btn)
		{
			btn.MoveWindow(&r2);
			r2.top += nBtnHeight + nEdge;
			r2.bottom += nBtnHeight + nEdge;
		}
		ii++;
	}
	return nEdge;
}
*/

	
	