/* 
 * Initialization segment for the Windows Win100 emulator.
 * This code is discarded after it is used.
 *
 * Copyright (c) 1990, 1991 by
 * William S. Hall
 * 3665 Benton Street, #66
 * Santa Clara, CA 95051
 *
 * $Date$
 * $Revision$
 * $RCSfile$
 * $Source$
 * $State$
 */

#define NOKANJI
#define NOMINMAX
#define NOSOUND
#include <windows.h>
#include <stdlib.h>
#include <limits.h>
#include <ascii.h>
#include <string.h>
#ifdef COLUMBIA
#include "wktsmt.h"
#else
#include "smterm.h"
#endif
#ifdef WIN600
#include "grterm.h"
#endif
#ifdef COLUMBIA
#include "wkt100.h"
#else
#include "win600.h"
#endif

static char *szInitKeyStr;
static int Initlen;
static BOOL WinIniModified = FALSE;
#define INITKEYSIZE	1024

/* local function declarations */
static BOOL NEAR RegisterWindowClass(HANDLE);
static void NEAR GetCurrentInstanceData(HANDLE hInstance);
static void NEAR GetPrevInstanceData(HANDLE);
static BOOL NEAR MakeAndShowMainWnd(HANDLE, HANDLE, int);
static BOOL NEAR ReadInitialData(HANDLE hInstance);
static BOOL NEAR OpenAndSetCommPort(HANDLE hInstance);
static BOOL NEAR SearchKey(char *str, char *key, int len);
static int NEAR GetInitData(int id, int defval);

/* This routine is FAR since it is called from another segment */
BOOL FAR InitProgram(hInstance,hPrevInstance, lpszCmdLine, cmdShow)
HANDLE hInstance, hPrevInstance;
LPSTR lpszCmdLine;
int cmdShow;
{

  /*** GET COMMAND LINE ? ***/
    hInst = hInstance;
    DoMessage = DoPeekMessage;
    
  /* if this is the first instance of the program ... */
    if (!hPrevInstance) {
	GetCurrentInstanceData(hInstance);
	
	if (!RegisterWindowClass(hInstance))
	    return FALSE;

	hAccel = LoadAccelerators(hInstance, (LPSTR)szAppName);
    }

  /* A previous instance already exists so get global data from there */
    else
	GetPrevInstanceData(hPrevInstance);

    if (!ReadInitialData(hInstance))
	return FALSE;
    
  /* Create and show the window */
    if (!MakeAndShowMainWnd(hInstance,hPrevInstance, cmdShow))
	return FALSE;

    hWndText = MakeAndShowTermWindow(hInstance,
			       hPrevInstance,
    			       MWnd.hWnd,
			       &Smt,
			       ColorTable[Initdata.TextColor],
			       ColorTable[Initdata.BGColor],
 			       0,0,
    			       Initdata.TermRows,
    			       Initdata.TermCols,
			       Initdata.Wrap,
			       Initdata.Fontface,
			       Initdata.NFontWidth,
			       Initdata.NFontHeight,
			       Initdata.SFontWidth,
			       Initdata.SFontHeight);
    if (hWndText == 0)
	PostMessage(MWnd.hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);

#ifdef WIN600
    if (!MakeAndShowGraphWindow(hInstance,
				hPrevInstance,
				MWnd.hWnd,
				&Grt,
				ColorTable[Initdata.TextColor],
				ColorTable[Initdata.BGColor],
				0,0,
				1024,800
				))
	PostMessage(MWnd.hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
#endif

    hWndNext = SetClipboardViewer(MWnd.hWnd);

    curproto.type = 'A';
    if (Initdata.EWidth == 7)
	curproto.mask = 0x7f;
    else
	curproto.mask = 0xff;

    hWndActive = hWndText;
    SetAlphaParams(Initdata.AlphaEmulation);

    LocalEcho = Initdata.LocalEcho;
    if (Initdata.LocalMode) {
	LineState = LOCAL_ON;
	DoMessage = DoGetMessage;
    } else {
	LineState = LINE_ON + LocalEcho;
	DoMessage = DoPeekMessage;
    }

    if (Initdata.ReverseVideo) {
	InvertScreen(TRUE);
	MWnd.Reverse = TRUE;
    }

    cid = INT_MIN;
    if (!OpenAndSetCommPort(hInstance))
	PostMessage(MWnd.hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);
    else {
        MWnd.Cursor = Initdata.Cursor ? TRUE : FALSE;
        MWnd.CursorType = Initdata.CursorType ? TRUE : FALSE;
        MWnd.BreakEnabled = Initdata.BreakEnabled ? TRUE : FALSE;
        MWnd.CurKeyMode = Initdata.CursorKeys ? TRUE : FALSE;
        MWnd.DeleteKey = Initdata.DeleteKey ? TRUE : FALSE;
        MWnd.AutoAnswer = Initdata.AutoAnswer ? TRUE : FALSE;
        MWnd.LFCR = Initdata.LFCR ? TRUE : FALSE;
        MWnd.ApplMode = Initdata.AltKeypad ? TRUE : FALSE;
        MWnd.WarningBell = Initdata.WarningBell ? TRUE : FALSE;
	MWnd.Wrap = Initdata.Wrap;

	MWnd.ControlRep = Initdata.ControlRep;
	if (MWnd.ControlRep) {
	    if (curproto.atype == 52)
		vt52SetState(-1);
	    else
		vt100SetState(-1);
            SendMessage(hWndActive, SMT_SETATTRIBUTE, SM_AUTOWRAP, (LONG)TRUE);
	}

        SendMessage(hWndText,SMT_SETATTRIBUTE,SM_MARGINBELL,
						(LONG)Initdata.MarginBell);
        SendMessage(hWndText,SMT_SETATTRIBUTE,SM_SMOOTHSCROLL,
						(LONG)Initdata.SmoothScroll);
        SendMessage(hWndText,SMT_SETATTRIBUTE,SM_SCROLLUNITS,
						(LONG)Initdata.ScrollUnits);

	/* finally, display the window and show success */
	ShowWindow(MWnd.hWnd, cmdShow);
	UpdateWindow(MWnd.hWnd);
    }
    return TRUE;
}

void FAR MainWndCreate(HWND hWnd, LONG lParam)
{
    MWnd.TextColor = Initdata.TextColor;
    MWnd.BGColor = Initdata.BGColor;
    MWnd.hBrush = CreateSolidBrush(ColorTable[Initdata.BGColor]);
}

static BOOL NEAR SearchKey(char *str, char *key, int len)
{
    int i;
    char *startptr;
    startptr = str;

    for (i = 0; i < len; i++) {
	if (*str++)
	    ;
	else {
	    if (strcmp(key, startptr) == 0)
		return(TRUE);
	    startptr = str;
	}
    }
    return (FALSE);
}

static BOOL NEAR ReadInitialData(HANDLE hInstance)
{

    char szKeyStr[80];
    char szDefStr[80];
    HANDLE hInitKeyStr;
    register int i, val;
    HDC hIC;
    int cwidth, cheight;
    HFONT hOldFont;
    TEXTMETRIC tm;

    GetModuleFileName(hInstance, szHelpName, sizeof(szHelpName));
    lstrcpy(szIniName, szHelpName);
    lstrcpy(szHelpName + strlen(szHelpName) - 3, "HLP");
    lstrcpy(szIniName + strlen(szIniName) - 3, "INI");

    hIC = CreateIC("DISPLAY", NULL, NULL, NULL);    
    MWnd.PelSize = GetDeviceCaps(hIC,BITSPIXEL) * GetDeviceCaps(hIC,PLANES);
    hOldFont = SelectObject(hIC, GetStockObject(SYSTEM_FIXED_FONT));
    GetTextMetrics(hIC, &tm);
    cwidth = tm.tmAveCharWidth;
    cheight = tm.tmHeight + tm.tmExternalLeading;
    SelectObject(hIC, hOldFont);
    DeleteDC(hIC);

    hInitKeyStr = LocalAlloc(LPTR, INITKEYSIZE);
    if ((szInitKeyStr = LocalLock(hInitKeyStr)) == NULL)
	return FALSE;

    Initlen = GetPrivateProfileString(szAppName, NULL, "", szInitKeyStr,
				      INITKEYSIZE, szIniName);

  /* default ports */
    for (i = 0; i < MAXCOMPORTS; i++) {
        LoadString(hInstance,IDS_FIRSTPORT+i,(LPSTR)szKeyStr,sizeof(szKeyStr));
        LoadString(hInstance,IDS_COM1 + i, (LPSTR)szDefStr, sizeof(szDefStr));
        if (!SearchKey(szInitKeyStr, szKeyStr, Initlen)) {
	    WinIniModified = TRUE;
	    WritePrivateProfileString(szAppName,szKeyStr,szDefStr, szIniName);
	}
        GetPrivateProfileString(szAppName,szKeyStr,szDefStr,
				Initdata.portname[i],
				sizeof(Initdata.portname[i]), szIniName);
    }

  /* comm parameters */
    Initdata.BaudRate = (WORD)GetInitData(IDS_BAUD, DEFBAUD);
    for (i = 0; i < BAUDRATETABLESIZE; i++)
	if (BaudRateTable[i] == Initdata.BaudRate)
	    break;
    if (i == BAUDRATETABLESIZE)
	Initdata.BaudRate = DEFBAUD;
	    
    Initdata.Parity = (BYTE)GetInitData(IDS_PARITY, DEFPARITY);
    Initdata.ByteSize = (BYTE)GetInitData(IDS_BYTESIZE, DEFBYTESIZE);
    for (i = 0; i < PARITYTABLESIZE; i++)
	if ((ParityTable[i].Parity == Initdata.Parity) &&
		(ParityTable[i].ByteSize == Initdata.ByteSize))
	    break;
    if (i == PARITYTABLESIZE) {
	Initdata.ByteSize = DEFBYTESIZE;
	Initdata.Parity = DEFPARITY;
    }

    Initdata.StopBits = (BYTE)GetInitData(IDS_STOPBITS, DEFSTOP);

    Initdata.fParity = (BYTE)GetInitData(IDS_PARCHECK, DEFPECHECK);

    Initdata.XonXoff = (BYTE)GetInitData(IDS_XONXOFF, DEFXONXOFF);

    Initdata.XoffLim = (WORD)GetInitData(IDS_XOFFLIM, DEFXOFFLIM);
    for (i = 0; i < XOFFLIMSIZE; i++)
	if (XoffSizeTable[i] == Initdata.XoffLim)
	    break;
    if (i == XOFFLIMSIZE)
	Initdata.XoffLim = DEFXOFFLIM;

    Initdata.LocalEcho = GetInitData(IDS_LOCALECHO, DEFLOCALECHO) ? 1 : 0;

    Initdata.Wrap = GetInitData(IDS_WRAP, DEFWRAP) ? TRUE : FALSE;

    Initdata.LFCR = GetInitData(IDS_AUTOLFCR, DEFLFCR) ? TRUE : FALSE;

    Initdata.MarginBell = GetInitData(IDS_MARGINBELL, DEFMBELL) ? TRUE : FALSE;

    Initdata.ControlRep = 
	GetInitData(IDS_CONTROLREP, DEFCONTROLREP) ? TRUE : FALSE;

    Initdata.Cursor = GetInitData(IDS_CURSOR, DEFCURSOR) ? TRUE : FALSE;

    Initdata.CursorType = 
	GetInitData(IDS_CURSORTYPE, DEFCURSORTYPE) ? TRUE : FALSE;

    val = COLORTABLESIZE - 1;
    Initdata.BGColor = GetInitData(IDS_BGCOLOR, DEFBGCOLOR) & val;
    Initdata.TextColor = GetInitData(IDS_TEXTCOLOR, DEFTEXTCOLOR) & val;
    if (MWnd.PelSize == 1) {
	if (Initdata.BGColor) {
	    Initdata.BGColor = val;
	    Initdata.TextColor = 0;
	} else {
	    Initdata.TextColor = val;
	    Initdata.BGColor = 0;
	}
    } else {
        if (Initdata.TextColor == Initdata.BGColor)
	    Initdata.TextColor = (~Initdata.BGColor) & val;
    }

    Initdata.WarningBell = 
	GetInitData(IDS_WARNINGBELL, DEFWBELL) ? TRUE : FALSE;

    val = GetInitData(IDS_TERMTYPE, DEFTERMTYPE);
    Initdata.AlphaEmulation =
			((val == 52) || (val == 100)) ? val : DEFTERMTYPE;

    val = GetInitData(IDS_EMULATIONWIDTH, DEFEWIDTH);
    Initdata.EWidth = ((val == 7) || (val == 8)) ? val : DEFEWIDTH;
    if (Initdata.AlphaEmulation == 52)
	Initdata.EWidth = 7;
    
    Initdata.ReverseVideo = 
	GetInitData(IDS_REVERSEVIDEO, DEFVIDEO) ? TRUE : FALSE;

    Initdata.SmoothScroll = 
	GetInitData(IDS_SMOOTHSCROLL, DEFSCROLL) ? TRUE : FALSE;

    val = GetInitData(IDS_SCROLLUNITS, DEFSCROLLUNITS);
    Initdata.ScrollUnits = 
	((val >= 0) && (val <= MAXSCROLLUNITS)) ? val : DEFSCROLLUNITS;

    Initdata.LocalMode = 
	GetInitData(IDS_LOCALMODE, DEFLOCALMODE) ? TRUE : FALSE;

    Initdata.AltKeypad = 
	GetInitData(IDS_ALTKEYPAD, DEFALTKEYPAD) ? TRUE : FALSE;

    Initdata.CursorKeys = 
	GetInitData(IDS_CURSORKEYS, DEFCURSORKEYS) ? TRUE : FALSE;

    Initdata.BreakEnabled = 
	GetInitData(IDS_BREAKKEYENABLED, DEFBREAKENABLED) ? TRUE : FALSE;

    Initdata.DeleteKey = 
	GetInitData(IDS_DELETEKEY, DEFDELETEKEY) ? TRUE : FALSE;

    Initdata.AutoAnswer = 
	GetInitData(IDS_AUTOANSWER, DEFAUTOANSWER) ? TRUE : FALSE;

    val = GetInitData(IDS_ROWS, DEFROWS);
    Initdata.TermRows = ((val >= 2) && (val <= MAXROWS)) ? val : DEFROWS;

    val = GetInitData(IDS_COLS, DEFCOLS);
    Initdata.TermCols = val > 80 ? 132 : 80;

    LoadString(hInstance, IDS_FONTFACE, (LPSTR)szKeyStr,sizeof(szKeyStr));
    LoadString(hInstance, IDS_DEFAULTFONT, szDefStr, sizeof(szDefStr));
    if (!SearchKey(szInitKeyStr, szKeyStr, Initlen)) {
	WinIniModified = TRUE;
	WritePrivateProfileString(szAppName, szKeyStr, szDefStr, szIniName);
    }
    GetPrivateProfileString(szAppName, szKeyStr, szDefStr, Initdata.Fontface,
			    sizeof(Initdata.Fontface), szIniName);

    Initdata.NFontWidth = GetInitData(IDS_NORMALWIDTH, cwidth);
    if (Initdata.NFontWidth == 0)
	Initdata.NFontWidth = cwidth;

    Initdata.NFontHeight = GetInitData(IDS_NORMALHEIGHT, cheight);
    if (Initdata.NFontHeight == 0)
	Initdata.NFontHeight = cheight;

    Initdata.SFontWidth = GetInitData(IDS_SMALLWIDTH, cwidth);
    if (Initdata.SFontWidth == 0)
	Initdata.SFontWidth = cwidth;

    Initdata.SFontHeight = GetInitData(IDS_SMALLHEIGHT, cheight);
    if (Initdata.SFontHeight == 0)
	Initdata.SFontHeight = cheight;

    LocalUnlock(hInitKeyStr);
    LocalFree(hInitKeyStr);

    if (WinIniModified) 
	BroadcastWinIniChange();

    return TRUE;
}

static int NEAR GetInitData(int id, int defval)
{

    char szKeyStr[80];
    char buf[40];

    LoadString(hInst, id, szKeyStr,sizeof(szKeyStr));
    if (!SearchKey(szInitKeyStr, szKeyStr, Initlen)) {
	WinIniModified = TRUE;
	WritePrivateProfileString(szAppName,szKeyStr,
				  itoa(defval, buf, 10), szIniName);
    }
    return GetPrivateProfileInt(szAppName, szKeyStr, defval, szIniName);
}

static BOOL NEAR OpenAndSetCommPort(HANDLE hInstance)
{
    int i, reply;
    char szMessage[80];
    char szBigMsg[160];

    for (i = 0; i < MAXCOMPORTS; i++) {
        if ((cid = OpenComm(Initdata.portname[i], DEFRXQUE, DEFTXQUE)) < 0) {
	    LoadString(hInstance,cid,szBigMsg,sizeof(szMessage));
	    LoadString(hInstance,IDS_TRYANOTHER,szMessage,sizeof(szMessage));
	    strcat(szBigMsg, szMessage);
            reply = MessageBox(MWnd.hWnd,(LPSTR)szBigMsg,
		   (LPSTR)Initdata.portname[i], MB_ICONQUESTION | MB_YESNO);
	    if (reply == IDNO)
		return FALSE;
	}
	else
	    break;
    }
    if (i == MAXCOMPORTS) {
//	LoadString(hInstance, IDS_NOCOM, szMessage, sizeof(szMessage));
        ShowMessage(MWnd.hWnd, IDS_NOCOM, MB_ICONEXCLAMATION | MB_OK);
	return FALSE;
    }
    LoadString(hInstance, IDS_TITLE, szMessage, sizeof(szMessage));
    strcat(szMessage, Initdata.portname[i]);
    SetWindowText(MWnd.hWnd, szMessage);

    if ((reply = GetCommState(cid, (DCB FAR *)&CommData)) >= 0) {
	CommData.BaudRate = Initdata.BaudRate;
	CommData.ByteSize = Initdata.ByteSize;
	CommData.Parity = Initdata.Parity;
	CommData.StopBits =
		(BYTE)(Initdata.StopBits == 2 ? TWOSTOPBITS : ONESTOPBIT);
	CommData.fParity = (BYTE)(Initdata.fParity ? 1 : 0);
        CommData.fPeChar = CommData.fParity;
        CommData.PeChar = DEFPECHAR;

        CommData.fOutX = CommData.fInX =
				(BYTE)(Initdata.XonXoff ? TRUE : FALSE);
        CommData.XonChar = DEFXONCHAR;
        CommData.XoffChar = DEFXOFFCHAR;

        CommData.XonLim = DEFXONLIM;
        CommData.XoffLim = DEFRXQUE - Initdata.XoffLim;
	CommData.fBinary = TRUE;
	CommData.fDtrDisable = FALSE;
	CommData.fNull = TRUE;
	if ((reply = SetCommState((DCB FAR *)&CommData)) >= 0)
	    return TRUE;
    }
    ShowMessage(MWnd.hWnd, reply, MB_OK | MB_ICONEXCLAMATION);
    CloseCommPort(MWnd.hWnd, &cid);
    return FALSE;
}

static void NEAR GetCurrentInstanceData(HANDLE hInstance)
{
    LoadString(hInstance, IDS_ICON, (LPSTR)szIcon, sizeof(szIcon));
}

/*
   If this not the first instance, we can retrieve static data from a
   previous invocation of the program
*/
static void NEAR GetPrevInstanceData(HANDLE hPrevInstance)
{

    GetInstanceData(hPrevInstance, (PSTR)szAppName, sizeof(szAppName));
    GetInstanceData(hPrevInstance, (PSTR)szIcon, sizeof(szIcon));
    GetInstanceData(hPrevInstance, (PSTR)&hAccel, sizeof(hAccel));
}

/* Every window must belong to a class. We register ours here */
static BOOL NEAR RegisterWindowClass(HANDLE hInstance)
{

    PWNDCLASS pWndClass;
    HANDLE hTemp;

  /* Load the name string from resources */
    LoadString(hInstance, IDS_APPNAME,(LPSTR)szAppName,sizeof(szAppName));

  /* allocate space for the WNDCLASS structure and lock it down */
    hTemp = LocalAlloc(LPTR,sizeof(WNDCLASS));
    pWndClass = (PWNDCLASS)LocalLock(hTemp);

  /* fill the structure */	
    pWndClass->hCursor	= LoadCursor(NULL, IDC_ARROW);  /* standard cursor */
    pWndClass->hIcon	= NULL;				/* no icon */
    pWndClass->lpszMenuName = (LPSTR)szAppName;
    pWndClass->lpszClassName = (LPSTR)szAppName;	/* our class name */
    pWndClass->hbrBackground = (HBRUSH)NULL;
    pWndClass->hInstance = hInstance;		/* instance handle */
    pWndClass->style = CS_VREDRAW | CS_HREDRAW; /* standard redraw values */
    pWndClass->lpfnWndProc = MainWndProc;  /* pointer to our window proc */
    pWndClass->cbClsExtra = 0;
    pWndClass->cbWndExtra = sizeof(pMWND);

  /* register the class.  if fail, abort */
    if (!RegisterClass((LPWNDCLASS)pWndClass))
	return FALSE;

  /* free the memory used */
    LocalUnlock(hTemp);
    LocalFree(hTemp);

  /* show success */
    return TRUE;
}

/*
 Create the window, making sure that its position and size are suitable
 for the display.
*/
static BOOL NEAR MakeAndShowMainWnd(HANDLE hInstance, HANDLE hPrevInstance, 
				    int cmdShow)
{

    char szTitle[50];
    DWORD style = WS_HSCROLL | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
    int x, y, cx, cy;
    int cwidth, cheight;

    LoadString(hInstance, IDS_TITLE,(LPSTR)szTitle,sizeof(szTitle));

    if (hPrevInstance)
	x = CW_USEDEFAULT;
    else
        x = 0;
    y = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);

    if (Initdata.TermCols == MAXCOLUMNS) {
	cwidth = Initdata.SFontWidth;
	cheight = Initdata.SFontHeight;
    }
    else {
	cwidth = Initdata.NFontWidth;
	cheight = Initdata.NFontHeight;
    }
    cx = Initdata.TermCols * cwidth + 2 * GetSystemMetrics(SM_CXFRAME);
    cx = min(GetSystemMetrics(SM_CXSCREEN), cx);
    cy = Initdata.TermRows * cheight + 2 * GetSystemMetrics(SM_CYFRAME) +
	 GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) +
	 GetSystemMetrics(SM_CYHSCROLL);
    cy = min(GetSystemMetrics(SM_CYSCREEN) - y, cy);
    
    if (MWnd.hWnd = CreateWindow((LPSTR)szAppName,
			     (LPSTR)szTitle,
			     style,
			     x, y, cx, cy,
			     (HWND)NULL,
			     (HMENU)NULL,
			     (HANDLE)hInstance,
			     (LPSTR)NULL))
	return TRUE;

    return FALSE;
}

