#include <types.h>
#include <stdio.h>
#include <quickdraw.h>
#include <qdaux.h>
#include <window.h>
#include <memory.h>
#define dtItemListLength    12
#include <event.h>
#include <dialog.h>
#include <control.h>
#include <lineedit.h>
#include <string.h>
#include <prodos.h>
#include "sp.h"
#include "bl.h"
#include "spdef.h"
#include "driver.h"

#define max(x, y)       ((x) > (y) ? (x) : (y))

#define IgnoreI 3
#define SuggestI 2
#define ReplaceI 1
#define DoneI 4
#define AddI 11
#define disableButt 255
#define enableButt 0

extern unsigned _SPID;

static pascal unsigned myfilter();
static pascal void drawWord();
static pascal void selProc();

static char ignoreStr[] = "\pIgnore";
static ItemTemplate ignoreButt =
{ IgnoreI, {68, 24, 80, 134}, buttonItem, ignoreStr, 0, 0, 0L };

static char suggestStr[] = "\pSuggest";
static ItemTemplate suggestButt =
{ SuggestI, {68, 154, 80, 264}, buttonItem, suggestStr, 0, 0, 0L };

static char replaceStr[] = "\pReplace";
static ItemTemplate replaceButt =
{ ReplaceI, {68, 284, 80, 394}, buttonItem, replaceStr, 0, 0, 0L };

static char cancelStr[] = "\pDone";
static ItemTemplate cancelButt =
{ DoneI, {68, 414, 80, 524}, buttonItem, cancelStr, 0, 0, 0L };

static char addStr[] = "\pAdd to Dictionary";
static ItemTemplate addButt =
{ AddI, {50, 284, 62, 524}, buttonItem, addStr, 0, 0, 0L };

static char wordStr[40];
static ItemTemplate wordLine =
{ 5, {8, 289, 18, 523}, statText + itemDisable, wordStr, 0, 0, 0L };

char *sperrs[] =
{ "", "Spelling", "Punctuation", "", "Capitalization", "", "", "",
    "Hyphenation"};

static char errStr[40];
static ItemTemplate errLine =
{ 6, {22, 289, 32, 523}, statText + itemDisable, errStr, 0, 0, 0L };

static char replStr[] = "\pReplace with:";
static ItemTemplate replLine =
{ 7, {36, 289, 46, 389}, statText + itemDisable, replStr, 0, 0, 0L };

static ItemTemplate replText =
{ 8, {34, 395, 47, 524}, editLine + itemDisable, NULL, 32, 0, 0L };

static ListRec theList = {
	0L,					
	{7, 22, 59, 238},	/* Box Rect */
	{7, 236, 59, 262},	/* ScrollBar Rect */
	0,
	10,					/* Height of 10 (for Shaston) */
	1,					/* Dbl-Click -> Replace button */
	drawWord,			/* Draw Proc */
	selProc,			/* Select Proc */
	0L					/* No changed proc */
	/* reserved array is zeroed too. */
};

static DialogTemplate myDlg =
{
    {50, 44, 125, 594}, 1, 0L, {&ignoreButt, &suggestButt, &replaceButt,
      &cancelButt, &wordLine, &errLine, &replLine, &replText, &addButt, NULL}
};

char *SPDidnt = "\pCouldn't add word.\rUser dictionary may be corrupt.";
static GrafPortPtr dlgPort;
static char **wlist;
static char **ignorelist;
static int isopen = 0;
extern char *WcurDoc;
static unsigned buttonState=0;

pascal int SPDlg(top, word, err, cor, upd, refnum)
unsigned top;           /* Top of dlg in global coords */
char *word;             /* Misspelled word */
int err;                /* Error spcheck returned */
char *cor;              /* Where to put replacement */
void (*upd)();          /* Routine to update what is exposed when dialog
                           moves; NULL if none. */
int refnum;             /* User dict to add to */
{
unsigned x, retval, done = 0;
Point tmpPt;
GrafPortPtr tmpPort;

    setbank;
    strcpy(wordStr, "Word: ");
    p2cstr(word);
    strcat(wordStr, word);
    c2pstr(word);
    c2pstr(wordStr);

    strcpy(errStr, "Error: ");
    strcat(errStr, sperrs[err]);
    c2pstr(errStr);

    if (err > 1)
        wlist = SPSuggest(NULL, 1);

    if (!isopen)
    {
        myDlg.dtBoundsRect.v2 = (myDlg.dtBoundsRect.v1 = top) + 85;
        dlgPort = GetNewModalDialog(&myDlg);
		theList.Dialog = dlgPort;
		theList.ListSize = (err > 1 ? 1 : 0);
		D_BLMAKELIST(&theList);
        isopen = 1;
    }
    else 
    {
		Rect tmpRect;
	
		if (ignorelist) {
			char *list;
			
			HLock(ignorelist);
			
			for (list = *ignorelist;*list;) {
				unsigned size;
				
				size = *list;
				/*  same length?     equivalent for that length? */
				if (size == *word && !strncmp(list+1,word+1,size)) {
					/* then we ignore it, because it's the same word */
					HUnlock(ignorelist);
					retval = 0;
					done = 1;
					goto Exit;
				} /* else */
				
				list += size+1;
			}
		}
		HUnlock(ignorelist);
		
		theList.Dialog = dlgPort;
		theList.ListSize = (err > 1 ? 1 : 0);
        D_BLSETPARMS(&theList, theList.ListSize, 0);

		tmpPort = GetPort();
		SetPort(dlgPort);
		tmpPt.h = tmpPt.v = 0;
		LocalToGlobal(&tmpPt);
		SetPort(tmpPort);
		
		/* Make the update pretty. */
		if (top != tmpPt.v) { 
			MoveWindow(40, top, dlgPort);
			DrawDialog(dlgPort);
		} else {
			SetIText(dlgPort, 6, errStr);
			SetIText(dlgPort, 5, wordStr);
		}

        SetIText(dlgPort, 8, "");
        if (upd)
            (*upd)();
    }
	
	
    if (err > 1)
    {
        SetIText(dlgPort, 8, wlist[0]);
        SelIText(dlgPort, 8, 0, 32767);
		HiliteControl(enableButt, GetControlDItem(dlgPort,ReplaceI));
		HiliteControl(disableButt, GetControlDItem(dlgPort, SuggestI));
		buttonState = 0;
    }
	else {
	    HiliteControl(disableButt, GetControlDItem(dlgPort, ReplaceI));
		HiliteControl(enableButt, GetControlDItem(dlgPort, SuggestI));
		buttonState = 1;
	}

    while (!done) {
		char s[35];
		
		D_SETCURSOR(arrowCursor);
        switch (D_BLMODALDIALOG(myfilter))
        {
            case IgnoreI:         /* Ignore */
				/* add to ignore list */
				{
					char *list;
					unsigned long size;
					unsigned length = *word;
					
					if (!ignorelist) {
						ignorelist = NewHandle(4L,_SPID,0,0L);
						if (*toolErr[0])
							goto Sorry;
						size = 1L;
					} else
						size = GetHandleSize(ignorelist);
						
					SetHandleSize(size + length + 1,ignorelist);
					
					if (!*toolErr[0]) {
					
						HLock(ignorelist);
						list = *ignorelist + size-1;
						strncpy(list,word,length+1);
						list[length+1] = '\0';		/* terminate the list */
						HUnlock(ignorelist);
					}
				}

Sorry:				
                retval = 0;
                done = 1;
                break;
            case SuggestI:         /* Suggest */
                D_BEACHBALL();
                wlist = SPSuggest(NULL, 10);
                D_SETCURSOR(arrowCursor);
                for (x = 0; wlist[x]; ++x)
                    ;
                D_BLSETPARMS(&theList, x, 0);
                HiliteControl(disableButt, GetControlDItem(dlgPort, SuggestI));
				buttonState = 0;
                HiliteControl(disableButt, GetControlDItem(dlgPort, ReplaceI));
                SetIText(dlgPort, 8, "");
                break;
            case ReplaceI:         /* Replace */
                GetIText(dlgPort, 8, cor);
                retval = done = 1;
                break;
            case DoneI:         /* Cancel */
                retval = done = 2;
                break;
            case AddI:        /* Add to dict */
                retval = done = 3;
                SPAddWord(refnum, word);
				if (_SPErrNum[0])
					D_ALERTBOX(okBox,SPDidnt);
                break;
        }
	}
Exit:
    restorebank;
    return(retval);
}

pascal void SPCloseDlg()
{
    setbank;
    if (isopen)
    {
		D_BLFORGETLISTS();
        CloseDialog(dlgPort);
		if (ignorelist) {
			DisposeHandle(ignorelist);
			ignorelist = 0L;
		}
        isopen = 0;
    }
    restorebank;
}

static pascal void drawWord(foo, wnum)
char *foo;
int wnum;
{
    setbank;
    Move(3, 8);
    DrawString(wlist[wnum]);
    restorebank;
}

static pascal void selProc(foo, wnum)
char *foo;
int wnum;
{
    if (wnum >= 0)
    {
        setbank;
        SetIText(dlgPort, 8, wlist[wnum]);
        SelIText(dlgPort, 8, 0, 32767);
        HiliteControl(0, GetControlDItem(dlgPort, 1));
        restorebank;
    }
}

static pascal unsigned myfilter(dlg, evt, item)
GrafPortPtr dlg;
EventRecordPtr evt;
int *item;
{
	extern pascal void W_UPDATEDOC();
	extern char *WcurDoc;

	char s[35];
	CtlRecHndl h;
	
	setbank;
	
	if (evt->what == activateEvt) {
		BeginUpdate(WcurDoc);
		W_UPDATEDOC(WcurDoc);
		EndUpdate(WcurDoc);
	}
	
	h = GetControlDItem(dlg, 1);
	GetIText(dlg, 8, s);
	if (s[0]) {
		HiliteControl(0, h);
	} else {
		HiliteControl(255, h);
		if ((evt->what == keyDownEvt || evt->what == autoKeyEvt)
			&& evt->message == 0xD) {
			*item = 0;
			restorebank;
			return 1;
		}	
	}
	if ((evt->what == keyDownEvt || evt->what == autoKeyEvt)) {
		char c = (char) evt->message;
		
		if (c == 0x1b) {
doCancel:
			*item = DoneI;
			D_BLINKBUTTON(dlg,DoneI);
			restorebank;
			return 1;
		}
		
		if (evt->modifiers & appleKey) {
			unsigned i;
			
			switch(c) {
			
			case '.':
				goto doCancel;
			
			case 's':
			case 'S':
				if (buttonState)
					i = SuggestI;
				else
					goto noButton;
				break;
				
			case 'a':
			case 'A':
				i = AddI;
				break;
			
			case 'i':
			case 'I':
				i = IgnoreI;
				break;
			
			default:
noButton:			
				restorebank;
				return 0;
			}
			
			*item = i;
			D_BLINKBUTTON(dlg,i);
			restorebank;
			return 1;

		}
	}

	restorebank;
    return (0);
}
