#include <windows.h>
#include <io.h>
#include <errno.h>
#include <string.h>
#include <sys\types.h>
#include <sys\stat.h>
#include "app.h"

/*
 * Module: file.c
 *
 * Contains: File related functions.  File oriented fuctions
 * show go here.  This includes file related callback functions
 * for such dialog boxes as Open, Save, SaveAs.
 *
 */


/*********************************************************************/
/* Local Function Prototypes                                         */
/*********************************************************************/

int FAR PASCAL SaveAsDlg(HWND, unsigned, WORD, LONG);
HANDLE FAR PASCAL OpenDlg(HWND, unsigned, WORD, LONG);

void UpdateListBox(HWND hDlg);

void FileSetDefExt(PSTR Ext, PSTR Name);
void FileSeparateName(LPSTR DestPath, LPSTR DestFile, LPSTR Src);
void FileAddExt(PSTR Name, PSTR Ext);
BOOL FileCheckName(HWND hDlg, PSTR Dest, PSTR Src);
BOOL FileSaveBuffer(HWND Hdlg);
void FileSetNewBuffer(HANDLE hNewBuffer, PSTR Title);

/*********************************************************************/
/* Local data and structures                                         */
/*********************************************************************/

static char FileName[128] = "";    /* the name of the current file   */
static char PathName[128] = "";    /* file pathname                  */
static char OpenName[128] = "";    /* name of a file to try and open */
static char DefPath[128] = "";     /* current path                   */
static char DefSpec[13] = "*.wsn"; /* current file specification     */
static char DefExt[] = ".wsn";     /* current default extension      */
static char str[255] = "";         /* work string                    */

static HANDLE hEditBuffer;         /* edit buffer                    */
static HANDLE hOldBuffer;          /* old buffer handle              */
static HANDLE hHourGlass;          /* handle to hourglass cursor     */
static HANDLE hSaveCursor;         /* current cursor handle          */
static int hFile;                  /* file handle                    */
static int count;                  /* number of chars read or written*/
static PSTR pBuffer;               /* address of read/write buffer   */
static OFSTRUCT OfStruct;          /* information from OpenFile()    */
static struct stat FileStatus;     /* information from fstat()       */
static BOOL bSaveEnabled = FALSE;  /* TRUE if text in the edit buffer*/
static PSTR pEditBuffer;           /* address of the edit buffer     */
static RECT Rect;                  /* dimension of the client window */
static HWND hwnd;                  /* handle to main window          */

/*********************************************************************/
/* Global functions                                                  */
/*********************************************************************/

/*-------------------------------------------------------------------*/
/* Set current file to NEW.                                          */
/*-------------------------------------------------------------------*/

void FileNew(hWnd)
HWND hWnd;
{
  if (!FileQuerySave(hWnd))
    return;

  FileName[0] = 0;

  /* Update the edit buffer */
  wsprintf(str, "%s %s", (LPSTR) WindowName,(LPSTR)" - Untitled");
  FileSetNewBuffer(NULL, str);
}

/*-------------------------------------------------------------------*/
/* Invoke a dialog box to open a file, check to save the current file*/
/*-------------------------------------------------------------------*/

void FileOpen(hWnd)
HWND hWnd;
{
  int numbytes;

  if (!FileQuerySave(hWnd))
    return;

  /* Open the file and get its handle */
  hFile = GoDialogBox(hInst, "Open", hWnd, (FARPROC)OpenDlg);
  if (hFile <= 0)
    return;

  /* Allocate edit buffer to the size of the file + 1 */
  hEditBuffer = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (WORD)(FileStatus.st_size+1));

  if (!hEditBuffer) {
    MessageBox(hWnd, "Not enough memory.", NULL, MB_OK | MB_ICONHAND);
    return;
  }
  hSaveCursor = SetCursor(hHourGlass);
  pEditBuffer = LocalLock(hEditBuffer);

  numbytes = _lread(hFile, (LPSTR)pEditBuffer, (WORD)FileStatus.st_size);
  close(hFile);

  /* # bytes read must equal file size */
  if (numbytes != FileStatus.st_size) {
    wsprintf(str, "Error reading %s.", (LPSTR)FileName);
    SetCursor(hSaveCursor);      /* Remove the hourglass */
    MessageBox(hWnd, str, NULL, MB_OK | MB_ICONEXCLAMATION);
  }

  LocalUnlock(hEditBuffer);
  /* Set up a new buffer and window title */
  wsprintf(str, (LPSTR)"%s - %s", (LPSTR)WindowName, (LPSTR)FileName);
  FileSetNewBuffer(hEditBuffer, str);
  SetCursor(hSaveCursor);
}

/*-------------------------------------------------------------------*/
/* Save the current file                                             */
/*-------------------------------------------------------------------*/

void FileSave(hWnd)
HWND hWnd;
{
  if (!FileName[0])
    FileSaveAs(hWnd);
  FileSaveBuffer(hWnd);
}

/*-------------------------------------------------------------------*/
/* Save the current file prompting for a filename                    */
/*-------------------------------------------------------------------*/

void FileSaveAs(hWnd)
HWND hWnd;
{
  int Success;

  /* Call the SaveAsDlg() function to get the new filename */
  Success = GoDialogBox(hInst, "SaveAs", hWnd, (FARPROC)SaveAsDlg);

  /* If successful, update the window title, save the file */
  if (Success == IDOK) {
    wsprintf(str, (LPSTR)"%s - %s", (LPSTR)WindowName,(LPSTR)FileName);
    SetWindowText(hWnd, str);
    FileSaveBuffer(hWnd);
  }
}


/*-------------------------------------------------------------------*/
/*  SaveAs dialog box callback function.                             */
/*-------------------------------------------------------------------*/

int FAR PASCAL SaveAsDlg(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
  char TempName[128];

  switch (message) {
    case WM_INITDIALOG:
      /* If no filename is entered, don't allow the user to save to it */
      if (!FileName[0])
        bSaveEnabled = FALSE;
      else {
        bSaveEnabled = TRUE;

        /* Process the path to fit within the IDC_PATH field */
        DlgDirList(hDlg, DefPath, NULL, IDC_PATH, 0x4010);

        /* Send the current filename to the edit control */
        SetDlgItemText(hDlg, IDC_EDIT, FileName);

        /* Accept all characters in the edit control */
        SendDlgItemMessage(hDlg, IDC_EDIT, EM_SETSEL, 0, MAKELONG(0, 0x7fff));
      }

      /* Enable or disable the save control depending on whether the
       * filename exists.
       */
      EnableWindow(GetDlgItem(hDlg, IDOK), bSaveEnabled);

      /* Set the focus to the edit control within the dialog box */
      SetFocus(GetDlgItem(hDlg, IDC_EDIT));
      return(FALSE);                 /* FALSE since Focus was changed */

    case WM_COMMAND:
      switch (wParam) {
        case IDC_EDIT:
          /* If there was previously no filename in the edit
           * control, then the save control must be enabled as soon as
           * a character is entered.
           */
          if (HIWORD(lParam) == EN_CHANGE && !bSaveEnabled)
            EnableWindow(GetDlgItem(hDlg, IDOK), bSaveEnabled = TRUE);
          return (TRUE);

        case IDOK:
          /* Get the filename from the edit control */
          GetDlgItemText(hDlg, IDC_EDIT, TempName, 128);

          /* If there are no wildcards, then separate the name into
           * path and name.  If a path was specified, replace the
           * default path with the new path.
           */
          if (FileCheckName(hDlg, FileName, TempName)) {
            FileSeparateName((LPSTR) str, (LPSTR) DefSpec, (LPSTR) FileName);
            if (str[0])
              strcpy(DefPath, str);

            /* Tell the caller a filename was selected */
            EndDialog(hDlg, IDOK);
          }
          return (TRUE);

        case IDCANCEL:
          /* Tell the caller the user canceled the SaveAs function */
          EndDialog(hDlg, IDCANCEL);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

/*-------------------------------------------------------------------*/
/* Open dialog box callback function.                                */
/*-------------------------------------------------------------------*/

HANDLE FAR PASCAL OpenDlg(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
  WORD index;
  PSTR pTptr;
  HANDLE hFile;

  switch (message) {
    case WM_COMMAND:
      switch (wParam) {
        case IDC_LISTBOX:
          if (HIWORD(lParam) == LBN_SELCHANGE) {
            /* If item is a directory name, append "*.*" */
            if (DlgDirSelect(hDlg, str, IDC_LISTBOX))
              strcat(str, DefSpec);

            SetDlgItemText(hDlg, IDC_EDIT, str);
            SendDlgItemMessage(hDlg, IDC_EDIT, EM_SETSEL, NULL, MAKELONG(0, 0x7fff));
            break;
          }
          else if (HIWORD(lParam) == LBN_DBLCLK)
            ;
          else
            return(TRUE);

        case IDOK:
          GetDlgItemText(hDlg, IDC_EDIT, OpenName, 128);
          if (strchr(OpenName, '*') || strchr(OpenName, '?')) {
            FileSeparateName((LPSTR) str, (LPSTR) DefSpec, (LPSTR) OpenName);
            if (str[0])
              strcpy(DefPath, str);
            FileSetDefExt(DefExt, DefSpec);
            UpdateListBox(hDlg);
            return (TRUE);
          }

          if (!OpenName[0]) {
            MessageBox(hDlg, "No filename specified.", NULL, MB_OK | MB_ICONHAND);
            return (TRUE);
          }

          FileAddExt(OpenName, DefExt);

          /* Open the file */
          if ((int)(hFile = OpenFile(OpenName, (LPOFSTRUCT)&OfStruct, OF_READ)) == -1) {
            wsprintf(str, "Error %d opening %s.", OfStruct.nErrCode, (LPSTR)OpenName);
            MessageBox(hDlg, str, NULL, MB_OK | MB_ICONHAND);
          }
          else {
            /* Make sure there's enough room for the file */
            fstat(hFile, &FileStatus);
            if (FileStatus.st_size > MAXFILESIZE) {
              wsprintf(str,
                "Not enough memory to load %s.\n%s exceeds %ld bytes.",
                (LPSTR)OpenName,
                (LPSTR)OpenName,
                MAXFILESIZE);
              MessageBox(hDlg, str, NULL, MB_OK | MB_ICONHAND);
              return (TRUE);
            }

            /* File is opened and there is enough room so return
             * the handle to the caller.
             */

            strcpy(FileName, OpenName);
            EndDialog(hDlg, hFile);
            return (TRUE);
          }
          return (TRUE);

        case IDCANCEL:
          EndDialog(hDlg, NULL);
          return (TRUE);
      }
      break;

    case WM_INITDIALOG:                        /* message: initialize    */
      UpdateListBox(hDlg);
      SetDlgItemText(hDlg, IDC_EDIT, DefSpec);
      SendDlgItemMessage(hDlg,               /* dialog handle      */
        IDC_EDIT,                            /* where to send message  */
        EM_SETSEL,                           /* select characters      */
        NULL,                                /* additional information */
        MAKELONG(0, 0x7fff));                /* entire contents      */
      SetFocus(GetDlgItem(hDlg, IDC_EDIT));
      return (FALSE);           /* Indicates the focus is set to a control */
  }
  return FALSE;
}

/*-------------------------------------------------------------------*/
/*  Update the list box of OpenDlg.                                  */
/*-------------------------------------------------------------------*/

void UpdateListBox(hDlg)
HWND hDlg;
{
  strcpy(str, DefPath);
  strcat(str, DefSpec);
  DlgDirList(hDlg, str, IDC_LISTBOX, IDC_PATH, 0x4010);

  /* To ensure that the listing is made for a subdir. of
   * current drive dir...
   */
  if (!strchr (DefPath, ':'))
    DlgDirList(hDlg, DefSpec, IDC_LISTBOX, IDC_PATH, 0x4010);

  /* Remove the '..' character from path if it exists, since this
   * will make DlgDirList move us up an additional level in the tree
   * when UpdateListBox() is called again.
   */
  if (strstr (DefPath, ".."))
    DefPath[0] = '\0';

  SetDlgItemText(hDlg, IDC_EDIT, DefSpec);
}

/*-------------------------------------------------------------------*/
/*  Change the default extension.                                    */
/*-------------------------------------------------------------------*/

void FileSetDefExt(Ext, Name)
PSTR Ext, Name;
{
  PSTR pTptr;

  pTptr = Name;
  while (*pTptr && *pTptr != '.')
    pTptr++;
  if (*pTptr)
    if (!strchr(pTptr, '*') && !strchr(pTptr, '?'))
      strcpy(Ext, pTptr);
}

/*-------------------------------------------------------------------*/
/*  Separate the filename and the path.                              */
/*-------------------------------------------------------------------*/

void FileSeparateName(lpDestPath, lpDestFileName, lpSrcFileName)
LPSTR lpDestPath, lpDestFileName, lpSrcFileName;
{
  LPSTR lpTmp;
  char  cTmp;

  lpTmp = lpSrcFileName + (long) lstrlen(lpSrcFileName);
  while (*lpTmp != ':' && *lpTmp != '\\' && lpTmp > lpSrcFileName)
    lpTmp = AnsiPrev(lpSrcFileName, lpTmp);
  if (*lpTmp != ':' && *lpTmp != '\\') {
    lstrcpy(lpDestFileName, lpSrcFileName);
    lpDestPath[0] = 0;
    return;
  }
  lstrcpy(lpDestFileName, lpTmp + 1);
  cTmp = *(lpTmp + 1);
  lstrcpy(lpDestPath, lpSrcFileName);
  *(lpTmp + 1) = cTmp;
  lpDestPath[(lpTmp - lpSrcFileName) + 1] = 0;
}

/*-------------------------------------------------------------------*/
/*  Add the default extension to a file name.                        */
/*-------------------------------------------------------------------*/

void FileAddExt(Name, Ext)
PSTR Name, Ext;
{
  PSTR pTptr;

  pTptr = Name;
  while (*pTptr && *pTptr != '.')
    pTptr++;
  if (*pTptr != '.')
    strcat(Name, Ext);
}

/*-------------------------------------------------------------------*/
/* Check the filename for wildcards and extension when saving a file.*/
/*-------------------------------------------------------------------*/

BOOL FileCheckName(hDlg,pDest, pSrc)
HWND hDlg;
PSTR pDest, pSrc;
{
  PSTR pTmp;

  if (!pSrc[0])
    return (FALSE);               /* Indicates no filename was specified */

  pTmp = pSrc;
  while (*pTmp) {                     /* Searches the string for wildcards */
    switch (*pTmp++) {
      case '*':
      case '?':
        MessageBox(hDlg, "Wildcards not allowed.", NULL, MB_OK | MB_ICONEXCLAMATION);
        return (FALSE);
    }
  }

  FileAddExt(pSrc, DefExt);

  if (OpenFile(pSrc, (LPOFSTRUCT) &OfStruct, OF_EXIST) >= 0) {
    wsprintf(str, "Replace existing %s?", (LPSTR)pSrc);
    if (MessageBox(hDlg, str, WindowName, MB_OKCANCEL | MB_ICONHAND) == IDCANCEL)
      return (FALSE);
  }
  strcpy(pDest, pSrc);
  return (TRUE);
}

/*-------------------------------------------------------------------*/
/*  Save the contents of the edit buffer to a file.                  */
/*-------------------------------------------------------------------*/

BOOL FileSaveBuffer(hDlg)
HWND hDlg;
{
  BOOL bSuccess;
  int numbytes;

  if ((hFile = OpenFile(FileName, &OfStruct, OF_PROMPT|OF_CANCEL|OF_CREATE)) < 0) {
    wsprintf(str, "Cannot write to %s.", (LPSTR)FileName);
    MessageBox(hDlg, str, NULL, MB_OK | MB_ICONEXCLAMATION);
    return (FALSE);
  }

  hEditBuffer = SendMessage(hEditWindow, EM_GETHANDLE, 0, 0L);
  pEditBuffer = LocalLock(hEditBuffer);

  hSaveCursor = SetCursor(hHourGlass);
  numbytes = _lwrite(hFile, (LPSTR)pEditBuffer, (WORD)strlen(pEditBuffer));
  close(hFile);
  SetCursor(hSaveCursor);
  if (numbytes != strlen(pEditBuffer)) {
    wsprintf(str, "Error writing to %s.", (LPSTR)FileName);
    MessageBox(hDlg, str, NULL, MB_OK | MB_ICONHAND);
    bSuccess = FALSE;
  }
  else {
    bSuccess = TRUE;                /* Indicates the file was saved      */
  }
  LocalUnlock(hEditBuffer);
  SendMessage(hEditWindow, EM_SETMODIFY, 0, 0L);
  return (bSuccess);
}

/*-------------------------------------------------------------------*/
/*  Ask if the current contents of the edit buffer should be saved.  */
/*-------------------------------------------------------------------*/

BOOL FileQuerySave(hWnd)
HWND hWnd;
{
  int Response;

  if (SendMessage(hEditWindow, EM_GETMODIFY, 0, 0L) != 0) {
    wsprintf(str, "Save current changes: %s", (LPSTR)FileName);
    Response = MessageBox(hWnd, str, WindowName, MB_YESNOCANCEL | MB_ICONEXCLAMATION);
    if (Response == IDYES) {
      while (!FileName[0]) {
        Response = GoDialogBox(hInst, "SaveAs", hWnd, (FARPROC)SaveAsDlg);
        if (Response == IDOK)
          continue;
        else
          return (FALSE);
      }
      FileSaveBuffer(hWnd);
    }
    else if (Response == IDCANCEL)
      return(FALSE);
  }
  return(TRUE);
}

/*-------------------------------------------------------------------*/
/*  Reset the edit window file buffer to a new one.                  */
/*-------------------------------------------------------------------*/

void FileSetNewBuffer(hNewBuffer, Title)
HANDLE hNewBuffer;
PSTR Title;
{
  HANDLE hOldBuffer;

  hOldBuffer = SendMessage(hEditWindow, EM_GETHANDLE, 0, 0L);
  LocalFree(hOldBuffer);
  if (!hNewBuffer)
    hNewBuffer = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, 1);

  /* Updates the buffer and displays new buffer */
  SendMessage(hEditWindow, EM_SETHANDLE, hNewBuffer, 0L);
  SendMessage(hEditWindow, EM_SETMODIFY, 0, 0L);

  SetWindowText(hWindow, Title);
  SetFocus(hEditWindow);
}

