/* search.c
 *   Handles the search window popup
 */

#include <stdio.h>

#include <Xos.h>
#include <Intrinsic.h>
#include <StringDefs.h>
#include <Xfuncs.h>

#include <Xatom.h>
#include <Xmu/Atoms.h>
#include <Xmu/StdSel.h>

#include <Shell.h>

#include <Xaw/Command.h>
#include <Xaw/Label.h>
#include <Xaw/Form.h>
#include <Xaw/Box.h>
#include <Xaw/AsciiText.h>
#include <Xaw/Paned.h>
#include <cursorfont.h>

/* for _XawTextGetSTRING(), except actually including it gets messy  */
/*#include <Xaw/TextP.h>*/


#include "defs.h"
#include "externs.h"
#include "game.h"
#include "widgets.h"
#include "search.h"
#include "convert.h"
#include "multikanji.h"
#include "strokesearch.h"
#include "radsearch.h"
#include "readfile.h"
#include "searchwidgets.h"
#include "learn.h"
#include "utils.h"
#include "init.h"
#include "log.h"

/* I dont like doing this. But there doesnt seem to be a reliable
 * way to tell a widget "be the entire width of the form" that
 * I have found
 */
#define SEARCHWIDTH 450


Cursor textcursor;

Widget search_popup=NULL;
Widget searchstatusline=NULL;

Widget searchwidgets[NUM_OF_W];
Widget searchnumbers[NUM_OF_N];
Widget searchkanjiW,searchokuW; /* display current kanji here */

/* note.. if your compiler bitches about this initialization...
 * just remove  the "={{0,0}}".
 * It will probably get initialized to 0,0 anyways
 * kanastring is the string held by the "type romaji here" widget.
 */
XChar2b kanastring[MAXKANALENGTH]={{0,0}};

/* flag, if we only match kanji/kana at beginning of translation */
int match_onlyatstart=0, match_onlyactive=0;


static char *searchAccel = 
 " <Key>Return:  do-find()";



/* This gets called after clicking on the "search" button, or
 *  using the keyboard accelerator. It pops up the search window.
 */
void SearchCallback(Widget w,XtPointer client_data, XtPointer call_data)
{
	static int search_up = -1; 
	static Position rel_x,rel_y;
	Position x,y;

	/* sometimes we are called with w==NULL by hand */

	if(search_up==-1){
		/* first time init.. */
		rel_x = GetXtrmNumber("search_popupx","Search_popupx");
		rel_y = GetXtrmNumber("search_popupy","Search_popupy");
		setup_deletewindow(search_popup);
		search_up=0;
	}
	if(isMapped(search_popup)==False){
		/* Map in! */

		XtTranslateCoords(toplevel,rel_x,rel_y,&x,&y);
		/* it seems some window managers let you have extreme
		 * negative coordinates for pop-ups. sigh
		 */
		if(x<0) x=0;
		if(y<0) y=0;

		XtVaSetValues(search_popup,
		      XtNx,x,
		      XtNy,y,
		      NULL);

		XtMapWidget(search_popup);
		setstatus("Bringing up search window...");

	} else {
		XtUnmapWidget(search_popup);
	}
}

/* handle toggle for "match only if kana STARTS a phrase" */
void ToggleMatchstart(Widget w,XtPointer client_data, XtPointer call_data)
{
	match_onlyatstart=!match_onlyatstart;

	ReverseButton(w);

}

/* handle toggle for "match only active kanji" */
void ToggleActivesearch(Widget w,XtPointer client_data, XtPointer call_data)
{
	match_onlyactive=!match_onlyactive;

	ReverseButton(w);
}

/* deal with matchkanji button. */
/* Find all matches for what is currently being displayed by the search win*/
void Handle_matchkanji(Widget w,XtPointer client_data, XtPointer call_data)
{
	findkanjiall(lastsearch->kanji);
}

/* Handle toggle callback for "[usefile]" toggle button */
/* Parallel func to multiUcallback() */
static void 
ToggleUsefile(Widget w,XtPointer client_data, XtPointer call_data)
{
	int kcount=trans_to_index(lastsearch);
	SetUseKanji(kcount, !InUsefile(kcount));

	if(InUsefile(kcount)){
		HighlightButton(w);
	} else {
		UnhighlightButton(w);
	}

	DisplayLearnChar(); /* on the off-chance the Learn window shows same*/
	RefreshMultiLabels();

	CountKanji();
}

/* Callback for button to  "Show usefile" */
void ShowUsefile(Widget w,XtPointer client_data, XtPointer call_data)
{
	setstatus("Showing usefile...");

	dousefilefind();
}

/* Update the labels for the info widgets at the top of search window.*/
/* Assumes variable "lastsearch" points to currently desired TRANSLATION */
void UpdateSearchlabels()
{
	TRANSLATION This=lastsearch;
	int kanjinum=0, kindex;
	XChar2b radlist[MAXRADICALS+1];

	if(search_popup==NULL)
		return;
	if(This==NULL){
		return;
	}

	XtVaSetValues(searchkanjiW,XtNlabel,This->kanji,
		XtNwidth,KANJIWIDTH,XtNheight,KANJIWIDTH,NULL);

	SetWidgetNumberval(searchnumbers[G_INPUT],(int)This->grade_level);
	SetWidgetNumberval(searchnumbers[F_INPUT],(int)This->frequency);
	SetWidgetNumberval(searchnumbers[H_INPUT],(int)This->Hindex);
	SetWidgetNumberval(searchnumbers[N_INPUT],(int)This->Nindex);
	SetWidgetHexval(searchnumbers[U_INPUT],(int)This->Uindex);

	kindex=trans_to_index(This);

	if(InUsefile(kindex)) {
		HighlightButton(searchnumbers[INUSEFILE]);
	} else {
		UnhighlightButton(searchnumbers[INUSEFILE]);
	}

	/* assume if kanji entry is ONE char long, that we
	 * can use that byte as old kdrill/kanjidic index
	 *  ('#x' window)
	 */

	if(This->kanji != NULL){
		if(This->kanji[1].byte1 == 0)
		{
			kanjinum = This->kanji[0].byte1;
			kanjinum = kanjinum <<8;
			kanjinum |= This->kanji[0].byte2;
		}
	}
	if(kanjinum == NOKANJI) {
		kanjinum = 0;
	}

	SetWidgetHexval(searchnumbers[POUND_INPUT], kanjinum);

	if(romajiswitch==1) {
		char stringbuff[MAXROMAJI+1];
		/*translate all kana into romaji */
		/* translate to buffer, then set widget string*/
		kanatoromaji(This->pronunciation, stringbuff);
		XtVaSetValues(searchwidgets[KANA_W],
		      XtNencoding,XawTextEncoding8bit,
		      XtNfont,englishfont,
		      NULL);
		XtVaSetValues(searchwidgets[KANA_W],
		      XtNlabel,stringbuff,
		      NULL);
	
	} else {
		XtVaSetValues(searchwidgets[KANA_W],
		      XtNencoding, XawTextEncodingChar2b,
		      XtNfont,smallkfont,
		      NULL);
		XtVaSetValues(searchwidgets[KANA_W],
		      XtNlabel,This->pronunciation,NULL);
	}
	XtVaSetValues(searchwidgets[ENGLISH_W],
		      XtNlabel,This->english,NULL);

	XtVaSetValues(searchnumbers[RADLIST_D],XtNlabel,"\0\0",NULL);
	if(kanjinum!=0){
		radlist[0].byte1=0;
		/* a single kanji, should have radicals associated with it*/
		FindRadicals(This->kanji[0],radlist);
		if(radlist[0].byte1 != 0){
			XtVaSetValues(searchnumbers[RADLIST_D],
				XtNlabel,radlist,NULL);
		}
	}
	
}

/* clear labels of "current kanji" display, in top of search window */
void clearsearchlabels()
{
	XChar2b blank = {0x0, 0x0};

	XtVaSetValues(searchkanjiW,
		      XtNlabel,"                               ",
		      NULL);
	XtVaSetValues(searchwidgets[ENGLISH_W],XtNlabel,"",NULL);
	SetWidgetNumberval(searchnumbers[G_INPUT],0);
	SetWidgetNumberval(searchnumbers[F_INPUT],0);
	SetWidgetNumberval(searchnumbers[POUND_INPUT],0);
	SetWidgetNumberval(searchnumbers[H_INPUT],0);
	SetWidgetNumberval(searchnumbers[N_INPUT],0);
	SetWidgetNumberval(searchnumbers[U_INPUT],0);
	XtVaSetValues(searchkanjiW,XtNlabel,&blank,
		XtNwidth,KANJIWIDTH,XtNheight,KANJIWIDTH,NULL);
		
}

/* printsearch:
*	Given an index, make search window print out appropriate stuff.
*	printsearch(0) means "clear windows".
*
*	This also sets the lastsearch static global!!
*/
void printsearch(TRANSLATION This)
{
	if(isMapped(search_popup)==False){
		/* pop up window, if it isnt already */
		SearchCallback(search_popup,NULL,NULL);
	}

	if(This==NULL){
		return;
	}
	lastsearch = This;
	UpdateSearchlabels();
}

/* SearchRefresh()
 *	called by romajicallback, when user toggles romaji/kana display
 */
void SearchRefresh()
{
	UpdateSearchlabels();
	if(isMapped(search_popup))
		printsearch(lastsearch);
}

/* stolen from xclipboard */
long TextLength (w)
    Widget  w;
{
    return XawTextSourceScan (XawTextGetSource (w),
                              (XawTextPosition) 0,
                              XawstAll, XawsdRight, 1, TRUE);
}

/*
 * This is basically a hand-coded "hextoi()" function.
 * I dont know of a ubiquitous "hex to int" function like
 * atoi
 * It is fairly inflexible: it wants EXACTLY 4 hex digits.
   values passed back as bits 0-7 is "byte1"
  * 8-15 is "byte2"
*/
static CARD16 unescape_kanji(char *string){
	int kchar[4]; /* temp buffer, really */
	int count;
	CARD16 newval;

	if(strlen(string)<4){
		fprintf(stderr,"unescape_kanji passed bad string\n");
		return 0;
	}

	for(count=0; count<4; count++){
		if(('A' <= string[count]) && (string[count] <='F')){
			kchar[count]=string[count] - 'A' + 10;
			
		} else if(('a' <= string[count]) && (string[count] <='f')){
			kchar[count]=string[count] - 'a' + 10;
			
		} else {
			kchar[count]=string[count] - '0';
		}
	}

	newval=(kchar[0]<<12) +(kchar[1]<<8) +(kchar[2]<<4) +kchar[3];

	return newval;
}

/* take various formats of JIS, etc,
 * [from cut-n-paste]
 * convert to what we expect, and call
 * findkanjiall() on resulting string, IF we recognize something.
 *
 * We Assume buffer is AT LEAST 2 bytes long !!!
 *
 * POSSIBILITIES:
 * 1. "raw" JIS, that looks to us like
 *   0xffffff##, 0xffffff##
 *
 * 2. prefaced SJIS, that looks to us like
 *   0x1b, 0x2d, 0x41, 0xffffff##, 0xffffff##
 *
 * 2.1 prefaced JIS, that looks to us like
 *   0x1b, 0x2d, 0x41, 0x####, 0x####, 0x1b, 0x28
 * 
 * 3. A different (older?) kind of prefaced JIS,that looks like
 *   0x1b, 0x24, 0x29, 0x42, blahblahblah
 * 
 * 4. stripped JIS (from rxvt), that is going to be tricky to tell.
 *
 * return 1 on recognizeable JIS string, or 0 otherwise.
 */
static int doJISConvert(char *inputstring){
	/* only handle up to three encoded chars. Ignore more. */
	XChar2b kstring[4];
	char *strstart=NULL;
	int kstr_ndx;

	bzero(kstring, sizeof(XChar2b) * 4);

	/* SPECIAL CASES: We have an ascii-hex-encoded string here */
	/* It is probably actually UNICODE */
	/* pan newsreader actually uses its own funky encoding:
	     \x{xxxxx} [maybe this was gtk1? pan+gtk2 uses mozilla style now]
	   Mozilla/firefox seems to use
	     \u6559\u80b2
	     ??
	 */
	if(strncmp("\\u",inputstring,2) == 0){
		strstart=&inputstring[2];
	}
	if(strncmp("\\x{",inputstring,3) == 0){
		strstart=&inputstring[3];
	}
	if(strstart != NULL){
		/* this takes only a SINGLE CHAR, unfortunately */
		CARD16 tmpval=unescape_kanji(strstart);
		if(tmpval != 0){
			kstring[0].byte1=(tmpval&0xff00)>>8;
			kstring[0].byte2=(tmpval&0xff);
		}

		/* and is there a second char available? */
		strstart=&strstart[4];
		if(strncmp("\\u",strstart,2) == 0){
			strstart=&strstart[2];
		}
		if(strncmp("\\x{",strstart,3) == 0){
			strstart=&strstart[3];
		}
		if(strstart != NULL){
			tmpval=unescape_kanji(strstart);
			if(tmpval != 0){
				kstring[1].byte1=(tmpval&0xff00)>>8;
				kstring[1].byte2=(tmpval&0xff);
			}
		}

		if(kstring[0].byte1 !=0){
			findunicodestring(kstring);
			return 1;
		}
	}



	/* Otherwise, we have lightly encoded, or raw, JIS to parse */


	if(inputstring[0]&0xffffff00){
		strstart=&inputstring[0];
	} else if(strncmp("\x1b\x24\x29\x42",inputstring,4) == 0){
		strstart=&inputstring[4];
	} else if(strncmp("\x1b\x2d\x41",inputstring,3) == 0){
		strstart=&inputstring[3];
	} else if(strncmp("\x1b\x2d\x42",inputstring,3) == 0){
		/* We should never normally see this, because
		 * the Xaw routines seem to autoconvert this to the
		 * 0xffffff format instead
		 */
		strstart=&inputstring[3];
	}


	if((strstart==NULL) && (kstring[0].byte1==0)){
		/* ugh. Unfortunately, rxvt hands us unencoded stuff,
		 * which in theory might just be plain ascii.
		 * Attempt to treat it as JIS, if first char hits
		 * a known kanji
		 */
		int tmpndx=0;
		tmpndx=(inputstring[0]<<8) |(inputstring[1]&0xff);
		if((tmpndx>MAXKANJIALLOWED) ||(tmpndx< MINKANJIALLOWED)){
			return 0;
		}
		if(translations[tmpndx] == NULL){
			return 0;
		}
		strstart=&inputstring[0];
	}

	/* Okay, we have valid string. Convert up to 3 chars to JIS
	 * format that we use internally, so we can search on it
	 */
	kstr_ndx=0;
	while(kstr_ndx<3){
		if((strstart[0]==0) || strstart[1]==0) {
			break;
		}
		kstring[kstr_ndx].byte1=*strstart++ & 0x7f;
		kstring[kstr_ndx].byte2=*strstart++ & 0x7f;
		kstr_ndx++;
	}
	if(kstr_ndx==0) return 0;

	kstring[kstr_ndx].byte1=0;
	kstring[kstr_ndx].byte2=0;
	findkanjiall(&kstring[0]);

	return 1;

}



/* copy cut-n-paste buffer into local storage, and do search on it 
 * if possible.
 * Triggered by pasteCallback()
 */
void
copybuffer(Widget w, XtPointer client_data, Atom *selection, Atom *type, 
            XtPointer value, unsigned long *length, int *format)
{
	int buflen=(int)*length;
	char *valuestring=(char*)value;

	if(*type==0){
#ifdef DEBUG
		puts("DEBUG copybuffer has *type=0. returning.");
#endif
		return;
	}


	if(buflen==0){
#ifdef DEBUG
		puts("DEBUG: paste len==0. ignoring");
#endif
		return;
	}
	if(buflen<2){
#ifdef DEBUG
		puts("DEBUG: paste len==1. ignoring");
#endif
		XtFree(value);
		return;
	}
#ifdef DEBUG
	puts("copybuffer: values of XtNstring pasted are:");
	while(bufparse <buflen) {
		printf("%.2x.",valuestring[bufparse++]);

	} 
	puts("");
	printf("  total string len == %d\n", buflen);
#endif
	doJISConvert(valuestring);


	XtFree(value);
}


/* "Handler" for "<paste kanji>" button in search window.
 * Completely obsoletes the old nasty Handle_searchPasted() hack I had before.
 * This takes the high-level X clipboard stuff, and hands it over to
 * copybuffer()
 */
void Handle_paste(Widget widget, XtPointer closure, XEvent *e, Boolean *cont)
{
	Time timestamp;
	Atom clipboardatom;

	timestamp=CurrentTime;

	/*
	puts("DEBUG: using XA_CLIPBOARD for cutnpaste");
	clipboardatom=XA_CLIPBOARD(display);
	*/

	clipboardatom=XA_PRIMARY;

	/* I originally used XA_STRING as the 'type', but
	 * that did not work with kterm.
	 * Once I changed to XA_TEXT(), it seems to work for both
	 * kterm, AND netscape4.x
	 *
	 * call copybuffer() with the value.
	 */
	XtGetSelectionValue(widget, clipboardatom, XA_TEXT(display),
			    copybuffer, NULL,
			    timestamp);
}


/* This gets called when someone presses a mousebutton in the big kanji
 * display string, in the search popup.
 * Our job is to split up the string into multiple kanji, and
 * popopulate the multikanji popup, so that the user can deconstruct
 * the string into separate kanji
 */
void Handle_kanji_split(Widget widget, XtPointer closure, XEvent *e, Boolean *cont)
{
	split_kanji_search();
}


/*************************************************************
 *    Widget Creation Below Here                             *
 *************************************************************/

/* make the G, F, # , etc,  for the search popup */
void makenumbers(Widget parent){
	searchnumbers[G_LABEL] = XtVaCreateWidget("0",labelWidgetClass,parent,
		       XtNlabel,"G:",      XtNborderWidth,0,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);

	/* G_INPUT is read-only, not really "INPUT".
	 * but keep as asciiText so UpdateSearchLabels()
	 * can have a uniform code layout.
	 */
	searchnumbers[G_INPUT] = XtVaCreateWidget("sn1",asciiTextWidgetClass,parent,
		       XtNfromHoriz,searchnumbers[G_LABEL],
		       XtNstring,"  ",  XtNdisplayCaret,False,
		       XtNwidth,30,	/* leave this short, match mainwin */
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[H_LABEL] = XtVaCreateWidget("sn6",labelWidgetClass,parent,
		       XtNfromVert,searchnumbers[G_LABEL],
		       XtNlabel,"H:",   XtNborderWidth,0,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[H_INPUT] = XtVaCreateWidget("sn7",asciiTextWidgetClass,parent,
		       XtNfromVert,searchnumbers[G_LABEL],
		       XtNfromHoriz,searchnumbers[G_LABEL],
		       XtNstring," ",  XtNwidth,INPUTWIDTH,
		       XtNeditType,XawtextEdit,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);

	searchnumbers[F_LABEL] = XtVaCreateWidget("sn2",labelWidgetClass,parent,
		       XtNfromHoriz,searchnumbers[H_INPUT],
		       XtNlabel,"F:",  XtNborderWidth,0,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[F_INPUT] = XtVaCreateWidget("sn3",asciiTextWidgetClass,parent,
		       XtNfromHoriz,searchnumbers[F_LABEL],
		       XtNstring,"",  XtNwidth,INPUTWIDTH,
		       XtNeditType,XawtextEdit,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[N_LABEL] = XtVaCreateWidget("sn8",labelWidgetClass,parent,
		       XtNfromVert,searchnumbers[G_LABEL],
		       XtNfromHoriz,searchnumbers[H_INPUT],
		       XtNlabel,"N:",   XtNborderWidth,0,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[N_INPUT] = XtVaCreateWidget("sn9",asciiTextWidgetClass,parent,
		       XtNfromVert,searchnumbers[G_LABEL],
		       XtNfromHoriz,searchnumbers[F_LABEL],
		       XtNstring," ",  XtNwidth,INPUTWIDTH,
		       XtNeditType,XawtextEdit,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);

	searchnumbers[POUND_LABEL] = XtVaCreateWidget("sn4",labelWidgetClass,parent,
		       XtNfromHoriz,searchnumbers[F_INPUT],
		       XtNfromHoriz,searchnumbers[N_INPUT],
		       XtNlabel,"#x:",  XtNborderWidth,0,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[POUND_INPUT] = XtVaCreateWidget("sn5",asciiTextWidgetClass,parent,
		       XtNfromHoriz,searchnumbers[POUND_LABEL],
		       XtNstring,"",  XtNwidth,INPUTWIDTH,
		       XtNeditType,XawtextEdit,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[U_LABEL] = XtVaCreateWidget("sn10",labelWidgetClass,parent,
		       XtNfromVert,searchnumbers[G_LABEL],
		       XtNfromHoriz,searchnumbers[F_INPUT],
		       XtNfromHoriz,searchnumbers[N_INPUT],
		       XtNlabel,"Ux:",   XtNborderWidth,0,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[U_INPUT] = XtVaCreateWidget(
			"11",asciiTextWidgetClass,parent,
			XtNfromVert,searchnumbers[G_LABEL],
			XtNfromHoriz,searchnumbers[POUND_LABEL],
			XtNstring," ",  XtNwidth,INPUTWIDTH,
			XtNeditType,XawtextEdit,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
			NULL);

	searchnumbers[INUSEFILE] = XtVaCreateWidget(
			"12",commandWidgetClass,parent,
			XtNlabel, "usefile",
			XtNfromHoriz,searchnumbers[U_INPUT],
			XtNhorizDistance, 20,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);
	searchnumbers[SHOWUSEFILE] = XtVaCreateWidget(
			"12",commandWidgetClass,parent,
			XtNlabel, "show u.",
			XtNshapeStyle,XawShapeRoundedRectangle,
			XtNcornerRoundPercent,50,
			XtNfromHoriz,searchnumbers[U_INPUT],
			XtNfromVert,searchnumbers[INUSEFILE],
			XtNhorizDistance, 20,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
		       NULL);

	searchnumbers[RADLIST_L] = XtVaCreateManagedWidget("radlist_l",
			labelWidgetClass,
			parent,
			XtNlabel,"Radicals:",
			XtNborderWidth, 0,
			XtNfromVert,searchnumbers[H_LABEL],
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
			NULL);
	searchnumbers[RADLIST_D] = XtVaCreateManagedWidget("radlist_d",
			labelWidgetClass,
			parent,
			XtNfromVert,searchnumbers[H_LABEL],
			XtNfromHoriz,searchnumbers[RADLIST_L],
			XtNlabel,"                  ",
			XtNencoding,XawTextEncodingChar2b,
			XtNfont,smallkfont,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			NULL);

	XtManageChildren(searchnumbers,NUM_OF_N);
}


/* make topstuff:
 * Make widgets dealing with "current kanji", at top of search popup
 */
void maketopsearchstuff(Widget parent){
	Widget numbersform,matchbutton;

	searchkanjiW = XtVaCreateManagedWidget("kanjilarge",
						  labelWidgetClass,
						  parent,
			XtNwidth,SEARCHWIDTH - 100,
			XtNheight,KANJIWIDTH,
			XtNlabel,"",
			XtNencoding,XawTextEncodingChar2b,
			XtNfont,largekfont,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			NULL);
	/* want to handle just middle button on this one */
	XtAddEventHandler(searchkanjiW,
			  ButtonPressMask,False,Handle_kanji_split,NULL);


	matchbutton = XtVaCreateManagedWidget("matchkanjib",
			commandWidgetClass,parent,
			XtNfromHoriz,searchkanjiW,
			XtNlabel, "match",
			XtNright, XawChainRight,
			XtNleft,  XawChainRight,
			NULL);
	
	XtAddCallback(matchbutton, XtNcallback, Handle_matchkanji, NULL);

	numbersform = XtVaCreateManagedWidget("numform",
			formWidgetClass, parent,
			XtNresizeToPreferred, True,
			XtNfromVert,searchkanjiW,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
       			NULL);

	makenumbers(numbersform);


}



/* define the label and input widgets for inputting english
 * and kana. At the TOP LEVEL of the search window.
 *
 * For kana, the "label" is actually a button that will bring up the
 * special kana input window. User can then point-and-click.
 *
 * Returns "lowest" (southernmost) widget, so status line can be
 * "below" that.
 */
Widget makesearchinputs(Widget parent)
{
	Widget kanjisform, searchinputform;
	Widget optsform, optslabel;


	searchinputform=XtVaCreateManagedWidget("searchinputform",
			formWidgetClass,parent,
			XtNfromVert, searchwidgets[ENGLISH_W],
			XtNvertDistance,10,
			XtNresizeToPreferred, True,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			NULL);

	searchwidgets[SEARCH_ENG_L] =
		XtVaCreateManagedWidget("searchenglishlabel",
			labelWidgetClass, searchinputform,
			XtNjustify, XtJustifyRight,
			XtNlabel, "English search",
			XtNborderWidth, 0,
			XtNleft, XawChainLeft,
			XtNright, XawChainLeft,
			NULL);
						       
	searchwidgets[SEARCH_ENG_W] =
		XtVaCreateManagedWidget("searchenglish",
			asciiTextWidgetClass,
			searchinputform, 
			XtNfromHoriz, searchwidgets[SEARCH_ENG_L],
			XtNfont, englishfont,
			XtNeditType, XawtextEdit,
			XtNleft, XawChainLeft,
			XtNright, XawChainRight,
			/*XtNstring,"                 ",*/
			XtNwidth, 150,
			NULL);

	/************************************************************/


	kanjisform=
		XtVaCreateManagedWidget("searchkanjif",
			formWidgetClass,searchinputform,
			XtNfromVert, searchwidgets[SEARCH_ENG_L],
			XtNvertDistance, 10,
			XtNleft, XawChainLeft,
			XtNright, XawChainLeft,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			NULL);

	searchwidgets[SEARCH_KANJI_L] =
		XtVaCreateManagedWidget("searchkanjibutton",
			commandWidgetClass, kanjisform,
			XtNjustify, XtJustifyRight,
			XtNlabel, "Kanji search  ",
			XtNright, XawChainRight,
			NULL);

	searchwidgets[SEARCH_SKIP_W] =
		XtVaCreateManagedWidget("searchskipbutton",
			commandWidgetClass, kanjisform,
			XtNlabel, "Kanji SKIP search",
			XtNfromHoriz, searchwidgets[SEARCH_KANJI_L],
			XtNleft, XawChainRight,
			XtNright, XawChainRight,
			NULL);

	searchwidgets[SEARCH_STROKE_W] =
		XtVaCreateManagedWidget("searchstrokebutton",
			commandWidgetClass,kanjisform,
			XtNjustify, XtJustifyRight,
			XtNlabel, "Stroke count  ",
			XtNfromVert, searchwidgets[SEARCH_KANJI_L],
			XtNright, XawChainRight,
			NULL);


	searchwidgets[SEARCH_KANJIPASTE] =
		XtVaCreateManagedWidget("searchkanji",
			labelWidgetClass,kanjisform,
			XtNlabel," <paste kanji> ",
			XtNfromVert, searchwidgets[SEARCH_KANJI_L],
			XtNfromHoriz, searchwidgets[SEARCH_STROKE_W],
			XtNleft, XawChainRight,
			XtNright, XawChainRight,
			NULL);

	searchwidgets[SEARCH_RADICAL_W] =
		XtVaCreateManagedWidget("searchradicals",
			commandWidgetClass,kanjisform,
			XtNlabel,"Radical search",
			XtNfromVert, searchwidgets[SEARCH_STROKE_W],
			XtNright, XawChainRight,
			NULL);

	/* and now the kana search input widgets. gets a bit messy here */

	searchwidgets[KANA_FORM]=XtVaCreateManagedWidget("kanasearchgroup",
			formWidgetClass, searchinputform,
			XtNresizeToPreferred, True,
			XtNfromVert, kanjisform,
			XtNvertDistance, 10,
			XtNborderWidth, 1,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			NULL);


	searchwidgets[SEARCH_KANA_L] =
		XtVaCreateManagedWidget("searchkanalabel",
			labelWidgetClass, searchwidgets[KANA_FORM],
			XtNlabel, "Kana searches",
			XtNborderWidth,0,
			XtNright, XawChainLeft,
			XtNleft, XawChainLeft,
			NULL);

	searchwidgets[SEARCH_KANA_B] =
		XtVaCreateManagedWidget("searchkanabutton",
			commandWidgetClass, searchwidgets[KANA_FORM],
			XtNfromHoriz,searchwidgets[SEARCH_KANA_L],
			XtNhorizDistance,20,
			XtNlabel, "Popup Kana table",
			XtNright, XawChainRight,
			XtNleft, XawChainRight,
			/* These dont work as I want */
			/*
			XtNresizable, False,
			*/
			NULL);


	searchwidgets[SEARCH_KANA_W] =
		XtVaCreateManagedWidget("searchkana",
			labelWidgetClass, searchwidgets[KANA_FORM], 
			XtNwidth, SEARCHWIDTH - 150,
			XtNlabel,"\0",
			/*XtNlabel, "!z",*/ /* 0x217a */
			XtNfromVert, searchwidgets[SEARCH_KANA_L],
			XtNfont, smallkfont,
			XtNencoding, XawTextEncodingChar2b,
			XtNjustify, XtJustifyLeft,
			XtNcursor, textcursor,
			XtNright, XawChainRight,
			XtNleft, XawChainLeft,
			NULL);


	/************************************************************/

	optsform=XtVaCreateManagedWidget("searchoptsform",
			formWidgetClass, parent,
			XtNresizeToPreferred, True,
			XtNfromVert, searchwidgets[ENGLISH_W],
			XtNvertDistance,10,
			XtNfromHoriz, searchinputform,
			XtNborderWidth, 1,
			XtNleft, XawChainRight,
			XtNright, XawChainRight,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			NULL);


	optslabel=XtVaCreateManagedWidget("searchoptslabel",
			labelWidgetClass, optsform,
			XtNlabel, " Match ",
			XtNborderWidth, 0,
			/*XtNjustify,XawCenter */ /* default */
			NULL);
			

	searchwidgets[SEARCH_ACTIVEFILTER]=
		XtVaCreateManagedWidget("filter_toggle",
			commandWidgetClass, optsform,
			XtNfromVert, optslabel,
			XtNlabel, "active",
			NULL);

	searchwidgets[SEARCH_STARTTOG]=
		XtVaCreateManagedWidget("atstart_toggle",
			commandWidgetClass, optsform,
			XtNfromVert, searchwidgets[SEARCH_ACTIVEFILTER],
			XtNlabel, "initial",
			NULL);
		
	/* This possibly now has the wrong value.(?) sigh. */
	/*XtManageChildren(searchwidgets,SEARCH_ENG_W+1);*/


	XtAddCallback(searchwidgets[SEARCH_KANA_B], 
		      XtNcallback, Showinputkana, NULL);
	XtAddCallback(searchwidgets[SEARCH_KANJI_L], 
		      XtNcallback, Showinputkanji, NULL);
	XtAddCallback(searchwidgets[SEARCH_SKIP_W], 
		      XtNcallback, ShowSKIP, NULL);
	XtAddCallback(searchwidgets[SEARCH_STROKE_W], 
		      XtNcallback, Showstroke, NULL);
	XtAddCallback(searchwidgets[SEARCH_RADICAL_W], 
		      XtNcallback, ShowRadicalinput, NULL);

	XtAddCallback(searchwidgets[SEARCH_STARTTOG], 
		      XtNcallback, ToggleMatchstart, NULL);
	XtAddCallback(searchwidgets[SEARCH_ACTIVEFILTER], 
		      XtNcallback, ToggleActivesearch, NULL);

	XtAddCallback(searchnumbers[INUSEFILE], 
		      XtNcallback, ToggleUsefile, NULL);
	XtAddCallback(searchnumbers[SHOWUSEFILE], 
		      XtNcallback, ShowUsefile, NULL);

	/*
	XtAddCallback(searchwidgets[SEARCH_KANJIPASTE],
		      XtNcallback, pasteCallback, NULL);
	*/

	/* want to handle any/all buttons */
	XtAddEventHandler(searchwidgets[SEARCH_KANJIPASTE],
			  ButtonPressMask,False,Handle_paste,NULL);


	XtAddEventHandler(searchwidgets[SEARCH_KANA_W],
			  KeyPressMask,
			  False, Handle_romajikana,NULL);
	
	return searchinputform;
}


/* This is the only exported "make widgets" routine */
void MakeSearchPopup()
{
	XtAccelerators Accel;
	Widget searchform,lastsearchinput;

	textcursor=XCreateFontCursor(display,XC_xterm);

#ifdef OLDWAY
	search_popup = XtVaCreatePopupShell("kdrill_search",
		transientShellWidgetClass,
		toplevel,
		NULL);
#else
	search_popup = XtVaCreateWidget("kdrill_search",
		/*shellWidgetClass,*/
		topLevelShellWidgetClass,
		toplevel,
		NULL);
	XtSetMappedWhenManaged(search_popup,False);
#endif

	searchform = XtVaCreateManagedWidget("searchform",
					     formWidgetClass,
					     search_popup,
					     NULL);

	searchwidgets[NFORM_W] = XtVaCreateManagedWidget("northform",
			formWidgetClass,
			searchform,
			XtNresizeToPreferred, True,
			XtNborderWidth,2,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			NULL);

	/* make everything in the top box: kanji, frequency, grade, etc*/
	maketopsearchstuff(searchwidgets[NFORM_W]);

	/* now make the wide output display widgets, below the main
	 * kanji display, at the top.
	 */
	searchwidgets[KANA_W] = XtVaCreateManagedWidget("searchkana",
						 labelWidgetClass,
						 searchform,
			XtNlabel,"                               ",
			XtNfromVert,searchwidgets[NFORM_W],
			XtNvertDistance,20,
			XtNencoding,XawTextEncodingChar2b,
			XtNfont,smallkfont,
			XtNwidth,SEARCHWIDTH,
			XtNleft, XawChainLeft,
			XtNright, XawChainRight,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			NULL);

	searchwidgets[ENGLISH_W] = XtVaCreateManagedWidget("searchenglish",
						    labelWidgetClass,
						    searchform, 
			XtNlabel,"                                       ",
			XtNfromVert,searchwidgets[KANA_W],
			XtNfont,englishfont,
			XtNwidth,SEARCHWIDTH,
			XtNleft, XawChainLeft,
			XtNright, XawChainRight,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			NULL);

	/* This makes other searchwidgets[] stuffs, below the static
	 * display we just made, above.
	 */
	lastsearchinput=makesearchinputs(searchform);

	searchstatusline = XtVaCreateManagedWidget("searchstatus",
			labelWidgetClass, searchform,
			XtNlabel,"Search popup",
			XtNwidth,SEARCHWIDTH,
			XtNborderWidth,2,
			XtNfromVert, lastsearchinput,
			XtNresize,True,
			XtNleft, XawChainLeft,
			XtNright, XawChainRight,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
		      NULL);

	Accel = XtParseAcceleratorTable(searchAccel);
	XtOverrideTranslations(searchwidgets[SEARCH_ENG_W],Accel);


	XtOverrideTranslations(searchnumbers[F_INPUT],Accel);
	XtOverrideTranslations(searchnumbers[POUND_INPUT],Accel);
	XtOverrideTranslations(searchnumbers[H_INPUT],Accel);
	XtOverrideTranslations(searchnumbers[N_INPUT],Accel);
	XtOverrideTranslations(searchnumbers[U_INPUT],Accel);

	MakeKanainputPopup();
	MakeKanjiinputPopup();
	MakeStrokeinputPopup();
	MakeSKIPInputPopup();
}
