/********************************************************************
 *                                                                  *
 *  MODULE    :  WVFILER.C                                          *
 *                                                                  *
 *  PURPOSE   :  This file high-level File and Path functions to    *
 *               allow WinVN to communicate with the file system.   *
 *                                                                  *
 *                Author - John S. Cooper                           *
 *                Date   - Sept 10, 1994                            *
 *                                                                  *
 *******************************************************************/

/* ------------------------------------------------------------------------
 * File handlers
 *
 *
 * $Id: wvfiler.c 1.10 1996/08/13 04:40:16 dumoulin Exp $
 */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop
#include <io.h>					// for _access
#include <stdlib.h>				// itoa

#define MAXFILTERLEN 512

void							/* Set up filters */
GenerateFileFilters (HWND hParentWnd, char *filters)
{
  register int i;
  int len;
  char chReplace;

  if ((len = LoadString (hInst, IDS_FILTERSTRING, filters, MAXFILTERLEN - 1)) == 0) {
	MessageBox (hParentWnd, "No Filters Available", "String Load Failure", MB_OK);
	*filters = '\0';
  }
  else {
	chReplace = filters[len - 1];	/* grab separator */

	for (i = 0; filters[i] != '\0'; i++)
	  if (filters[i] == chReplace)
		filters[i] = '\0';
  }
}

/* ------------------------------------------------------------------------
 *  Asks for a path
 *  jsc
 */
BOOL
AskForFilePath (HWND hParentWnd, char *pathName, char *title)
{
  if (!DialogBoxParam (hInst, (LPCSTR) "WinVnSelectPath", hParentWnd, (DLGPROC) lpfnWinVnSelectPathDlg, (LPARAM) pathName))
	return (FAIL);
  strcpy (pathName, AnsiLower (DialogString));

  return (SUCCESS);
}

/* ------------------------------------------------------------------------
 * Asks for a filename which must exist
 */
BOOL
AskForExistingFileName (HWND hParentWnd, char *fileName, char *title)
{
  OPENFILENAME ofn;
  char szFile[MAXFILENAME];
  char filters[MAXFILTERLEN];

  GenerateFileFilters (hParentWnd, filters);

  memset (&ofn, 0, sizeof (OPENFILENAME));
  szFile[0] = '\0';
  ofn.lpstrTitle = title;
  ofn.lStructSize = sizeof (OPENFILENAME);
  ofn.hwndOwner = hParentWnd;
  ofn.lpstrFilter = filters;
  ofn.nFilterIndex = 1;
  ofn.lpstrFile = szFile;
  ofn.nMaxFile = sizeof (szFile);
  ofn.lpstrFileTitle = NULL;
  ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

  if (GetOpenFileName (&ofn) == 0)
	return (FAIL);
  strcpy (fileName, AnsiLower (szFile));
  return (SUCCESS);
}
/* ------------------------------------------------------------------------
 * Check if file name is OK based on SmartFiler settings.  If not, prompt user new name
 * Check if file already exists.  If so, prompt user OK to overwrite
 * If fileName contains a name on entry, check if it's OK, if yes-done
 */
BOOL
AskForNewFileName (HWND hParentWnd, char *fileName, char *startDir, BOOL appendOk)
{
  OPENFILENAME ofn;
  char mybuf[MAXINTERNALLINE];
  char szDirName[256];
  char szFile[256];
  BOOL valid;
  char filters[MAXFILTERLEN];

  GenerateFileFilters (hParentWnd, filters);

  /* loop while no filename, invalid filename, or file exists */
  while (fileName[0] == '\0' ||
		 (valid = VerifyFileName (fileName)) == FAIL ||
		 (!appendOk && _access (fileName, 0) == 0)) {

	/* filename valid, but file exists - ask if want to overwrite it */
	if (fileName[0] != '\0' && valid == SUCCESS) {
	  _snprintf (mybuf, MAXINTERNALLINE, "File %s exists.  OK to overwrite it?", fileName);
	  if (MessageBox (hParentWnd, mybuf, "File exists",
					  MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION) == IDYES)
		break;
	}

	/* Open dialog to ask user for a new file name */
	memset (&ofn, 0, sizeof (OPENFILENAME));
	if (fileName[0] != '\0')
	  _snprintf (mybuf, MAXINTERNALLINE, "Invalid file name %s. Select new name", fileName);
	else {
	  if (appendOk)
		strcpy (mybuf, "Select new file name to create/append");
	  else
		strcpy (mybuf, "Select new file name to create/overwrite");
	}
	ofn.lpstrTitle = mybuf;
	strcpy (szDirName, startDir);
	if (szDirName[0])
	  ofn.lpstrInitialDir = szDirName;
	else
	  ofn.lpstrInitialDir = NULL;

	ofn.lStructSize = sizeof (OPENFILENAME);
	ofn.hwndOwner = hParentWnd;
	ofn.lpstrFilter = filters;
	ofn.nFilterIndex = 1;
	szFile[0] = '\0';
	ofn.lpstrFile = szFile;
	ofn.nMaxFile = sizeof (szFile);
	ofn.lpstrFileTitle = NULL;
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;

	if (GetOpenFileName (&ofn) == 0)
	  return (FAIL);

	strcpy (fileName, strlwr (ofn.lpstrFile));
  }
  return (SUCCESS);
}
/* ------------------------------------------------------------------------
 * Test file name is OK using SmartFiler settings
 */
BOOL
VerifyFileName (char *fileName)
{
  char *beg, *ptr;

  if ((beg = strrchr (fileName, '\\')) == NULL)
	beg = fileName;
  else
	beg++;						/* skip to after path slash */

  if ((ptr = strchr (beg, '.')) == NULL)
	if (strlen (beg) <= MaxFileNameLen)		/* no extension */
	  return (SUCCESS);

  if ((unsigned int) (ptr - beg) > MaxFileNameLen)
	return (FAIL);

  beg = ptr + 1;
#ifndef WIN32					/* multiple extensions (ok in NTFS) */
  if ((ptr = strchr (beg, '.')) != NULL)
	return (FAIL);
#endif

  if (strlen (beg) > MaxFileExtLen)		/* extension too long */
	return (FAIL);

  return (SUCCESS);
}

/* ------------------------------------------------------------------------
 * SplitFileName into path, name, ext, fullName
 * i.e. c:\windows\system\xyz.txt returns xyz.txt
 * path     --> c:\windows\system  (note no final slash)
 * name     --> xyz
 * ext      --> txt
 * fullName --> xyz.txt
 *
 * args must be pointers to buffers large enough to hold strings
 * any of args can be NULL, in which case that fileName portion is ignored
 */
void
SplitFileName (char *path, char *name, char *ext, char *fullName, char *fileName)
{
  char *start, *slash, *dot, *end;
  BOOL restoreSlash;
#ifndef _WIN32
  char * ptr;
#endif

  start = fileName;
  end = start + strlen (fileName);

  if ((slash = strrchr (start, '\\')) == NULL) {
	/* handle case like c:abc.def (no slash) */
    restoreSlash = FALSE;
	if (start[1] == ':' && tolower (*start) >= 'a' && tolower (*start) <= 'z') {
	  slash = &start[2];
	}
	else {
	  slash = start;			/* there is no path */
	}
  }
  else {
	*slash = '\0';				/* replace last slash with null */
	restoreSlash = TRUE;
	slash++;
  }
  if (path) {
	if (slash == start)
	  *path = '\0';
	else
	  strcpy (path, start);		/* from start to slash is the path */
  }

  if (fullName)
	strcpy (fullName, slash);

  if ((dot = strrchr (slash, '.')) == NULL) {
	dot = end;
  }
  else {
	*dot = '\0';				/* replace last dot with null */
	
#ifndef WIN32					/* replace multiple dots with dashes in non-NTFS */
	for (ptr = slash; *ptr; ptr++) {
		if (*ptr == '.') {
			*ptr = '-';
		}
	}
#endif

	dot++;
  }
  if (name) {
	strcpy (name, slash);		/* from after the slash to dot is the name */
  }

  if (ext) {
	strcpy (ext, dot);			/* from after the dot to the end is the extension */
  }
  if (slash != start && restoreSlash)
	*(slash - 1) = '\\';		/* restore the slash */
  if (dot != end)
	*(dot - 1) = '.';			/* restore the dot */
}

/* useful front ends to SplitFileName */
char *
GetFileExtension (char *ext, char *fileName)
{
  SplitFileName (NULL, NULL, ext, NULL, fileName);
  return ext;
}

char *
NameWithoutPath (char *name, char *fileName)
{
  SplitFileName (NULL, NULL, NULL, name, fileName);
  return name;
}

char *
PathWithoutName (char *path, char *fileName)
{
  SplitFileName (path, NULL, NULL, NULL, fileName);
  return path;
}


/* ------------------------------------------------------------------------
 * Smartfiler: HandleDupeName 
 * check if dupe file name, and if there is, deal with it 
 * return SUCCESS if dupe and handled (fixed name in newName),or if no dupe
 * return FAIL on serious failure
 */
BOOL
HandleDupeName (HWND hParentWnd, char *fileName)
{
  char path[MAXFILENAME], name[MAXFILENAME], ext[MAXFILENAME], numStr[4];
  char newName[MAXFILENAME], namecat[MAXFILENAME];
  int i, len;

  if (_access (fileName, 0) < 0)
	return SUCCESS;

  /* we have a dupe */
  strcpy (newName, fileName);
  SplitFileName (path, name, ext, NULL, fileName);
  switch (OnDupeName) {
  case DUPE_AVOID_NONE:
	return AskForNewFileName (hParentWnd, fileName, path, FALSE);
	break;

  case DUPE_AVOID_NUMBER_EXT:
	for (i = 0; i < 999; i++) {
	  _snprintf (newName, MAXFILENAME, "%s\\%s.%03d", path, name, i);
	  if (_access (newName, 0) < 0)
		break;
	}
	break;

  case DUPE_AVOID_PREPEND_NUM:
	for (i = 0; i < 999; i++) {
	  _snprintf (namecat, MAXFILENAME, "%d%s", i, name);
	  namecat[MaxFileNameLen] = '\0';
	  _snprintf (newName, MAXFILENAME, "%s\\%s.%s", path, namecat, ext);
	  if (_access (newName, 0) < 0)
		break;
	}
	break;

  case DUPE_AVOID_APPEND_NUM:
	for (i = 0; i < 999; i++) {
	  itoa (i, numStr, 10);
	  len = MaxFileNameLen - strlen (numStr);
	  if (len <= 0) {
		i = 1000;
		break;
	  }
	  name[len] = '\0';
	  _snprintf (namecat, MAXFILENAME, "%s%d", name, i);
	  namecat[MaxFileNameLen] = '\0';
	  _snprintf (newName, MAXFILENAME, "%s\\%s.%s", path, namecat, ext);
	  if (_access (newName, 0) < 0)
		break;
	}
	break;
  }
  if (i == 1000)				/* we failed to get an alternative, so ask user for help */
	return AskForNewFileName (hParentWnd, fileName, path, FALSE);
  else
	strcpy (fileName, newName);

  return TRUE;
}

/* ------------------------------------------------------------------------
 * SmartFiler: HandleLongName
 * check if given name is longer than given maxLen, and if it is, deal with it 
 * return SUCCESS if too long and handled (fixed name in newName), 
 * or if name is not too long
 * return FAIL if not handled
 */
BOOL
HandleLongName (char *name, unsigned int maxLen)
{
  char newName[MAXFILENAME];
  unsigned int skipped, len, src, dest;
  BOOL result;

  len = strlen (name);
  if (len <= maxLen)
	return SUCCESS;

  /* name too long */
  switch (OnNameTooLong) {
  case SHORTEN_NONE:
	result = FAIL;
	break;

  case SHORTEN_TRUNCATE:
	name[maxLen] = '\0';
	result = SUCCESS;
	break;

  case SHORTEN_SKIP_VOWELS:
	src = dest = skipped = 0;
	while (dest < maxLen && src < len) {
	  if (len - skipped > maxLen && strchr ("aeiou-_*!@:#$%^&*{}[]<>,()+.", name[src])) {
		skipped++;
	  }
	  else {
		newName[dest] = name[src];
		dest++;
	  }
	  src++;
	}
	newName[dest] = '\0';
	strcpy (name, newName);
	result = SUCCESS;
	break;
  }
  return result;
}

/* ------------------------------------------------------------------------
 * SmartFiler: HandleExtensionConversion
 * check if ext is in the extension mapping list, and if so,
 * replace it with the mapped ext
 */
void
HandleExtensionConversion (char *ext)
{
  register unsigned long i;
  for (i = 0L; i < ExtMapSourceList->numLines; i++) {
	if (!_stricmp (TextBlockLine (ExtMapSourceList, i), ext)) {
	  strcpy (ext, TextBlockLine (ExtMapDosList, i));
	  break;
	}
  }
}

/* ------------------------------------------------------------------------
 * SmartFiler
 * processes fileName for dupe, too long, extension conversion
 * returns SUCCESS if everything works, else FAIL
 */
BOOL
SmartFile (HWND hParentWnd, char *fileName)
{
  char newName[MAXFILENAME];
  char path[MAXFILENAME], name[MAXFILENAME], ext[MAXFILENAME];
  BOOL result, result2;

  strcpy (newName, fileName);
  SplitFileName (path, name, ext, NULL, fileName);

  if (VerifyFileName (fileName) == FAIL) {
	if (EnableExtensionConversion)
	  HandleExtensionConversion (ext);

	result = HandleLongName (name, MaxFileNameLen);
	result2 = HandleLongName (ext, MaxFileExtLen);

	_snprintf (newName, MAXFILENAME, "%s\\%s.%s", path, name, ext);

	if (result == FAIL || result2 == FAIL) {
	  AskForNewFileName (hParentWnd, newName, path, FALSE);
	}

  }
  result = HandleDupeName (hParentWnd, newName);
  strcpy (fileName, newName);
  return result;
}
