/************************************************************************\
 * File Version Information
 * $Header: /Altair32v2/utilfunc.c 6     11/08/06 9:21p Racini $
 ************************************************************************/
/************************************************************************
  MITS Altair Emulator
  Utility Routines

  Copyright (c) 2000-2006 Richard A. Cini


Change Log:
  2005/09/22  RAC -- Began moving routines into this new module
  2006/05/12  RAC -- RELEASE MARKER -- v3.10.0200
  2006/06/13  RAC -- Added HOST_UniqueFilename function from Solace 3.2
  2006/11/15  RAC -- RELEASE MARKER -- v3.20.0400
************************************************************************/
#include <windows.h>	// required for all Windows applications
#include <commdlg.h>	// Windows common dialogs
#include <stdlib.h>		// C standard lib
#include <string.h>		// C-lib - strings
#include <stdio.h>		// C-lib - I/O 
#include "altair32.h"	// includes "resource.h" and exports from other major modules
#include "comcthlp.h"	// common control macros


/*--  HOST_ThrowErrMsg ----------------------------------------
	Routine to display an error message on the screen.
	Should be buffer-overrun safe. Can be used only after main
	window is initialized because it uses the application
	hwnd.	
-------------------------------------------------------------*/
void HOST_ThrowErrMsg(char *message)
{

	BOOL	trunc = FALSE;
	char	*destbuf;	// destination char *string
	size_t	msglen = 0;


	ASSERT(message != NULL);
	ASSERT(winstate.hWnd != NULL);

	destbuf = (char*)malloc(256 * sizeof(char));
    if (!destbuf)
		return;
	memset(destbuf, '\0', (256 * sizeof(char)));

	if ((msglen = strlen(message)) >= 256){
		trunc = TRUE;
		msglen = 251;
	}

	// if count is > strlen(source) string is null-paded. No null is
	// appended if count is <= strlen(source)
	strncpy(destbuf, message, msglen);	// copy up to 251 chars
	if (trunc){
		strncat(destbuf, "...", 3);		// append elipses
	}
	strncat(destbuf, "\n", 1);			// terminate string
	MessageBox(winstate.hWnd, destbuf, winstate.szAppName, MB_OK | MB_ICONEXCLAMATION);
	free(destbuf);

}


/*--  DoCaption  ----------------------------------------------
	Changes the title bar caption of the window associated with
	the passed-in HWND.
	
-------------------------------------------------------------*/
void DoCaption(HWND hwnd, char *appname, char *progname)
{
	char szCaption[64 + _MAX_FNAME + _MAX_EXT];


	wsprintf(szCaption, "%s - %s", appname, progname[0] ? progname : UNTITLED);
	SetWindowText(hwnd, szCaption);
}


/*--  HOST_ExtractPath  ---------------------------------------
	Returns a pointer to a string containing the path leading
	to the file name passed in. The caller must allocate and
	free the returned string.
		
-------------------------------------------------------------*/
char *HOST_ExtractPath(char *name)
{
    char *path, *p;
    int len;


    ASSERT(name != NULL);

    len = strlen(name);
    ASSERT(len > 0);

    path = strdup(name);
    ASSERT(path != NULL);

    // ...then erase the text after the last backslash.
    p = &path[len - 1];
    while (*p != '\\' && len > 1) {
		ASSERT(p > path); // at least one backslash
		p--;
		len--;
    }
    *p = '\0';	// wipe out tail

    return path;
}


/*--  HOST_IsAbsolutePath  ------------------------------------
	This function classifies the passed-in filename as being
	either relative (returns 0) or absolute (returns 1). To be
	considered absolute, it must have one of these forms:
		[driveletter]:\path\to\file.c	- or -
		\path\to\file.c
	otherwise it is considered relative. 
-------------------------------------------------------------*/
int HOST_IsAbsolutePath(char *name)
{

    ASSERT(name != NULL);
    if (isalpha(name[0]) && (name[1] == ':') && (name[2] == '\\'))
		return 1;
    if (name[1] == '\\')
		return 1;
    return 0;
}


/*--  HOST_MakeAbsolutePath  ----------------------------------
	If the passed-in filename isn't an absolute path, make it an
	absolute path assuming the name given is relative to the
	install directory. Caller must allocate and free space for
	the string returned. Returns NULL on error.	
-------------------------------------------------------------*/
char *HOST_MakeAbsolutePath(char *name)
{
    char *newname;


    if (name == NULL)
		return NULL;
    if (strlen(name) > _MAX_PATH)
		return NULL;

    if (HOST_IsAbsolutePath(name)) {
		newname = strdup(name);
    } else {
		int newlen = strlen(winstate.szBaseDir) + 1 + strlen(name) + 1;
		if (newlen > _MAX_PATH)
	    	return NULL;
		newname = (char *)malloc(newlen); 
		strcpy(newname, winstate.szBaseDir);
		strcat(newname, "\\");
		strcat(newname, name);
    }

    return newname;
}


/*--  just_filename  ------------------------------------------
	Returns a pointer to just the filename ignoring any leading
	path. Caller must allocate and free space for the returned
	string.
-------------------------------------------------------------*/
char *just_filename(char *fullname)
{
    char *p;
    int len;

    ASSERT(fullname != NULL);

    len = strlen(fullname);
    ASSERT(len > 0);

    // back up until a backslash or colon
    p = &fullname[len - 1];
    while (len > 0) {
		if (*p == '\\')
		    break;
		if (*p == ':')
		    break;
		p--;
		len--;
    }

    return (p+1);
}


/*--  GetFilenameFromUser  -----------------------------------
	Prompt the user to locate a file using Common Dialogs.
	Returns fully-qualified path to the file in one of the
	calling parameters.

	caption should be a string or NULL; outfile should be
	pointer to string buffer of size _MAX_PATH. On return, outfile
	is NULL or fully-qualified pathname. Can use just_filename
	to get short file name. newdisk=FALSE if image already exists
	and TRUE if image doesn't exist (but user typed file name to
	use to create new image).
-------------------------------------------------------------*/
BOOL GetFilenameFromUser(char *caption, char *outfile, BOOL *newdisk)
{

	char	szFileDir[_MAX_PATH];
	char	szFileName[_MAX_PATH];					// filename buffer
	char	szFileTitle[_MAX_FNAME + _MAX_EXT];	// filename only
	static  char szFilter[] = "Virtual Hard Disk Image Files (*.VHD;*.IMG)\0*.vhd;*.img\0" \
                              "All Files (*.*)\0*.*\0\0";
	OPENFILENAME	ofn;


	newdisk = FALSE;
	szFileName[0]	 = 0  /* EOS */;
	szFileTitle[0]	 = 0  /* EOS */;
	strcpy (szFileDir, winstate.szFilesDir);
	
	ofn.lStructSize       = sizeof(OPENFILENAME);
	ofn.hwndOwner         = winstate.hWnd;
	ofn.hInstance         = (HINSTANCE)NULL;
	ofn.lpstrFilter       = szFilter;		// filter string
	ofn.lpstrCustomFilter = NULL;			// used to preserve user-defined filters
	ofn.nMaxCustFilter    = 0;				// size of custom filter buffer
	ofn.nFilterIndex      = 0;				// current filter index
	ofn.lpstrFile         = szFileName;	// contains full path and filename on return
	ofn.nMaxFile          = _MAX_PATH;		// sizeof lpstrFile
	ofn.lpstrFileTitle    = szFileTitle;	// filename and extension only
	ofn.nMaxFileTitle     = _MAX_FNAME + _MAX_EXT;	// sizeof lpstrFileTitle
 	ofn.lpstrInitialDir   = szFileDir;		// initial directory
	ofn.lpstrTitle        = caption;		// title bar string or NULL
	ofn.Flags             = OFN_HIDEREADONLY | OFN_CREATEPROMPT;
	ofn.nFileOffset       = 0;				// offset to filename in lpstrFile
	ofn.nFileExtension    = 0;				// offset in TCHARs to ext. in lpstrFile
	ofn.lpstrDefExt       = "vhd";			// default extension
	ofn.lCustData         = 0L;			// data passed to hook procedure
	ofn.lpfnHook          = NULL;			// pointer to hook procedure
	ofn.lpTemplateName    = NULL;			// dialog box template

	// file could be already existing or new.
	if (!GetOpenFileName(&ofn)){	// GOFN returns zero on error
		outfile = NULL;
		newdisk = FALSE;
		return FALSE;
	}

	if(GetFileAttributes(szFileName) == 0xFFFFFFFF){		// FileNotFound (FNF)
		// flag that filename represents a "new" container file
		*newdisk = TRUE;
	}

	strncpy(outfile, szFileName, _MAX_PATH);	// copy string to caller
	return TRUE;
}


/*--  HOST_UniqueFilename  ------------------------------------
	Return a filename in the specified directory, dir, using a
	prefix name, prefix, if possible. Returns a malloc'd string
	if successful, NULL if not. An empty file is created with
	the given name.
-------------------------------------------------------------*/
char *HOST_UniqueFilename(const char *dir, const char *prefix)
{
#if 0  // not used because under XP, at least, the dir was being ignored
    return tempnam(dir, prefix);
#else
    char *tempname = (char *)malloc(MAX_PATH);
    int rv;

    if (tempname == NULL)
		return NULL;

    rv = GetTempFileName(dir, prefix, 0, tempname);
    if (rv == 0) {
		free(tempname);
		return NULL;
    }

    return tempname;
#endif
}

/*  end of file: utilfunc.c  */
