/*	File: D:\WACKER\tdll\misc.c (Created: 27-Nov-1993)
 *
 *	Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
 *	All rights reserved
 *
 *	$Revision: 5 $
 *	$Date: 3/22/01 11:27a $
 */

#include <windows.h>
#pragma hdrstop

#include "stdtyp.h"
#include "misc.h"
#include "tdll.h"
#include "htchar.h"
#include "globals.h"
#include "assert.h"
#include <term\res.h>

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 * FUNCTION:
 *	mscCenterWindowOnWindow
 *
 * DESCRIPTION:
 *	Center's first window on the second window.  Assumes hwndChild is
 *	a direct descendant of hwndParent
 *
 * ARGUMENTS:
 *	hwndChild	- window to center
 *	hwndParent	- window to center on
 *
 * RETURNS:
 *	BOOL
 *
 */
BOOL mscCenterWindowOnWindow(const HWND hwndChild, const HWND hwndParent)
	{
	RECT	rChild, rParent;
	int 	wChild, hChild, wParent, hParent;
	int 	xNew, yNew;
	int 	iMaxPos;

	if (!IsWindow(hwndParent))
		return FALSE;

	if (!IsWindow(hwndChild))
		return FALSE;

	/* --- Get the Height and Width of the child window --- */

	GetWindowRect(hwndChild, &rChild);
	wChild = rChild.right - rChild.left;
	hChild = rChild.bottom - rChild.top;

	/* --- Get the Height and Width of the parent window --- */

	GetWindowRect(hwndParent, &rParent);
	wParent = rParent.right - rParent.left;
	hParent = rParent.bottom - rParent.top;

	/* --- Calculate new X position, then adjust for screen --- */

	xNew = rParent.left + ((wParent - wChild) / 2);

	/* --- Calculate new Y position, then adjust for screen --- */

	// Let's display the dialog so that the title bar is visible.
	//
	iMaxPos = GetSystemMetrics(SM_CYSCREEN);
	yNew = min(iMaxPos, rParent.top + ((hParent - hChild) / 2));

	//mpt:3-13-98 Need to make sure dialog is not off the screen
    if (yNew < 0)
        {
        yNew = 0;
        }

    if (xNew < 0)
        {
        xNew = 0;
        }

    // Set it, and return
	//
	return SetWindowPos(hwndChild, 0, xNew, yNew, 0, 0,
		SWP_NOSIZE | SWP_NOZORDER);
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 * FUNCTION:
 *  mscStripPath
 *
 * DESCRIPTION:
 *	Strip off the path from the file name.
 *
 * ARGUMENTS:
 * 	pszStr - pointer to a null terminated string.
 *
 * RETURNS:
 *  void.
 */
LPTSTR mscStripPath(LPTSTR pszStr)
	{
	LPTSTR pszStart, psz;

	if (pszStr == 0)
		return 0;

	for (psz = pszStart = pszStr; *psz ; psz = StrCharNext(psz))
		{
		if (*psz == TEXT('\\') || *psz == TEXT(':'))
			pszStart = StrCharNext(psz);
		}

	StrCharCopy(pszStr, pszStart);
	return pszStr;
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 * FUNCTION:
 *  mscStripName
 *
 * DESCRIPTION:
 *	Strip off the name of the file, leave just the path.
 *
 * ARGUMENTS:
 * 	pszStr - pointer to a null terminated string.
 *
 * RETURNS:
 *  void.
 */
LPTSTR mscStripName(LPTSTR pszStr)
	{
	LPTSTR pszEnd, pszStart = pszStr;

	if (pszStr == 0)
		return 0;

	for (pszEnd = pszStr; *pszStr; pszStr = StrCharNext(pszStr))
		{
		if (*pszStr == TEXT('\\') || *pszStr == TEXT(':'))
			pszEnd = StrCharNext(pszStr);
		}

	*pszEnd = TEXT('\0');
	return (pszStart);
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 * FUNCTION:
 *  mscStripExt
 *
 * DESCRIPTION:
 *	Strip off the file extension.  The parameter string can be a full-path
 *	or just a file name.
 *
 * ARGUMENTS:
 * 	pszStr - pointer to a null terminated string.
 *
 * RETURNS:
 *  void.
 */
LPTSTR mscStripExt(LPTSTR pszStr)
	{
	LPTSTR pszEnd, pszStart = pszStr;

	for (pszEnd = pszStr; *pszStr; pszStr = StrCharNext(pszStr))
		{
		// Need to check for both '.' and '\\' because directory names
		// can have extensions as well.
		//
		if (*pszStr == TEXT('.') || *pszStr == TEXT('\\'))
			pszEnd = pszStr;
		}

	if (*pszEnd == TEXT('.'))
		*pszEnd = TEXT('\0');

	return pszStart;
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 * FUNCTION:
 *  mscModifyToFit
 *
 * DESCRIPTION:
 *  If a string won't fit in a given window then chop-off as much as possible
 *  to be able to display a part of the string with ellipsis concatanated to
 *  the end of it.
 *
 *  NOTE: I've attempted to make this code DBCS aware.
 *
 * ARGUMENTS:
 *  hwnd 	- control window, where the text is to be displayed.
 *  pszStr 	- pointer to the string to be displayed.
 *
 * RETURNS:
 *  lpszStr - pointer to the modified string.
 *
 */
LPTSTR mscModifyToFit(HWND hwnd, LPTSTR pszStr)
	{
	HDC	 	hDC;
	SIZE	sz;
	HFONT	hFontSave, hFont;
	RECT	rc;
	TCHAR	ach[512], achEllipsis[10];
	int		nWidth = 0, i = 0;

	TCHAR_Fill(ach, TEXT('\0'), sizeof(ach) / sizeof(TCHAR));
	memset(&hFont, 0, sizeof(HFONT));
	memset(&hFontSave, 0, sizeof(HFONT));
	memset(&rc, 0, sizeof(RECT));

	GetWindowRect(hwnd, &rc);
	nWidth = rc.right - rc.left;

	hDC = GetDC(hwnd);

	hFont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
	if (hFont)
		hFontSave = SelectObject(hDC, hFont);

	// TODO: I think here the string pszStr would have to be "deflated"
	// before we continue.  The rest of the code should stay the same.
	//
	GetTextExtentPoint(hDC, (LPCTSTR)pszStr, StrCharGetStrLength(pszStr), &sz);
	if (sz.cx > nWidth)
		{
		LoadString(glblQueryDllHinst(), IDS_GNRL_ELLIPSIS,
			achEllipsis, sizeof(achEllipsis) / sizeof(TCHAR));

		StrCharCopy(ach, achEllipsis);
		StrCharCat(ach, pszStr);
		i = StrCharGetStrLength(ach);

		while ((i > 0) && (sz.cx > nWidth))
			{
			GetTextExtentPoint(hDC, (LPCTSTR)ach, i, &sz);
			i -= 1;
			}
		TCHAR_Fill(ach, TEXT('\0'), sizeof(ach) / sizeof(TCHAR));
		StrCharCopyN(ach, pszStr, i);
		StrCharCat(ach, achEllipsis);
		StrCharCopy(pszStr, ach);
		}

	// Select the previously selected font, release DC.
	//
	if (hFontSave)
		SelectObject(hDC, hFontSave);
	ReleaseDC(hwnd, hDC);

	return pszStr;
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 * FUNCTION:
 *	extLoadIcon
 *
 * DESCRIPTION:
 *	Gets the icon from the hticons.dll.  The extension handlers use
 *	this dll for icons and need to not link load anything more than
 *	absolutely necessary, otherwise, this function would go in the
 *	icon handler code.
 *
 * ARGUMENTS:
 *	id	- string id of resource (can be MAKEINTRESOURCE)
 *
 * RETURNS:
 *	HICON or zero on error.
 *
 */
HICON extLoadIcon(LPCSTR id)
	{
	static HINSTANCE hInstance;

	if (hInstance == 0)
		{
		if ((hInstance = LoadLibrary("hticons")) == 0)
			{
			assert(FALSE);
			return 0;
			}
		}

	return LoadIcon(hInstance, id);
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 * FUNCTION:
 *	mscCreatePath
 *
 * DESCRIPTION:
 *	Creates the given path.  This function is somewhat tricky so study
 *	it carefully before modifying it.  Despite it's simplicity, it
 *	accounts for all boundary conditions. - mrw
 *
 * ARGUMENTS:
 *	pszPath - path to create
 *
 * RETURNS:
 *	0=OK,else error
 *
 */
int mscCreatePath(const TCHAR *pszPath)
	{
	TCHAR ach[512];
	TCHAR *pachTok;

	if (pszPath == 0)
		return -1;

	StrCharCopy(ach, pszPath);
	pachTok = ach;

	// Basicly, we march along the string until we encounter a '\', flip
	// it to a NULL and try to create the path up to that point.
	// It would have been nice if CreateDirectory() could
	// create sub/sub directories, but it don't. - mrw
	//
	while (1)
		{
		if ((pachTok = StrCharFindFirst(pachTok, TEXT('\\'))) == 0)
			{
			if (!mscIsDirectory(ach) && !CreateDirectory(ach, 0))
				return -2;

			break;
			}

		if (pachTok != ach)
			{
			*pachTok = TEXT('\0');

			if (!mscIsDirectory(ach) && !CreateDirectory(ach, 0))
				return -3;

			*pachTok = TEXT('\\');
			}

		pachTok = StrCharNext(pachTok);
		}

	return 0;
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 * FUNCTION:
 *	mscIsDirectory
 *
 * DESCRIPTION:
 *	Checks to see if a string is a valid directory or not.
 *
 * PARAMETERS:
 *	pszName   -- the string to test
 *
 * RETURNS:
 *	TRUE if the string is a valid directory, otherwise FALSE.
 *
 */
int mscIsDirectory(LPCTSTR pszName)
	{
	DWORD dw;

	dw = GetFileAttributes(pszName);

	if ((dw != (DWORD)-1) && (dw & FILE_ATTRIBUTE_DIRECTORY))
		return TRUE;

	return FALSE;
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 * FUNCTION:
 *	mscAskWizardQuestionAgain
 *
 * DESCRIPTION:
 *	Reads a value from the Registry.  This value represents how many times
 *	the user responded "NO" to the question:  "Do you want to run the
 *	New Modem Wizard?".  We won't ask this question any more if the
 *	user responded no, twice.
 *
 * PARAMETERS:
 *	None
 *
 * RETURNS:
 *	TRUE if the modem wizard question should be asked again, otherwize
 *	FALSE.
 *
 */
int mscAskWizardQuestionAgain(void)
	{
	long	lResult;
	DWORD	dwKeyValue = 0;
	DWORD	dwSize;
	DWORD	dwType;
	TCHAR	*pszAppKey = "HYPERTERMINAL";

	dwSize = sizeof(DWORD);

	lResult = RegQueryValueEx(HKEY_CLASSES_ROOT, (LPTSTR)pszAppKey, 0,
		&dwType, (LPBYTE)&dwKeyValue, &dwSize);

	// If we are able to read a value from the registry and that value
	// is 1, there is no need to ask the question again, so return
	// a false value.
	//
	if ( (lResult == ERROR_SUCCESS) && (dwKeyValue >= 1) )
		return (FALSE);

	return (TRUE);
	}

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 * FUNCTION:
 *	mscUpdateRegistryValue
 *
 * DESCRIPTION:
 *	See mscAskWizardQuestionAgain.	If the user responds "NO" to this
 *	question, we update a counter in the registry.
 *
 * PARAMETERS:
 *	None
 *
 * RETURNS:
 *	void
 *
 */
void mscUpdateRegistryValue(void)
	{
	long	lResult;
	DWORD	dwKeyValue = 0;
	DWORD	dwSize;
	DWORD	dwType;
	TCHAR	*pszAppKey = "HYPERTERMINAL";

	dwSize = sizeof(DWORD);

	lResult = RegQueryValueEx(HKEY_CLASSES_ROOT, (LPTSTR)pszAppKey, 0,
		&dwType, (LPBYTE)&dwKeyValue, &dwSize);

	dwKeyValue += 1;

	lResult = RegSetValueEx(HKEY_CLASSES_ROOT, pszAppKey, 0,
		REG_BINARY, (LPBYTE)&dwKeyValue, dwSize);

	assert(lResult == ERROR_SUCCESS);

	return;
	}