/* 
 * Resident segment for the Windows Win100/Win600 emulator
 *
 * Copyright (c) 1989, 1990, 1991 by
 * William S. Hall
 * 3665 Benton Street, #66
 * Santa Clara, CA 95051
 *
 * $Date$
 * $Revision$
 * $RCSfile$
 * $Source$
 * $State$
 */

#define NOKANJI
#define NOSOUND
#define NOMINMAX
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <io.h>
#include <ascii.h>
#ifdef COLUMBIA
#include "wktsmt.h"
#else
#include "smterm.h"
#endif

#ifdef WIN600
#include "grterm.h"
#endif

#define EXTERN
#define INITIALIZE
#ifdef COLUMBIA
#include "wkt100.h"
#else
#include "win600.h"
#endif

#if defined(KERMIT)
#define KERMITEXTERN
#ifdef COLUMBIA
#include "wkkerm.h"
#else
#include "wnkerm.h"
#endif
#endif

static int NEAR ProcessComm(void);

/* Entry point for program */
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, 
		   LPSTR lpszCmdLine, int cmdShow)
{

  /* If initialization is not successful then exit */
    if (!InitProgram(hInstance,hPrevInstance, lpszCmdLine, cmdShow))
	return FALSE;

  /* Retrieve messages from Windows */

    while (TRUE)
	(*DoMessage)();

}

void NEAR DoGetMessage()
{
    MSG msg;

    if (GetMessage((LPMSG)&msg,NULL,0,0)) {
	if ((!TranslateAccelerator(MWnd.hWnd,hAccel,(LPMSG)&msg))
	    && (!IsWindow(Kermit.hWndXfer) || 
		!IsDialogMessage(Kermit.hWndXfer, &msg))) {
	    TranslateMessage((LPMSG)&msg);
	    DispatchMessage((LPMSG)&msg);
	}
    }
    else
	exit((int)msg.wParam);
}

void NEAR DoPeekMessage()
{
    MSG msg;

    if (PeekMessage((LPMSG)&msg,NULL,0,0,PM_REMOVE)) {
        if (msg.message == WM_QUIT)
	    exit((int)msg.wParam);
#if defined(KERMIT)
	if (IsWindow(Kermit.hWndXfer) && IsDialogMessage(Kermit.hWndXfer,&msg))
		;
	else 
#endif
	if (TranslateAccelerator(MWnd.hWnd,hAccel,(LPMSG)&msg))
		;
	else {
            TranslateMessage((LPMSG)&msg);
            DispatchMessage((LPMSG)&msg);
	}
    }
    else if (!ScrollLock) {
	ProcessComm();
	PostMessage(MWnd.hWnd, WM_USER, 0, 0L);
    }
}

/* All messages are processed here */
long FAR PASCAL MainWndProc(HWND hWnd,unsigned message,WORD wParam,LONG lParam)
{

    PAINTSTRUCT ps;
    FARPROC fp;
    short result;
    int minpos, maxpos;
    
    switch(message) {

	case WM_USER:
#if defined(KERMIT)
	    if (Kermit.InTransfer) {
		int startlen = ComBuf.len;
		wart();
		ComBuf.ptr += (startlen - ComBuf.len);
	        break;
	    }
#endif
	    if (ComBuf.len > 0) {
	        pBuf = &ComBuf;
		while ((*curproto.pf)())
		    ;
	        if (hLogFile > 0)
	            result = write(hLogFile, Buffer, ComBuf.ptr - Buffer);
            }
	    else if (GB.hBuf)
	        WriteClipData();
	    break;

   	case WM_CHANGECBCHAIN:
	    if (wParam == hWndNext)
		hWndNext = LOWORD(lParam);
	    SendMessage(hWndNext, message, wParam, lParam);
	    break;

	case WM_DRAWCLIPBOARD:
	    if (IsWindow(hWndNext))
		SendMessage(hWndNext, message, wParam, lParam);
	    if (OpenClipboard(hWnd)) {
		HMENU hMenu = GetMenu(hWnd);
		if (GetClipboardData(CF_TEXT) != NULL)
		    EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
		else
		    EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED);
		CloseClipboard();
	    }
	    break;

	case WM_TIMER:
	    WndTimer(hWnd, wParam);
	    break;

	case WM_CREATE:
	    MainWndCreate(hWnd, lParam);
#if defined(KERMIT)
	    if (!krmInit(hWnd, Buffer, &ComBuf.len, &cid,
			 GetMenuItemCount(GetMenu(hWnd)) - 1))
		PostMessage(MWnd.hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
#endif
	    break;

	case WM_KEYDOWN:
	    if (wParam == VK_SCROLL)
		ScrollLock = (ScrollLock == TRUE) ? FALSE : TRUE;
	    break;

	case WM_ERASEBKGND:
	    SelectObject((HDC)wParam, MWnd.hBrush);
	    FillRect((HDC)wParam, (LPRECT)&MWnd.rect, MWnd.hBrush);
	    return (LONG)TRUE;

	case WM_COMMAND:
#if defined(KERMIT)
	    if (krmWndCommand(hWnd, wParam))
		break;
#endif
	    WndCommand(hWnd, wParam, lParam);
	    break;

	case WM_CHAR:
#ifdef WIN600
	    if ((curproto.type == 'G') && (curproto.gtype == XC)) {
		SetGraphicsParams(US);
		AnswerEnq((BYTE)wParam, XC);
	    }
	    else
#endif
	        ProcessChars((BYTE)wParam, (int)LOWORD(lParam));
	    break;
	    
	case WM_DESTROY:
	    PostQuitMessage(0);
	    break;

	case WM_CLOSE:
#if defined(KERMIT)
	    if (krmShutdown() != IDYES)
	        break;
#endif
	    if (MWnd.hBrush)
	        DeleteObject(MWnd.hBrush);
	    CloseCommPort(hWnd, &cid);
	    if (IsWindow(hWndNext))
	        ChangeClipboardChain(hWnd, hWndNext);
	    if (hLogFile > 0)
		CloseLogFile();
	    if (GB.hBuf)
		LocalFree(GB.hBuf);
	    DestroyWindow(hWnd);
	    break;

	case WM_QUERYENDSESSION:
#if defined(KERMIT)
	    if (krmShutdown() != IDYES)
	        break;
#endif
	    return ((LONG)TRUE);

	case WM_ENDSESSION:
	    if (wParam) {
	        CloseCommPort(hWnd, &cid);
		if (hLogFile > 0)
		    CloseLogFile();
	    }
	    break;

	case WM_PAINT:
	    BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
#if defined(KERMIT)
	    if (IsIconic(hWnd)) {
		if (Kermit.InTransfer) {
		    SetTextColor(ps.hdc, ColorTable[MWnd.TextColor]);
		    SetBkColor(ps.hdc, ColorTable[MWnd.BGColor]);
		    krmPaint(hWnd, ps.hdc);
		}
		else {
		    RECT rect;
		    GetClientRect(hWnd, &rect);
		    DrawIcon(ps.hdc, 
			     (rect.right - GetSystemMetrics(SM_CXICON)) / 2,
			     (rect.bottom - GetSystemMetrics(SM_CYICON)) / 2,
			     krmIcon);
		}
	    }
	    else
#endif	    
	    MainWndPaint(hWnd, (LPPAINTSTRUCT)&ps);
	    EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
	    break;

#if defined(KERMIT)
	case WM_QUERYDRAGICON:
	    return MAKELONG(krmIcon, 0);
#endif

    	case WM_SIZE:
	    if (wParam == SIZEICONIC) {
//		DoMessage = DoGetMessage;
		break;
	    }
//	    DoMessage = DoPeekMessage;
	    MWnd.rect.right = LOWORD(lParam);	/* save these values */
	    MWnd.rect.bottom = HIWORD(lParam);

	    fp = MakeProcInstance((FARPROC)MainHasResized, hInst);
	    EnumChildWindows(hWnd, fp, lParam);
	    FreeProcInstance(fp);

	    if (hWnd == GetFocus())
		MakeCaret(TRUE);

	    if (IsWindow(hWndActive)) {
		if (curproto.type == 'A') {
	            LONG range = SendMessage(hWndActive, SMT_SIZEPARENT, 
						(WORD)hWndActive, lParam);
		    SetScrollPos(MWnd.hWnd, SB_HORZ, 0, FALSE);
		    SetScrollRange(MWnd.hWnd, SB_HORZ, 0, LOWORD(range), TRUE);
		}
#ifdef WIN600
		else
		    SetScrollRange(MWnd.hWnd, SB_HORZ, 0, 0, TRUE);
#endif
	    }
	    break;

	case WM_HSCROLL:
	     switch (wParam) {
		case SB_LINEUP:
		    GetScrollRange(hWnd, SB_HORZ, &minpos, &maxpos);
		    if ((result = GetScrollPos(hWnd, SB_HORZ)) > minpos) {
		        SetScrollPos(hWnd, SB_HORZ, result - 1, TRUE);
		        SendMessage(hWndActive, SMT_COMMAND, SM_HSCROLL,
						MAKELONG(result - 1, 0));
		    }
		    break;
		case SB_LINEDOWN:
		    GetScrollRange(hWnd, SB_HORZ, &minpos, &maxpos);
		    if ((result = GetScrollPos(hWnd, SB_HORZ)) < maxpos) {
		        SetScrollPos(hWnd, SB_HORZ, result + 1, TRUE);
		        SendMessage(hWndActive, SMT_COMMAND, SM_HSCROLL,
						MAKELONG(result + 1, 0));
		    }
		    break;
		case SB_THUMBPOSITION:
		    result = LOWORD(lParam);
		    SetScrollPos(hWnd, SB_HORZ, result, TRUE);
		    SendMessage(hWndActive, SMT_COMMAND, SM_HSCROLL,
							MAKELONG(result, 0));
		    break;
	    }
	    break;

    /* window has focus, so tty window can create a caret */
	case WM_SETFOCUS:
	    MakeCaret(TRUE);
	    break;

    /* window has lost focus, so it can tell tty to kill the caret */
	case WM_KILLFOCUS:
	    MakeCaret(FALSE);
	    break;

	default:
	    return ((long)DefWindowProc(hWnd,message,wParam,lParam));
	    break;
    }
    return(0L);
}

BOOL FAR PASCAL MainHasResized(HWND hWnd, LONG lParam)
{
    LONG range;

    if (IsWindow(hWnd))
        range = SendMessage(hWnd, SMT_SIZEPARENT, (WORD)hWndActive, lParam);
    return TRUE;
}


BOOL FAR PASCAL ColorChange(HWND hWnd, LONG lParam)
{
    if (IsWindow(hWnd)) {
        SendMessage(hWnd, SMT_SETATTRIBUTE, SM_COLORCHANGE, lParam);
	return TRUE;
    }
    return TRUE;
}

/* come here to read the communications buffer if no messages to process */
static int NEAR ProcessComm(void)
{

    COMSTAT ComStatus;
    register int result;
    register WORD room = BUFSIZE - ComBuf.len;

    if ((ComBuf.len > 0) && (ComBuf.ptr > Buffer))
	memmove(Buffer, ComBuf.ptr, ComBuf.len);
    ComBuf.ptr = Buffer;
    if (room) {
        if (GetCommError(cid, (COMSTAT FAR *)&ComStatus) == 0) {
            if (ComStatus.cbInQue) {
	        result = ReadComm(cid, Buffer + ComBuf.len, 
				  min(ComStatus.cbInQue, room));
	        ComBuf.len += abs(result);
	    }
	}
    }
    return (ComBuf.len);
}
