#include <stdio.h>
#include <stdlib.h>

#include <Xatom.h>
#include <Xos.h>
#include <Intrinsic.h>
#include <StringDefs.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> /* See comment around MakeSpecialForms */

#include "defs.h"
#include "externs.h"
#include "game.h"
#include "grades.h"
#include "options.h"
#include "search.h"
#include "searchwidgets.h"
#include "strokesearch.h"
#include "learn.h"
#include "utils.h"
#include "multikanji.h"
#include "init.h"
#include "log.h"
#include "timeout.h"

Widget toplevel,mainform;

XFontStruct *largekfont;
XFontStruct *smallkfont;
XFontStruct *englishfont;
XFontStruct *defaultfont;

Widget kanjiform,englishform,buttonform;

Widget statusline;
Widget currentkanjiForm;
Widget currentkanjiGrade,currentkanjiFreq,currentkanjiNum;
Widget kanjiMissed;

Widget choicesWidgets[NUMBEROFCHOICES],questionWidget;

Widget ONWidget;

static char * jumpAccel = 
 " <Key>Return:  jump-to-kanji()";


/* setstatus:
 *  sets label for main status bar widget.
 *	( the long one at the bottom)
 *  and also the same message at the bottom of the search popup window
 */
void setstatus(char *s)
{
	if((statusline==NULL) || (searchstatusline==NULL)){
		/* Some kind of warning message, before program has fullyh
		 * come up. Print to stdout instead
		 */
		printf("%s\n", s);
		return;
	}
	XtVaSetValues(statusline,
		      XtNlabel,s,
		      NULL);
	XtVaSetValues(searchstatusline,
		      XtNlabel,s,
		      NULL);
}


/* handle_button
 *	exists for the sole purpose of getting Button2 events
 */
void
handle_button(Widget w,XtPointer closure,XEvent *e,Boolean *cont)
{
	XButtonEvent *event = (XButtonEvent *) e;
	int buttoncount=0;

	if(e->type == ClientMessage)
		puts("CLIENT MESSAGE FROM BUTTONH");
	if((event->button != Button2) &&
	   (event->button != Button3))
		return;

#ifdef DEBUG
	puts("Got button2/3 click?");
#endif

	do {
		if(w == choicesWidgets[buttoncount]){
			break;
		}
		buttoncount++;
	} while(buttoncount <NUMBEROFCHOICES);

	if(buttoncount == NUMBEROFCHOICES){
		puts("huh? how we get a click on a nonexistant button?");
		quit(NULL, NULL, NULL);
	}

	printsearch(values[buttoncount]);

}


/*	JumpToKanji
 *	callback when Return is pressed in Frequency or #index window
 */
 
int getclosestindex(int target){
	int closestindex = lowestkanji;
	int counter = lowestkanji-1;
	
	while(counter <=highestkanji){
		while(!UseThisKanji(counter)){
			counter++;
			if(counter >highestkanji){
				setstatus("Using closest index available");
				Beep();
				return closestindex;
			}
		}
		if(abs(target - closestindex) > abs(target - counter)){
			closestindex = counter;
			if(closestindex == target)
				break;
		}
		counter++;
	}
	if(target != closestindex){
		setstatus("Using closest index available");
		Beep();
	}
	return closestindex;
}

/* given a frequency rating,
 *	will find the closest usable kanji
 */
int getindexfromfreq(int freq){
	int closestindex = lowestkanji;
	int closestfreq = translations[lowestkanji]->frequency;
	int counter = lowestkanji-1;
	
	while(counter <=highestkanji){
		while(!UseThisKanji(counter)){
			counter++;
			if(counter >highestkanji)
				return closestindex;
		}
		if(abs(closestfreq - freq) >
		   abs((translations[counter]->frequency) - freq) )
		{
			closestindex = counter;
			closestfreq = translations[counter]->frequency;
			if(closestfreq == freq)
				break;
		}
		counter++;
	}
	return closestindex;
}

/* DescribeCurrent()
 *	Sets labels in MAIN window to display difficulty of
 *	reading displayed on the top
 */
void DescribeCurrent(TRANSLATION kanji)
{
	int kindex;

	if(kanji->kanji == NULL) {
		kindex = 0;
	} else {
		kindex = kanji->kanji[0].byte1;
		kindex = kindex <<8;
		kindex |= kanji->kanji[0].byte2;
	}
	if(kindex == NOKANJI) {
		kindex = 0;
	}
			
	SetWidgetNumberval(currentkanjiGrade,(int)kanji->grade_level);
	SetWidgetNumberval(currentkanjiFreq,(int)kanji->frequency);
	SetWidgetHexval(currentkanjiNum,kindex);
}


/* JumpToKanji
 *	This is the MAIN WINDOW "jump to kanji" routine.
 *	The search window has its own.
 *	This handles jump for either direct index, Or Frequency.
 */
void JumpToKanji(Widget w,XEvent *event,String *params,Cardinal *num_parags)
{
	int kindex;

	kindex = GetWidgetNumberval(w);
	/* kindex is actually EITHER index, or
	 *  frequency rating
	 */


	if(w == currentkanjiNum){
		if((kindex <lowestkanji) || (kindex> highestkanji)){
			SetWidgetHexval(w,kindex);
			return;
		} 

		kindex = getclosestindex(kindex);
	} else {
		if(kindex <1){
			setstatus("negative frequencies do not occur");
			/*	SetWidgetNumberval(w,values[truevalue]);*/
			return;			
		}
		kindex = getindexfromfreq(kindex);
	}
	lastpicked = values[truevalue];
	values[truevalue] = translations[kindex];
	DescribeCurrent(translations[kindex]);
	printallchoices();
	printquestion();
	return;

	
}

/* This is a special hack to attempt to force all the widgets to be the 
 * same size.
 * It has the unfortunate side-effect of killing initial auto-size-width
 * for the top-level main window.
 * So if you use this, remember to do a good layout of the top-level window
 * as well. SIGH.
 *
 * The standard creation methods like MakeQuestionWidget are set up to
 * create the forms if they have not already been made here.
 */
void MakeSpecialForms(Widget parent){

	/* We try to set resource so that we will be happy  with EITHER
	 * a Paned parent, or a Form parent.
	 *
	 * Note that if the parent is PanedWidget, these forms will
	 * all be forcibly resized and stretched, ignoring
	 * XawChainXXX
	 */


	kanjiform = XtVaCreateManagedWidget("kanjiform",formWidgetClass, mainform,
			XtNshowGrip, False,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainBottom,
			XtNbottom,XawChainBottom,
			NULL);
	englishform = XtVaCreateManagedWidget("englishform",formWidgetClass,
			mainform,
			XtNfromVert,kanjiform,
			XtNvertDistance,10,
			XtNshowGrip, False,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainBottom,
			XtNbottom,XawChainBottom,
			NULL);
	buttonform = XtVaCreateManagedWidget(
			"buttonform",formWidgetClass,mainform,
			XtNfromVert,englishform,
			XtNvertDistance,15,
			XtNshowGrip, False,
			XtNskipAdjust, True,
			XtNright, XawChainLeft,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainBottom,
			XtNbottom,XawChainBottom,
			NULL);

}



/* MakeCurrent;
 *	Makes window that describes current widget.
 *	Has current kanji grade, frequency, and index listed
 *	(It is now also editable, to enable jumping to a kanji)
 */
Widget MakeCurrent(Widget parent,Widget fromvert){
	Widget gradelabel,freqlabel,numlabel;
	XtAccelerators Accel;

	currentkanjiForm = XtVaCreateManagedWidget(
			"curkanjiForm",boxWidgetClass,parent,
			/*XtNright,XawChainRight,XtNleft,XawChainRight,*/
			XtNtop,XawChainTop, XtNbottom,XawChainTop,
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNfromVert,fromvert,
			XtNorientation,XtEhorizontal,
			NULL);
	gradelabel = XtVaCreateManagedWidget(
			"currgradelabel",labelWidgetClass,currentkanjiForm,
			XtNlabel,"G:",
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			XtNborderWidth,0,
			NULL);
	currentkanjiGrade = XtVaCreateManagedWidget(
			"curkanjiGrade",asciiTextWidgetClass,currentkanjiForm,
			XtNwidth,30, /* match search window */
			XtNstring,"  ",
			XtNdisplayCaret,False,
			NULL);
	freqlabel = XtVaCreateManagedWidget(
			"currfreqlabel",labelWidgetClass,currentkanjiForm,
			XtNlabel,"F:",
			XtNborderWidth,0,
			NULL);
	currentkanjiFreq = XtVaCreateManagedWidget(
			"curkanjiFreq",asciiTextWidgetClass,currentkanjiForm,
			XtNeditType,XawtextEdit,
			XtNstring,"     ",
			XtNwidth,INPUTWIDTH,
			NULL);
	numlabel = XtVaCreateManagedWidget(
			"curNumlabel",labelWidgetClass,currentkanjiForm,
			XtNlabel,"#x:",
			XtNborderWidth,0,
			NULL);

	currentkanjiNum = XtVaCreateManagedWidget(
			"curkanjiNum",asciiTextWidgetClass,currentkanjiForm,
			XtNeditType,XawtextEdit,
			XtNstring,"     ",
			XtNwidth,INPUTWIDTH,
			NULL);

	/* NOTE ! ! we do NOT add a callback, because that is
	 * taken care of by the accelerators.
	 * callback is JumpToKanji
	 */

	Accel = XtParseAcceleratorTable(jumpAccel);
	XtOverrideTranslations(currentkanjiFreq,Accel);
	XtOverrideTranslations(currentkanjiNum,Accel);

	return currentkanjiForm;
}


static char *missedAccel = " \
  <Key>BackSpace:	Accelerator(x)\n \
  <Key>Delete:		Accelerator(x)\n \
";

/* MakeQuestionWidget()
 *	set up widgets for top section of main window
 */
void MakeQuestionWidget(){
	Widget tmplabel, qthrowaway;
	XtAccelerators Accel;

	if(kanjiform == NULL){
		/* normally made in MakeSpecialForms() */
		kanjiform = XtVaCreateManagedWidget(
			"kanjiform",formWidgetClass, mainform,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainBottom,
			XtNbottom,XawChainBottom,
			NULL);
	}

	questionWidget = XtVaCreateManagedWidget("questionlarge",
						  commandWidgetClass,
						  kanjiform,
			XtNshapeStyle,XawShapeRoundedRectangle,
			XtNcornerRoundPercent,50,
			XtNlabel,"",
			XtNwidth,FULLWIDTH,
			XtNencoding,XawTextEncodingChar2b,
			XtNfont,largekfont,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			XtNleft, XawChainLeft, XtNright,XawChainRight,
			NULL);

#ifdef USE_OKU
	ONWidget = XtVaCreateManagedWidget(
			"ONreading",labelWidgetClass,kanjiform,
			XtNlabel,"       ",
			XtNencoding,XawTextEncodingChar2b,
			XtNfont,smallkfont,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			XtNjustify,XtJustifyLeft,
			XtNwidth,KANJIWIDTH * NUMBEROFCHOICES +
					   (NUMBEROFCHOICES *5),
			XtNfromVert,questionWidget,
			NULL);
#endif
	/* now describe current kanji */
	MakeCurrent(kanjiform,questionWidget);

	tmplabel=XtVaCreateManagedWidget(
			"missedlabel",labelWidgetClass,kanjiform,
			XtNfromVert, questionWidget,
			XtNfromHoriz, currentkanjiForm,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNlabel,"missed",
			XtNborderWidth,0,
			/* nasty hardcode.. */
			XtNvertDistance, 10,
			NULL);
	kanjiMissed=XtVaCreateManagedWidget(
			"missedkanji",asciiTextWidgetClass,kanjiform,
			XtNfromVert, questionWidget,
			XtNfromHoriz, tmplabel,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			/*XtNlabel,"00/00/00",*/
			/* hardcode numbers, becuase ascitxtwidget is wierd*/

			XtNwidth, (int)(INPUTWIDTH *1.5) ,
			
			XtNdisplayCaret,False,
			XtNvertDistance, 10,
			NULL);

	/* Xaw layout is a black art. This is solely for spacing */
/*
	qthrowaway=XtVaCreateManagedWidget(
			"qthrowaway",asciiTextWidgetClass,kanjiform,
			XtNfromVert, questionWidget,
			XtNfromHoriz, kanjiMissed,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNlabel,"0",
			XtNdisplayCaret,False,
			NULL);
*/
	
	Accel = XtParseAcceleratorTable(missedAccel);
	XtOverrideTranslations(kanjiMissed,Accel);

}

/* MakeEnglishButtons:
 * Just that. initialize the english buttons that display the possible
 * guesses.
 */
void MakeChoicesButtons(){
	int i;


	if(englishform==NULL) {
		/* See also MakeSpecialWidgets() */
		englishform = XtVaCreateManagedWidget(
			"englishform",formWidgetClass, mainform,
			XtNfromVert,kanjiform,
			XtNvertDistance,5,
			XtNright, XawChainRight,
			XtNleft,  XawChainLeft,
			XtNtop,XawChainBottom,
			XtNbottom,XawChainBottom,
			NULL);
	}

	for(i=0;i<NUMBEROFCHOICES;i++){
		char labl[20];
		sprintf(labl,"english%d",i);

		if(i==0){
		   choicesWidgets[0]=XtVaCreateWidget(
			labl,commandWidgetClass,englishform,
			XtNwidth,FULLWIDTH,
			XtNright,XawChainRight,
			XtNleft,XawChainLeft,
			XtNtop,XawChainTop,
			XtNbottom,XawChainTop,
			XtNfont,largekfont,
			XtNvertDistance,10,
			XtNshapeStyle,XawShapeRoundedRectangle,
			XtNcornerRoundPercent,50,
			NULL);
		} else {
		   choicesWidgets[i]=XtVaCreateWidget(
			labl,commandWidgetClass,englishform,
			XtNwidth,FULLWIDTH,
			XtNright,XawChainRight,	XtNleft,XawChainLeft,
			XtNtop,XawChainTop, XtNbottom,XawChainTop,
			XtNfont,largekfont,
			XtNfromVert,choicesWidgets[i-1],
			XtNshapeStyle,XawShapeRoundedRectangle,
			XtNcornerRoundPercent,50,
			NULL);
		}
		XtAddEventHandler(choicesWidgets[i],ButtonPressMask,False,
				  handle_button,NULL);
		XtAddCallback(choicesWidgets[i],
			      XtNcallback,choicescallback,(XtPointer) i);

	}
	XtManageChildren(choicesWidgets,NUMBEROFCHOICES);
}

void MakeButtons(){
	Widget w[7];

	if(buttonform==NULL){
		/* See also MakeSpecialForms(). sigh */
		buttonform = XtVaCreateManagedWidget(
			"buttonform",formWidgetClass,mainform,
			XtNfromVert,englishform,
			XtNvertDistance,15,
			XtNright, XawChainLeft,	XtNleft,  XawChainLeft,
			XtNtop,XawChainBottom,	XtNbottom,XawChainBottom,
			NULL);
	}

	w[0] = XtVaCreateWidget("quit",commandWidgetClass,buttonform,
			XtNlabel,"quit",
			XtNshapeStyle,XawShapeEllipse,
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
			NULL);

	w[1] = XtVaCreateWidget("cheat",commandWidgetClass,buttonform,
			XtNfromHoriz,w[0],
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
			NULL);

	w[2]= XtVaCreateManagedWidget("back",commandWidgetClass,
			buttonform,
			XtNlabel,"prev. char",
			XtNfromHoriz,w[1],
			/*XtNshapeStyle,XawShapeEllipse,*/
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
			NULL);

	w[3]= XtVaCreateManagedWidget("log",commandWidgetClass,
			buttonform,
			XtNlabel,"Log",
			XtNfromHoriz,w[2],
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
			/*XtNshapeStyle,XawShapeEllipse,*/
			NULL);

	w[4] = XtVaCreateWidget("options",commandWidgetClass,
			buttonform,
			XtNlabel,"options",
			XtNfromHoriz,w[3],
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
			XtNshapeStyle,XawShapeEllipse,
			NULL);

	w[5]= XtVaCreateManagedWidget("search",commandWidgetClass,
			buttonform,
			XtNlabel,"Search",
			XtNfromHoriz,w[4],
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
			XtNshapeStyle,XawShapeEllipse,
			NULL);
	w[6]= XtVaCreateManagedWidget("learn",commandWidgetClass,
			buttonform,
			XtNlabel,"Learn",
			XtNfromHoriz,w[5],
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
			XtNshapeStyle,XawShapeEllipse,
			NULL);


	statusline = XtVaCreateManagedWidget("status",labelWidgetClass,
					     buttonform,

			XtNlabel,"             Welcome to kanjidrill             ",

			XtNborderWidth,2,
			XtNvertDistance,STATUSDISTANCE,
			XtNfromVert,w[0],
			XtNleft, XawChainLeft, XtNright,XawChainLeft,
			XtNtop,XawChainBottom, XtNbottom,XawChainBottom,
		      NULL);

	XtAddCallback(w[0],XtNcallback,quit,NULL);
	XtAddCallback(w[1],XtNcallback,cheatcallback,NULL);
	XtAddCallback(w[2],XtNcallback,BackCallback,NULL);
	XtAddCallback(w[3],XtNcallback,MakeLog,NULL);
	XtAddCallback(w[4],XtNcallback,OptionsCallback,NULL);
	XtAddCallback(w[5],XtNcallback,SearchCallback,NULL);
	XtAddCallback(w[6],XtNcallback,LearnCallback,NULL);
	
	XtManageChildren(w,7);
}


void initfonts(){
	char LargeKname[100],SmallKname[100],Efontname[100];
/*	Widget tmplabel;*/
/*	String tmpstring;*/

	/* Sigh, okay this is ugly, tell me a better way...*/
	/* Hell, tell me a way that WORKS, dammit... */
	/*
	tmplabel=XtVaCreateManagedWidget("tmplabel", labelWidgetClass,toplevel,
				       NULL);
	XtVaGetValues(tmplabel, "XtNfont", &defaultfont, NULL);
	if(defaultfont==NULL){
		puts("ERROR: cannot find default font?!!");
		exit(0);
	}
	XtDestroyWidget(tmplabel);
	*/
	
	GetXtrmString("kanjifont","Kanjifont",LargeKname);
	GetXtrmString("smallkanji","Smallkanji",SmallKname);
	GetXtrmString("englishfont","Englishfont",Efontname);

/*	GetXtrmString("font", "Font", tmpstring);*/

#ifdef DEBUG
	printf("kanjifont from resources is \"%s\"\n",LargeKname);
	printf("smallkanjifont from resources is \"%s\"\n",SmallKname);
	printf("regular font from resources is \"%s\"\n",Efontname);
#endif
	largekfont = XLoadQueryFont(display,LargeKname);
	smallkfont = XLoadQueryFont(display,SmallKname);
	englishfont  = XLoadQueryFont(display,Efontname);
/*	defaultfont =  XLoadQueryFont(display,tmpstring);*/

	if(largekfont == NULL){
		fprintf(stderr,"could not load large kanji font\n");
		exit(0);
	}
	if(smallkfont == NULL){
		fprintf(stderr,"could not load small kanji font\n");
		exit(0);
	}
	if(englishfont == NULL){
		fprintf(stderr,"could not load english font??\n");
		exit(0);
	}
	

}

static char *guessAccel = " \
  Ctrl<Key>q:	quit()\n \
  <Key>1:		guess-meaning(0)\n \
  <Key>2:		guess-meaning(1)\n \
  <Key>3:		guess-meaning(2)\n \
  <Key>4:		guess-meaning(3)\n \
  <Key>5:		guess-meaning(4)\n \
  <Key>6:		guess-meaning(5)\n \
  <Key>7:		guess-meaning(6)\n \
  <Key>8:		guess-meaning(7)\n \
  <Key>9:		guess-meaning(8)\n \
  Shift<Key>c:		Accelerator(C)\n \
  <Key>c:		Accelerator(c)\n \
  Shift<Key>e:		Accelerator(E)\n \
  <Key>e:		Accelerator(e)\n \
  Shift<Key>k:		Accelerator(K)\n \
  <Key>k:		Accelerator(k)\n \
  Any<Key>l:		Accelerator(l)\n \
  Shift<Key>m:		Accelerator(M)\n \
  <Key>m:		Accelerator(m)\n \
  <Key>n:		Accelerator(n)\n \
  Shift<Key>o:		Accelerator(O)\n \
  <Key>F13:		Accelerator(O)\n \
  <Key>o:		Accelerator(o)\n \
  <Key>p:		Accelerator(b)\n \
  Any<Key>s:		Accelerator(s)\n \
  Shift<Key>t:		Accelerator(T)\n \
  <Key>u:		Accelerator(u)\n \
  <Key>F19:		Accelerator(s)\n \
  Shift<Key>a:		Accelerator(S0)\n \
  Shift<Key>1:		Accelerator(S1)\n \
  Shift<Key>2:		Accelerator(S2)\n \
  Shift<Key>3:		Accelerator(S3)\n \
  Shift<Key>4:		Accelerator(S4)\n \
  Shift<Key>5:		Accelerator(S5)\n \
  Shift<Key>6:		Accelerator(S6)\n \
  Shift<Key>7:		Accelerator(S7)\n \
  Shift<Key>=:		Accelerator(S7)\n \
  Shift<Key>+:		Accelerator(S7)\n \
  Shift<Key>KP_Add:	Accelerator(S7)\n \
  <Message>WM_PROTOCOLS: delete-window()\n \
  <Message>WM_DELETE_WINDOW: delete-window()\n \
  ";
/* The 'Shift=' thing is a hack, because usually the '+' is actually
 * the '=' key plus shift
 */

/* Accelerator()
 *	A jumping-off point for keyboard accelerators, as set above.
 *	This handles multiple widgets, so it can get messy.
 *	WARNING: It seems you can only have a single accelerator table
 *	for the ENTIRE PROGRAM. Not on a window-by-window basis.
 *	We check 'w' for pointer to the window involved, if needed
 *
 *	Adding a new key in here also needs a line added in an Accel list,
 *	like guessAccel, above.
 */
void Accelerator(Widget w, XEvent *event,String *params,Cardinal *num_params){
	int int_store;
	char *param = *params;
	
	if(*num_params <1){
		puts("Warning: Accelerator function must have one argument!");
		return;
	}
	if(*num_params >1){
		printf("Warning: Accelerator functions take one argument, and one only\n");
	}


	switch(param[0]){
		case 'b':
			BackCallback(NULL,NULL,NULL);
			break;
		case 'c':
			cheatcallback(NULL,NULL,NULL);
			break;
		case 'C':
			supercheat();
			break;
		case 'e':
			ChangeMode(NULL,(XtPointer) GUESS_ENGLISH,NULL);
			break;
		case 'E':
			ChangeQuestion(NULL,(XtPointer) GUESS_ENGLISH,NULL);
			break;
		case 'k':
			ChangeMode(NULL,(XtPointer) GUESS_KANJI,NULL);
			break;
		case 'K':
			ChangeQuestion(NULL,(XtPointer) GUESS_KANJI,NULL);
			break;
		case 'l':
			LearnCallback(NULL,(XtPointer) NULL,NULL);
			break;
		case 'm':
			ChangeMode(NULL,(XtPointer) GUESS_KANA,NULL);
			break;
		case 'n':
			if(w==learn_popup){
				LearnNewChar(w, (XtPointer)True,NULL);
			}
			break;
		case 'N':
			if(w==learn_popup){
				LearnNewChar(w, False,NULL);
			}
			break;
		case 'M':
			ChangeQuestion(NULL,(XtPointer) GUESS_KANA,NULL);
			break;
		case 'o':
			ordercallback(orderbutton,NULL,NULL);
			break;
		case 'O':
			OptionsCallback(NULL,NULL,NULL);
			break;
		case 'u':
			UsefileCallback(usefilebutton,NULL,NULL);
			break;
		case 's':
			SearchCallback(NULL,NULL,NULL);
			break;

		/* handle two-digit accelerator code.
		 * This is actually S[123456+]
		 */
		case 'S':
			param+=1;
			int_store = (*param)-'0';
			GradeCallback(gradeButtons[int_store],
				      (XtPointer) int_store,NULL);
			break;

		case 'T':
			TimerCallback(NULL,NULL,NULL);
			break;
		case 'x':
			if(w== kanjiMissed){
				ClearMissed();
				break;
			}
			break;
		default:
			printf("DEBUG: unrecognized Accelerator '%c'\n",
			       param[0]);
	}
}



/* delete_calback
 *	sole purpose is to handle window deletion. (like)<Message>WM_PROTOCOLS
 *   still technically selected, via Actions.? bizzare, and irritating that we
 *   have to use TWO METHODS to deal with this insanity. sigh.
 *
 * EXCEPT... This one seems to be to simply notify us.
 * If we don't register this, the client dies. But now that
 * we register this via XtAugmentTranslations... we dont actually
 * have to do anything. Mindbogglingly stupid, really.
 */

void 
delete_callback(Widget w, XEvent *event,String *params,Cardinal *num_params)
{

	if(event->xclient.data.l[0] == delete_message){
		/*
		handle_delete(w, NULL, event, NULL);
		*/
		return;
	}
	puts("Got NON-delete event, in delete_callback?");

}

void quitaction(Widget w, XEvent * e, String *p, Cardinal *c)
{
	quit(NULL, NULL, NULL);
}


/* deliberately a "nop". used primarily to make the RETURN key
 * do nothing, when we want to disable it.
 */
void do_nothing(Widget w, XEvent * e, String *p, Cardinal *c)
{
	return;
}

/* Different widgets may have different "Accelerator" tables,
 * parsed by 
 * but all of them have to hook through this shared Actions list
 */
static XtActionsRec kdrillActionList[] = {
	{ "quit",		quitaction},
	{ "update-frequency",	UpdateFrequency},
	{ "update-timeout",	UpdateTimeout},
	{ "do-find",		DoFind},
	{ "stroke-search",	DoStrokeSearch}, /* ignore warning*/
	{ "jump-to-kanji",	JumpToKanji},
	{ "guess-meaning",	Guessvalue},
	{ "Accelerator",	Accelerator},
	{ "delete-window",	delete_callback},
	{ "do-nothing",		do_nothing},
};
	
XtAccelerators AllAccel;
void handle_delete(Widget,XtPointer,XEvent *,Boolean *);

/* MakeWidgets()
 *	Highest level routine for making ALL the widgets.
 *	This is THE starting point for making widgets
 *	(even the popup stuff actually gets created through here)
 */


void MakeWidgets(){

#ifdef DEBUG
	puts("Starting MakeWidgets");
#endif

	/* I suppose I shouldn't hard-code window-width and height..
		but it makes things easier for now.
	*/

#ifdef USEFORMFORTOP /* not currently used */
	mainform = XtVaCreateManagedWidget("kdrill",formWidgetClass,
					   toplevel,
			XtNvSpace,16,
			XtNhSpace,10,
			NULL);
#else
	/* Note: This automatically stretches out the widgets to be
	 * the full width of the window
	 */

	mainform = XtVaCreateManagedWidget("kdrill",panedWidgetClass,
					   toplevel,
			NULL);
#endif

	initfonts();

	XtAppAddActions(Context,kdrillActionList,XtNumber(kdrillActionList) );
	AllAccel = XtParseAcceleratorTable(guessAccel);

	/*XtOverrideTranslations(mainform,AllAccel);*/
	XtAugmentTranslations(mainform,AllAccel);

	MakeSpecialForms(mainform);

	MakeQuestionWidget();
	MakeChoicesButtons();

	MakeOptionsPopup();
	MakeSearchPopup();
	MakeLearnPopup();
	MakeMulti();
	MakeButtons();

#ifdef DEBUG
	puts("Ending MakeWidgets");
#endif
}




syntax highlighted by Code2HTML, v. 0.9.1