#include <types.h>
#include <stdio.h>
#include <quickdraw.h>
#include <qdaux.h>
#include <window.h>
#include <memory.h>
#define dtItemListLength    9
#include <event.h>
#include <dialog.h>
#include <control.h>
#include <lineedit.h>
#include <string.h>
#include <misctool.h>
#include <gsos.h>
#include "sp.h"
#include "spdef.h"
#include "sc.h"
#include "scparam.h"
#include "clam.h"
#include "environ.h"
#include "bl.h"
#include "driver.h"

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

extern CLAM *_SPudtable[];
extern char **_SPudpn[];

static int strhpcmp();
extern CLAM *clamalloc();

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

static wListSize;
static char ****wList;      /* Handle to an array of handles to strings */
static int doingword, doingsel;

static char texStr[] = "\pEdit User Dictionary";
static ItemTemplate texLine =
{ 8, {5, 25, 17, 200}, statText + itemDisable, texStr, 0, 0, 0L };

static char addStr[] = "\pAdd Word";
static ItemTemplate addButt =
{ 1, {42, 325, 54, 445}, buttonItem, addStr, 0, 0, 0L };

static char removeStr[] = "\pRemove Word";
static ItemTemplate removeButt =
{ 4, {58, 325, 70, 445}, buttonItem, removeStr, 0, 0, 0L };

static char okStr[] = "\pOK";
static ItemTemplate okButt =
{ 3, {74, 325, 86, 445}, buttonItem, okStr, 0, 0, 0L };

static char cancelStr[] = "\pCancel";
static ItemTemplate cancelButt =
{ 2, {90, 325, 102, 445}, buttonItem, cancelStr, 0, 0, 0L };

static ItemTemplate wordLine =
{ 5, {20, 290, 33, 480}, editLine + itemDisable, NULL, MAXWORD, 0, 0L };

static ListRec theList = {
	0L,					
	{20, 25, 102, 241},	/* Box Rect */
	{20, 239, 102, 265},/* ScrollBar Rect */
	0,
	10,					/* Height of 10 (for Shaston) */
	0,					
	drawWord,			/* Draw Proc */
	selProc,			/* Select Proc */
	0L					/* No changed proc */
	/* reserved array is zeroed too. */
};

static DialogTemplate myDlg =
{
    {35, 60, 145, 575}, 1, 0L, { &addButt, &removeButt, &okButt, &cancelButt,
      &wordLine, &texLine, NULL}
};

static GrafPortPtr dlgPort;


char *fullmsg = "\pChanges to the dictionary could not be saved.";
	

/* Interactively edit a User Dictionary.  The UDict must have been opened
   with SPOpenUDict. */

pascal void _SPEditUDict(refnum,addpath)
unsigned refnum;                    /* User Dict reference number */
char *addpath;						/* Text file to add to udict */
{
char wBuf[2 * MAXWORD];
unsigned flags;
int done, cancelled, x, init;
char **temp;
int thefile;
CLAM *cp;
char *thePath;
char *pos;
int wSel;
unsigned Umodflag;

    if (!_SPActive[0])
        SPErr2(SPINACTIVE, 0);
    _SPErrNum[0] = 0;

    _SPTHID[0] = _SPID;

    wListSize = doingword = doingsel = 0;

    --refnum;
    if (refnum < 0 || refnum >= SPMAXUDICT)
        SPErr2(SPBADREF, 0);
    if (!_SPudtable[refnum])
        SPErr2(SPBADREF, 0);

	Umodflag = 0;
	
    wList = (char ****) NewHandle(0L, _SPID, 0x0010, 0L);

    /* Read in udict */

    Sccurlist = (char *) _SPudtable[refnum];
    init = TRUE;
    while (clamnext(wBuf, &flags, init, _SPudtable[refnum]) != CL_EOF)
    {
		char **hdl;
		unsigned i;
		
        init = FALSE;
        SetHandleSize(GetHandleSize(wList) + 4, wList);

		hdl = (char **) NewHandle(80L,_SPID,0x8010,0L);
		undoflags(wBuf,flags,*hdl);
		i = strlen(*hdl) + 1;
		HUnlock(hdl);
		SetHandleSize((unsigned long) i,hdl);
		(*wList)[wListSize++] = hdl;
    }

/*	„ ASCII DICT
	if (addpath) {
		char **hdl;
		unsigned i;
		/* open the ascii file *
		for (;;) {
			/* read a word (up to a carriage return,space,newline,tab [max 32 char]) *
			break;
		
			/* add it to the list *
			i = strlen(*hdl) + 1;
			HUnlock(hdl);
			SetHandleSize((unsigned long) i,hdl);
			(*wList)[wListSize++] = hdl;
		}
		Umodflag = 1;
	}
*/

    HLock(wList);

	clamclose(_SPudtable[refnum]);		/* Close User.Dictionary */	
	
    /* Sort it quickly.  We can use insertion for addword, but not here.
       UDicts could be large. */
    qsort(*wList, wListSize, 4, strhpcmp);


    dlgPort = GetNewModalDialog(&myDlg);
    HiliteControl(255, GetControlDItem(dlgPort, 1));
    HiliteControl(255, GetControlDItem(dlgPort, 4));
    done = 0;
	theList.Dialog = dlgPort;
	theList.ListSize = wListSize;
	D_BLMAKELIST(&theList);
	D_SETCURSOR(arrowCursor);
	
    while (1)
    {
        switch(D_BLMODALDIALOG(udfilter))
        {
            case 1:                 /* Add word */
                HiliteControl(255, GetControlDItem(dlgPort, 1));
                doingword = 0;
                GetIText(dlgPort, 5, wBuf);
                HUnlock(wList);
                SetHandleSize(GetHandleSize(wList) + 4, wList);
                HLock(wList);
                (*wList)[wListSize] = (char **) NewHandle((long) wBuf[0] + 1, _SPID, 0x0010, 0L);
                p2cstr(wBuf);
                strcpy(*(*wList)[wListSize], wBuf);
                SetIText(dlgPort, 5, "");
                x = wListSize++;
                while (x && strcmp(*(*wList)[x - 1], *(*wList)[x]) > 0)
                {
                    temp = (*wList)[x - 1];
                    (*wList)[x - 1] = (*wList)[x];
                    (*wList)[x--] = temp;
                }
                D_BLSETPARMS(&theList, wListSize, max(x - 3, 0));
				Umodflag = 1;
                break;
            case 2:                 /* Cancel */
                done = cancelled = 1;
                break;
            case 3:                 /* OK */
                D_SETCURSOR(watchCursor);
                done = 1;
                cancelled = 0;
                break;
            case 4:                 /* Remove word */
                wSel = D_BLGETSEL(&theList);
                D_BLSELECT(&theList, -1);
                DisposeHandle((*wList)[wSel]);
                for (x = wSel; x + 1 < wListSize; ++x)
                    (*wList)[x] = (*wList)[x + 1];
					
                HUnlock(wList);
                SetHandleSize(GetHandleSize(wList) - 4, wList);
                HLock(wList);
                --wListSize;
                D_BLSETPARMS(&theList, wListSize, -1);
				Umodflag = 1;
                break;
        }
        if (done)
            break;
    }

	cancelled |= !Umodflag;
	thePath = *_SPudpn[refnum];

    if (!cancelled)
    {
		if (pos = strrchr(thePath,':'))
			pos++;
		else
			pos = thePath;
        strcpy(pos, "bobo.temp");

        if (!(cp = clamalloc(thePath, CL_INIT + CL_REORG, 0xD0, 0x8001L))) {
            /* signal error */
			D_ALERTBOX(1,fullmsg);
			cancelled = 1;
			strcpy(pos,"User.Dictionary");/* This restores the _SPudpn entry */
        } else
			pos[0] = '\0';
    }

    for (x = 0; x < wListSize; ++x)
    {
        if (!cancelled)
        {
            flags = doflags(*(*wList)[x], wBuf, MAXWORD);
            if (clamadd(wBuf, flags, cp) == ERROR) {
				D_ALERTBOX(1,fullmsg);
				cancelled = 1;
				strcpy(pos,"User.Dictionary");/* This restores the _SPudpn entry */
			}
        }
        DisposeHandle((*wList)[x]);
    }

    if (!cancelled)
    {
		char *path1, *path2;
		extern char *c2pstr1();
		ChangePathRec crec;
		
		unsigned clamfree();


		strcpy(pos,"bobo.temp");
		path1 = c2pstr1(thePath);
		strcpy(pos,"User.Dictionary");/* This restores the _SPudpn entry */

        if (clamfree(cp) == ERROR) {
			D_ALERTBOX(1,fullmsg);
			/* cancelled = 1; */
			D_DESTROY2(path1);
		} else {
									/* bobo.temp now exists on disk */
		
			path2 = c2pstr1(thePath);
			
			D_DESTROY2(path2);				/* Eliminate old udict */
			
			crec.pCount = 2;
			crec.pathname = (GSString255Ptr) path1;
			crec.newPathname = (GSString255Ptr) path2;
			ChangePathGS(&crec);			/* Move bobo.temp to udict */
			
			D_DISPOSEPTR(path2);
 		}
		D_DISPOSEPTR(path1);
		
	}
	
	/* ReŠopen the udict, be it old or new. */
	_SPudtable[refnum] = clamopen(refnum + 3, SP_DETECT + SP_CORRECT, thePath, 0xD0, 0x8001L);

    D_BLFORGETLISTS();
    HUnlock(wList);
    DisposeHandle(wList);
	D_SETCURSOR(arrowCursor);
    CloseDialog(dlgPort);
}


/* Compare strings given ptrs to handles to strings */

static int strhpcmp(ptr1, ptr2)
char ***ptr1, ***ptr2;
{
    return(strcmp(**ptr1, **ptr2));
}

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

static pascal void selProc(foo, wnum)
char *foo;
int wnum;
{
unsigned val;

    setbank;

    if (wnum >= 0)
    {
        if (!doingsel)
        {
            doingsel = 1;
            doingword = 0;
            HiliteControl(255, GetControlDItem(dlgPort, 1));
            HiliteControl(0, GetControlDItem(dlgPort, 4));
            SetIText(dlgPort, 5, "");
        }
    }
    else if (doingsel)
    {
        doingsel = 0;
        HiliteControl(255, GetControlDItem(dlgPort, 4));
    }

    restorebank;
}


static pascal unsigned udfilter(dlg, evt, item)
GrafPortPtr dlg;
EventRecordPtr evt;
int *item;
{
Point thept;
int top;
unsigned val;
char s[35];

	extern pascal void D_BLINKBUTTON();

    setbank;

	GetIText(dlg, 5, s);
	if (s[0]) {
		HiliteControl(0, GetControlDItem(dlg, 1));
		doingword = 1;
	} else {
		HiliteControl(255, GetControlDItem(dlg, 1));
		doingword = 0;
	}
		
    if (evt->what == keyDownEvt || evt->what == autoKeyEvt) {
		switch((char) evt->message) {
			case 0x0d:
				if (doingword) {
					D_BLINKBUTTON(dlg,ok);
					*item = ok;
					restorebank;
					return 1;
				}
				else
					evt->what = nullEvt;
				break;

			case 0x1B:	/* ESC */
				evt->message = 0x18;
				evt->modifiers |= keyPad;
				restorebank;
				return 0;

			case '.':
				if (evt->modifiers & appleKey) {
					D_BLINKBUTTON(dlg,cancel);
					*item = cancel;
					restorebank;
					return 1;
				}
				break;

			case 0xBA:	/* non-breaking space */
				*item = 0;
				restorebank;
				return 1;
				
			default:
       			if (!doingword) {
					D_BLSELECT(&theList, -1);
				}
		}
    }

    restorebank;
    return 0;
}
