/*-----------------------------------------------------
   POPPAD2.C -- Popup Editor Version 2 (includes menu)
                (c) Charles Petzold, 1992
  -----------------------------------------------------*/

/* TkWin version 0.2 -- Tk for Windows
 * Copyright (C) 1994 K. K. Kubota
 * Mathematical Sciences Computing Facility, University of Kentucky,
 * Lexington, KY 40506, USA (e-mail: ken@ms.uky.edu)
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose is granted without fee, provided that the above copyright notice
 * and the following paragraph appear in all copies of this software
 * and supporting documentation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY, even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  In no event shall the author be
 * liable to any party for direct, indirect, special, incidental, or
 * consequential damages arising out of the use of this software and its
 * documentation.
 */

/*-----------------------------------------------------
   Wish.c -- Tk 3.6 Interpreter for Windows
   This code derived from PopPad2 by Charles Petzold
  -----------------------------------------------------*/

#define WISH
#define SINGLE_EXECUTION

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef WISH
#include "wish.h"
#include <tkint.h>
#else
#include "wintclsh.h"
#include <windows.h>
#include "tcl.h"
#endif
Tcl_Interp *interp;
static Tcl_DString command;	/* Used to buffer incomplete commands */
char cmdBuf[300];		/* Line buffer for commands */
int Ready = 0;
#ifdef WISH
int argc = 1;
char *argv[20] = {"Wish", NULL};
#else
int argc = 1;
char *argv[] = {"WinTclSh", 0};
#endif


long FAR PASCAL _export WndProc (HWND, UINT, UINT, LONG);
long FAR PASCAL _export EditProc (HWND, UINT, UINT, LONG) ;
BOOL FAR PASCAL _export AboutDlgProc (HWND, UINT, UINT, LONG) ;

FARPROC lpfnOldEdit ;
LOGFONT logfont;
HFONT hFont;

#ifdef WISH
char szAppName [] = "Wish" ;
#else
char szAppName [] = "WinTclSh" ;
#endif

#ifdef WISH
int getargs(char *cmdline){
     char *cmdp, *p;
     int i;
     int cflag = 0;
     cmdp = (char *)malloc(strlen(cmdline) + 1);
     strcpy(cmdp, cmdline);
     p = strtok(cmdp, " \t\r\n");
     argc = 1;
     for(i = 1; i < 19; i++){
	argv[i] = p;
	if(p) {
	    argc++;
	    if(strcmp(p, "-c") == 0) cflag = 1;
	    p = strtok(NULL, " \t\r\n");
	} else break;
     }
     return cflag;
}
#endif

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
   LPSTR lpszCmdLine, int nCmdShow) {
#ifndef WISH
    HANDLE   hAccel ;
#endif
    HWND     hwnd ;
    MSG      msg;
    WNDCLASS wndclass ;
    int consoleFlag;
    int ret;
    char *errmsg;

#ifdef WISH
    consoleFlag = getargs(lpszCmdLine);
#endif
    if (!hPrevInstance) {
        wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
        wndclass.lpfnWndProc   = WndProc ;
        wndclass.cbClsExtra    = 0 ;
        wndclass.cbWndExtra    = 0 ;
        wndclass.hInstance     = hInstance ;
        wndclass.hIcon         = LoadIcon (hInstance, szAppName) ;
        wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
        wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
        wndclass.lpszMenuName  = szAppName ;
        wndclass.lpszClassName = szAppName ;

        RegisterClass (&wndclass) ;
    }
#ifdef SINGLE_EXECUTION
    else {
	MessageBox(NULL, "Sorry, only one Wish allowed at a time!",
	    "Wish", MB_OK);
	return NULL;
    }
#endif
	  
    /* Increase the application queue size from default value of 8.
     * At the default value, cross application SendMessage of WM_KILLFOCUS
     * will fail because the handler will not be able to do a PostMessage!
     */
    /* Changed to 96 from 64 with tk4.0 -- not clear that it is needed */
    SetMessageQueue(96);

    hwnd = CreateWindow (szAppName, "Wish Console", WS_OVERLAPPEDWINDOW,
        GetSystemMetrics (SM_CXSCREEN) / 4, GetSystemMetrics (SM_CYSCREEN) / 4,
        GetSystemMetrics (SM_CXSCREEN) / 2, GetSystemMetrics (SM_CYSCREEN) / 2,
        NULL, NULL, hInstance, NULL) ;

    ShowWindow (hwnd, (argc == 1) ? nCmdShow :
	((consoleFlag == 1) ? SW_MINIMIZE : SW_HIDE)) ;
    UpdateWindow (hwnd); 

#ifndef WISH
    hAccel = LoadAccelerators (hInstance, szAppName) ;
#endif

#ifdef WISH
    interp = Tcl_CreateInterp();
    Tk_SetInstance(interp, hInstance, hPrevInstance, lpszCmdLine, nCmdShow, hwnd);
    errmsg = Tk_InterpStart(interp, argc, argv);
    if(strlen(errmsg) &&
	MessageBox(NULL, errmsg, "Continue?", MB_YESNO) == IDNO) {
	exit(1);
    }
    Tcl_DStringInit(&command);
    Ready = 1;
    ret = 0;
    ret = Tk_MainLoop(interp);
    Tcl_DeleteInterp(interp);
    WinsockCleanup();
    return ret;
#else
    while (GetMessage (&msg, NULL, 0, 0)) {
        if (!TranslateAccelerator (hwnd, hAccel, &msg)) {
            TranslateMessage (&msg) ;
            DispatchMessage (&msg) ;
               }
        }
    return msg.wParam ;
#endif
}

AskConfirmation (HWND hwnd) {
#ifdef WISH
    return MessageBox (hwnd, "Really want to close Wish?",
        szAppName, MB_YESNO | MB_ICONQUESTION) ;
#else
    return MessageBox (hwnd, "Really want to close WinTclSh?",
        szAppName, MB_YESNO | MB_ICONQUESTION) ;
#endif
}

long FAR PASCAL _export WndProc (HWND hwnd, UINT message, UINT wParam,
    LONG lParam) {
    static HANDLE  hInst ;
    static FARPROC lpfnAboutDlgProc ;
    static HWND hwndEdit ;
#ifdef NOTDEF
    static Once = 0;
#endif
    LONG        lSelect ;
    WORD        wEnable ;
    int i;

    switch (message) {
        case WM_CREATE:
            hInst = ((LPCREATESTRUCT) lParam)->hInstance ;
            lpfnAboutDlgProc = MakeProcInstance ((FARPROC) AboutDlgProc,
                                                    hInst) ;
            hwndEdit = CreateWindow ("edit", NULL,
                WS_CHILD | WS_VISIBLE | /* WS_HSCROLL | WS_VSCROLL | */
                /* WS_BORDER | */ ES_LEFT | ES_MULTILINE |
                ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0, 0, 0, 0,
                hwnd, 1, ((LPCREATESTRUCT) lParam)->hInstance, NULL) ;
	    lpfnOldEdit = (FARPROC) GetWindowLong (hwndEdit, GWL_WNDPROC) ;
	    SetWindowLong(hwndEdit, GWL_WNDPROC, 
		(LONG) MakeProcInstance ((FARPROC)EditProc,
		GetWindowWord (hwnd, GWW_HINSTANCE))) ;
#ifdef NOTDEF
	    GetObject (GetStockObject (SYSTEM_FIXED_FONT), sizeof (LOGFONT),
		(LPSTR) &logfont);
	    hFont = CreateFontIndirect (&logfont);
#endif
	    SendMessage (hwndEdit, WM_SETFONT, hFont, 0L);
	    SendMessage (hwndEdit, WM_CHAR, '%', 1L);
	    SendMessage (hwndEdit, WM_CHAR, ' ', 1L);
            return 0 ;

        case WM_SETFOCUS:
            SetFocus (hwndEdit) ;
            return 0;

        case WM_SIZE: 
            MoveWindow (hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE);
            return 0 ;

        case WM_INITMENUPOPUP:
            if (lParam == 1){
                EnableMenuItem (wParam, IDM_UNDO,
                    SendMessage (hwndEdit, EM_CANUNDO, 0, 0L) ?
                    MF_ENABLED : MF_GRAYED) ;

                EnableMenuItem (wParam, IDM_PASTE,
                    IsClipboardFormatAvailable (CF_TEXT) ?
                    MF_ENABLED : MF_GRAYED) ;

                lSelect = SendMessage (hwndEdit, EM_GETSEL, 0, 0L) ;

                if (HIWORD (lSelect) == LOWORD (lSelect)) wEnable = MF_GRAYED ;
                else wEnable = MF_ENABLED ;

                EnableMenuItem (wParam, IDM_CUT,   wEnable) ;
                EnableMenuItem (wParam, IDM_COPY,  wEnable) ;
                EnableMenuItem (wParam, IDM_DEL,   wEnable) ;

                return 0 ;
            }
            break ;

        case WM_COMMAND :
            if (LOWORD (lParam)) {
#ifdef NOTDEF
		/* Shameless hack to avoid seeing why it doesn't work
		 * otherwise....
		 */
	        if(!Once && Ready){
		    Once = 1;
		    Tcl_DStringAppend(&command, "pack propagate . 1\n", -1);
		    Tcl_RecordAndEval(interp, command.string, 0);
	            Tcl_DStringFree(&command);
	        }
#endif
                if (wParam == 1 && HIWORD (lParam) == EN_ERRSPACE)
                    MessageBox (hwnd, "Edit control out of space.",
                        szAppName, MB_OK | MB_ICONSTOP) ;
		else if (wParam == 1 && HIWORD(lParam) == LBN_DBLCLK) {
		    char FAR *cmd;
		    int off;
		    HGLOBAL hResMem;
		    UINT nLength, line;
		    line = SendMessage(hwndEdit, EM_LINEFROMCHAR,
			SendMessage(hwndEdit, EM_LINEINDEX, -1, 0L), 0L) ;
		    *(WORD *) cmdBuf = sizeof(cmdBuf) - 1; 
		    nLength = SendMessage(hwndEdit, EM_GETLINE, line,
			(long) (LPSTR) cmdBuf);
		    cmdBuf[nLength] = '\n';
		    cmdBuf[nLength+1] = '\0';
		    off = (cmdBuf[0] == '%') ? 1 : 0 ;
		    cmd = Tcl_DStringAppend(&command, cmdBuf+off, -1);
		    if(Tcl_CommandComplete(cmd)){
		        int lineCnt;
		        char FAR *rp;
		        DWORD size;
		        Tcl_RecordAndEval(interp, cmd, 0);
		        Tcl_DStringFree(&command);
		        if(*interp->result != 0){
		  	    int lineCnt;
			    char FAR *rp = interp->result;
			    for(lineCnt = 0; *rp; rp++)
				if(*rp == '\n') lineCnt++ ;
			    size  = (DWORD)lstrlen(interp->result)
			        + lineCnt + 7;
			} else size = 5L;
			if((hResMem = GlobalAlloc(GHND, size)) != NULL) {
			    char FAR *p = GlobalLock(hResMem);
			    char FAR *p2 = interp->result;
			    char FAR *startp;
			    int len = strlen(p2);
			    startp = p;
			    if(p != NULL) {
				if(*p2 != 0) {
			 	    *p++ = '\r';
				    *p++ = '\n';

				    while(*p2 != '\0') {
				        if(*p2 == '\n')
				 	    *p++ = '\r';
					*p++ = *p2++ ;
				    }
			        }
				if(!len || (p != startp && *(p-1) != '\n')){
			            *p++ = '\r';
			    	    *p++ = '\n';
				}
				*p++ = '%';
				*p++ = ' ';
				*p = '\0';
				GlobalUnlock(hResMem);
				OpenClipboard(hwnd);
				EmptyClipboard() ;
				SetClipboardData(CF_TEXT, hResMem) ;
				CloseClipboard() ;
				SendMessage(hwndEdit, WM_PASTE, 0, 0L) ;
			    }
			} 
		    } else {
		        if((hResMem = GlobalAlloc(GHND, 3)) != NULL) { 
		            char FAR *p = GlobalLock(hResMem);
		            if(p != NULL) {
		   	        *p++ = '\r';
			        *p++ = '\n';
			        *p = '\0';
			        GlobalUnlock(hResMem);
				OpenClipboard(hwnd);
				EmptyClipboard() ;
				SetClipboardData(CF_TEXT, hResMem) ;
				CloseClipboard() ;
				SendMessage(hwndEdit, WM_PASTE, 0, 0L) ;
			    }
			}
		    }
		}
                return 0 ;
            } else {
	        switch (wParam) {
                    case IDM_EXIT:
                        SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
	    		break;
                    case IDM_UNDO:
                        SendMessage (hwndEdit, WM_UNDO, 0, 0L) ;
		        break;
                    case IDM_CUT:
                        SendMessage (hwndEdit, WM_CUT, 0, 0L) ;
		        break;
                    case IDM_COPY:
                        SendMessage (hwndEdit, WM_COPY, 0, 0L) ;
			break;
                    case IDM_PASTE:
                        SendMessage (hwndEdit, WM_PASTE, 0, 0L) ;
			break;
                    case IDM_DEL:
                        SendMessage (hwndEdit, WM_CLEAR, 0, 0L) ;
		        break;
                    case IDM_SELALL:
                        SendMessage (hwndEdit, EM_SETSEL, 0,
                            MAKELONG (0, 32767)) ;
			break;
                    case IDM_HELP:
                        MessageBox (hwnd, "Help not yet implemented!",
                            szAppName, MB_OK | MB_ICONEXCLAMATION) ;
		        break;
                    case IDM_ABOUT:
                        DialogBox (hInst, "AboutBox", hwnd,lpfnAboutDlgProc);
			break;
                }
		return 0;
	    }
            break ;

        case WM_CLOSE:
            if (IDYES == AskConfirmation (hwnd))
                PostQuitMessage(0);
            return 0 ;

        case WM_QUERYENDSESSION:
            if (IDYES == AskConfirmation (hwnd)) return 1L ;
            else return 0 ;

        case WM_DESTROY :
            PostQuitMessage (0) ;
            return 0 ;
	default:
    	    return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    return DefWindowProc (hwnd, message, wParam, lParam) ;
}

long FAR PASCAL _export EditProc(HWND hwnd, UINT message, UINT wParam,
    LONG lParam) {
    if(message == WM_CHAR && (wParam == '\r' || wParam == '\n')){
	SendMessage (GetParent (hwnd), WM_COMMAND, 1,
	    MAKELONG (hwnd, LBN_DBLCLK)) ;
	return 0 ;
    } else return CallWindowProc(lpfnOldEdit, hwnd, message, wParam, lParam) ;
}

BOOL FAR PASCAL _export AboutDlgProc (HWND hDlg, UINT message, UINT wParam,
    LONG lParam) {
    switch (message) {
        case WM_INITDIALOG:
            return TRUE ;
        case WM_COMMAND:
	    if(wParam == IDOK) {
                EndDialog (hDlg, 0) ;
                return TRUE ;
	    } else return FALSE;
    }
    return FALSE ;
}
