/* editccpd.cpp  A text editing application with extensive file handling */
/* capability. Uses the Common Dialog Functions GetOpenFileName() &      */
/* GetSaveFileName(). Adds cut, copy, paste, & delete facilities         */

#include <windows.h>
#include <commdlg.h>
#include <string.h>
#include <stdio.h>
#include "resource.h"

LRESULT CALLBACK WndProc (HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam);
int StringTableMessageBox (HWND hWnd, int nString, int nCaption, WORD wFlags);

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine,
    int nCmdShow)
{
    HWND        hWnd ;        /* the window's "handle" */
    HACCEL      hAccel ;        /* accelerator table handle */  
    MSG         msg ;         /* a message structure */
    WNDCLASS    wndclass ;    /* window class structure */
    char        cBuf [128] ;  /* character buffer */

        wndclass.style          = CS_HREDRAW | CS_VREDRAW ;
        wndclass.lpfnWndProc    = WndProc ;
        wndclass.cbClsExtra     = 0 ;
        wndclass.cbWndExtra     = 0 ;
        wndclass.hInstance      = hInstance ;
        wndclass.hIcon          = LoadIcon (hInstance, "MyIcon") ;
        wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW) ;
        wndclass.hbrBackground  = GetStockObject (WHITE_BRUSH) ;
        wndclass.lpszMenuName   = "MyMenu" ;
        wndclass.lpszClassName  = "MyClass" ;
                        /* register the window class */
        if (!RegisterClass (&wndclass))
            return 0 ;
 
    LoadString (hInstance, S_PROGRAMCAPTION, cBuf, sizeof (cBuf)) ;

    hWnd = CreateWindow ("MyClass", cBuf, WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
        NULL, NULL, hInstance, NULL) ;
    ShowWindow (hWnd, nCmdShow) ;   /* display the window */    
    UpdateWindow (hWnd) ;

    hAccel = LoadAccelerators (hInstance, "MYACCEL") ;  /* load accel. table */

    while (GetMessage (&msg, NULL, 0, 0))   /* message loop */
    {
        if (!TranslateAccelerator (hWnd, hAccel, &msg)) /* translate accel. */
        {
            TranslateMessage (&msg) ;   /* translate keyboard messages */
            DispatchMessage (&msg) ;    /* send message to WndProc() */
        }
    }

    return (msg.wParam) ;
}

LRESULT CALLBACK WndProc (HWND hWnd, UINT wMessage, 
                                        WPARAM wParam, LPARAM lParam)
{
    static  HANDLE          hInstance ;
    static  OPENFILENAME    ofn;                    /* open file name structure */
    FILE                    *fp ;
    PSTR                    pEditBuf ;
    static  HWND            hEditWindow ;
    int                     nFileLong ;
    char                    cBuf2 [128] ;
    static char szFileTitle[_MAX_FNAME + _MAX_EXT], /* filename and extension */
                szFile[_MAX_PATH];                  /* filename including path */
    static char szFilter[] = "Edit Files (*.edt)\0*.edt\0" \
                                         "Text Files (*.txt)\0*.txt\0" \
                                         "All Files (*.*)\0*.*\0\0";

    switch (wMessage)       /* process windows messages */
    {
        case WM_CREATE:     /* create edit control window */
            hInstance = (HINSTANCE)GetWindowLong (hWnd, GWL_HINSTANCE) ;
            hEditWindow = CreateWindow ("EDIT", "",
                WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE |
                ES_LEFT | ES_NOHIDESEL | WS_VSCROLL| ES_AUTOHSCROLL |
                WS_HSCROLL, 0, 0, 1, 1, hWnd, NULL, hInstance, NULL) ;
            SendMessage (hEditWindow, EM_LIMITTEXT, 32000, 0); 
            break ;

        case WM_SIZE:       /* keep edit control filling client area */
            MoveWindow (hEditWindow, 5, 0, LOWORD (lParam) - 5, 
                                         HIWORD (lParam), TRUE) ;
            break ;

        case WM_COMMAND:
            switch (LOWORD(wParam))      /* menu items */
            {
                case IDM_OPEN:   /* ff: opens and reads file selected by user */
                                 /* into edit buffer using file common dlg box*/
                                 /* set all open file structure members to zero */
                    memset(&ofn, 0, sizeof(OPENFILENAME));
                    ofn.lStructSize = sizeof(OPENFILENAME);
                    ofn.hwndOwner = hWnd;
                    ofn.lpstrFilter = szFilter;
                    ofn.lpstrFile = szFile;
                    ofn.nMaxFile = _MAX_PATH;
                    ofn.lpstrFileTitle = szFileTitle;
                    ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;
                    ofn.lpstrInitialDir = NULL;     /* use current directory */
                    ofn.lpstrDefExt = "edt";        /* default file extension */
                              
                    GetOpenFileName(&ofn);  /* fill ofn struct */
                    lstrcat(szFile,"\0");   /* make sure it's null terminated */

                    /***** Now open file, get info, and put in edit box *****/

                    fp = fopen (szFile,"rb") ; /* open the file */ 
                    if (fp == NULL)
                    {
                        LoadString (hInstance,S_FILENOTOPEN,cBuf2,sizeof (cBuf2)) ;
                        MessageBox (hWnd, szFileTitle, cBuf2, MB_OK | MB_ICONHAND) ;
                    }
                    else                 /* file is open, so read it */
                    {                    /* window title = file name */
                        SetWindowText (hWnd, szFileTitle) ;
                        /* find the length of file */
                        fseek (fp, 0, SEEK_END) ;
                        nFileLong = ftell (fp) ;
                        /* go back to front of file */
                        fseek (fp, 0, SEEK_SET) ;
                        /* allocate new edit buffer block */
                        pEditBuf = (PSTR)malloc (nFileLong+1) ;
                        if (pEditBuf != NULL)
                        {                /* copy file data to block */
                            fread (pEditBuf, 1, nFileLong, fp) ;
                            fclose(fp);     /* close the file */
                            pEditBuf[nFileLong] = 0 ; /* null terminate text */
                            /* send it to the edit control */
                            SetWindowText (hEditWindow, pEditBuf) ;
                            free (pEditBuf) ;
                        }
                        else
                            StringTableMessageBox (hWnd,S_NOTALLOC,S_MEMERROR,MB_OK | MB_ICONHAND) ;
                    }                        
                    break ;

                case IDM_SAVE:  /* save edit buffer to file selected by user */
                    /* set all structure members to zero */
                    memset(&ofn, 0, sizeof(OPENFILENAME));
                    ofn.lStructSize = sizeof(OPENFILENAME);
                    ofn.hwndOwner = hWnd;
                    ofn.lpstrFilter = szFilter;
                    ofn.lpstrFile = szFile;
                    ofn.nMaxFile = _MAX_PATH;
                    ofn.lpstrFileTitle = szFileTitle;
                    ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;
                    ofn.lpstrInitialDir = NULL;     /* use current directory */
                    ofn.lpstrDefExt = "edt";        /* default extension */

                    GetSaveFileName(&ofn); /* fill ofn struct */

                    /*** Now open file, get contents of edit box, save to file ***/

                    fp = fopen (szFile, "wb") ; /* open the file */  
                    if (fp == NULL)
                    {
                        LoadString (hInstance,S_FILENOTCREATE,cBuf2,sizeof (cBuf2)) ;
                        MessageBox (hWnd, szFileTitle, cBuf2, MB_OK | MB_ICONHAND) ;
                    }
                    else
                    {   /* window title = file name */
                        SetWindowText (hWnd, szFileTitle) ;
                        /* ff: copies edit buffer to file */
                        nFileLong = GetWindowTextLength (hEditWindow) ;
                        if (NULL == (pEditBuf = (PSTR)malloc(nFileLong+1)))
                        {
                            StringTableMessageBox (hWnd,S_NOTALLOC,S_MEMERROR,MB_OK|MB_ICONHAND) ;
                        }
                        else
                        {   /* get text from the edit control */
                            GetWindowText (hEditWindow, pEditBuf, nFileLong+1); 
                            /* write to the file */
                            fwrite (pEditBuf, 1, nFileLong, fp) ;
                            free (pEditBuf);
                        }
                    fclose(fp) ;
                    }
                    break ;

                case IDM_COPY:      /* copy menu item */
                    SendMessage (hEditWindow, WM_COPY, 0, 0L) ;
                    break ;

                case IDM_CUT:       /* cut menu item */ 
                    SendMessage (hEditWindow, WM_CUT, 0, 0L) ;
                    break ;

                case IDM_DELETE:    /* delete menu item */
                    SendMessage (hEditWindow, WM_CUT, 0, 0L) ;
                    if (OpenClipboard (hWnd))
                    {               /* empty clipboard */
                        EmptyClipboard () ;
                        CloseClipboard () ;
                    }
                    break ;

                case IDM_PASTE:     /* paste menu item */
                    SendMessage (hEditWindow, WM_PASTE, 0, 0L) ;
                    break ;

                case IDM_ABOUT:
                    StringTableMessageBox (hWnd, S_ABOUTTEXT, S_ABOUTCAPTION,
                        MB_OK | MB_ICONINFORMATION) ;
                    break ;             

                case IDM_QUIT:              /* "Quit" menu item */
                    DestroyWindow (hWnd) ;  /* destroy window, */
                    break ;                 /* terminating application */
            }
            break ;

        case WM_DESTROY:                    /* stop application */
            PostQuitMessage (0) ;
            break ;

        default:        /* default windows message processing */
            return (DefWindowProc (hWnd, wMessage, wParam, lParam)) ;
    }
    return (0) ;
}


/*** display a message box based on two string table entries ***/
int StringTableMessageBox (HWND hWnd, int nString, int nCaption, WORD
    wFlags)
{
    char    cBuf1 [128], cBuf2 [128] ;
    HANDLE  hInstance ;
    
    hInstance = (HINSTANCE)GetWindowLong (hWnd, GWL_HINSTANCE) ;
    LoadString (hInstance, nString, cBuf1, sizeof (cBuf1)) ;
    LoadString (hInstance, nCaption, cBuf2, sizeof (cBuf2)) ;
    return (MessageBox (hWnd, cBuf1, cBuf2, wFlags)) ;
}