#include <stdlib.h>	/* for srand48() */
#include <unistd.h>	/* for "access()" */
#include <stdio.h>

#include <limits.h>	/* for POSIX_PATH_MAX */

#include <Xatom.h>
#include <Xfuncs.h>	/* handles bzero redefine stuff */
#include <Xos.h>
#include <Intrinsic.h>
#include <StringDefs.h>
#include <Shell.h>
#include <Xaw/Command.h>
#include <Xaw/Label.h>
#include <Xaw/Form.h>
#include <Composite.h>


#include "defs.h"
#include "externs.h"
#include "game.h"
#include "grades.h"
#include "options.h"
#include "searchwidgets.h"
#include "widgets.h"
#include "timeout.h"

#include "icon_xbm"

int lowfrequency=0,highfrequency=0;

char *usefile=NULL;	/* global pointer that indicates if usefile is
			 * AVAILABLE, not neccessarily that it is used
			 */
char usefilename[100];

Atom wm_message,delete_message;


/*
 * This array has "fallback resources", in case
 * the normal "KDrill" resource file is not present.
 * Note that it is an either/or situation.
 * If there is a KDrill app-resources file on the system,
 * these fallback resources WILL NOT BE LOOKED AT !!!
 *
 *  If you add something to this list, consider adding it to
 *  SaveConfig() as well!!
 *  And dont forget that you have to use SetXtrmXXXX() routines
 *  to have the values available for SaveConfig() also!!
 *
 */
static char *fallback[] = {
	"KDrill.options_popupx:		0",
	"KDrill.options_popupy:		-200",
	"KDrill.search_popupx:		400", /* should really be precise,
						but... */
	"KDrill.search_popupy:		0",
	"KDrill.notallT:	0",
	"KDrill.noBell:		0",
	"KDrill.nousefile:	1",
	"KDrill.usefile:	.kanjiusefile", 
	DICTLOCATION,	/* change this value in Imakefile !!*/
	EDICTLOCATION,	/* change this value in Imakefile !!*/
	RADLOCATION,	/* change this value in Imakefile !!*/
	"KDrill.kanjifont:	-jis-*--24*jisx0208*",
	"KDrill.smallkanji:	-jis-*--16*jisx0208*",
	"KDrill.englishfont:	fixed",
	"KDrill.gradelevel:	0",
	"KDrill.guessmode:	english",
	"KDrill.questionmode:	kanji",
	"KDrill.romajiswitch:	0",
	"KDrill.lowfrequency:	0",
	"KDrill.highfrequency:	0",
	"KDrill.showinorder:	0",
	"KDrill.timersec:	7",
	"KDrill.logfile:	kdrill.log",
	NULL
};

/* command line arguments should set the appropriate resources.. so we can
 * pull them out when wanted
 */
static XrmOptionDescRec optionDescList[] = {
	{"-notallT",	".notallT",XrmoptionNoArg,"1"},
	{"-usefile",	".usefile",	XrmoptionSepArg,(caddr_t) NULL},
	{"-nousefile",  ".nousefile",	XrmoptionNoArg, "1"},
	{"-kdictfile",	".kdictfile",	XrmoptionSepArg,(caddr_t) NULL},
	{"-edictfile",	".edictfile",	XrmoptionSepArg,(caddr_t) NULL},
	{"-radkfile",	".radkfile",	XrmoptionSepArg,(caddr_t) NULL},
	{"-englishfont",".englishfont",	XrmoptionSepArg,(caddr_t) NULL},
	{"-kanjifont",	".kanjifont",	XrmoptionSepArg,(caddr_t) NULL},
	{"-smallkanji",	".smallkanji",	XrmoptionSepArg,(caddr_t) NULL},
	{"-noBell",     ".noBell",	XrmoptionNoArg, "1"},
	{"-guessmode",	".guessmode",	XrmoptionSepArg,(caddr_t) NULL},
	{"-questionmode",".questionmode",XrmoptionSepArg,(caddr_t) NULL},
	{"-romajiswitch",   ".romajiswitch",    XrmoptionNoArg,"1"},
	{"-showinorder",   ".showinorder",    XrmoptionNoArg,"1"},
	{"-gradelevel", ".gradelevel",  XrmoptionSepArg,(caddr_t) NULL},
	{"-lowfrequency",	".lowfrequency",XrmoptionSepArg,(caddr_t) NULL},
	{"-highfrequency",	".highfrequency",XrmoptionSepArg,(caddr_t) NULL},
	{"-logfile",	".logfile",	XrmoptionSepArg,(caddr_t) NULL},
	
	
};



/* handle_delete
 *	Its sole purpose is to handle WM_DELETE messages.
 *	These days, we want to only CLOSE windows that aren't the
 *	main one.
 *
 */
void
handle_delete(Widget w,XtPointer closure,XEvent *event,Boolean *cont)
{
	XClientMessageEvent *cevent = (XClientMessageEvent *) event;

	if(cevent->type != ClientMessage) return;
	if(cevent->message_type != wm_message) return;
	if(cevent->data.l[0] != delete_message)  return;

	if(w == toplevel){
		quit(NULL, NULL, NULL);
	}

#ifdef DEBUG
	puts("In handle_delete...");
	if(XtIsTopLevelShell(w)){
		puts("   IS a top level shell");
	}
	if(XtIsShell(w)){
		puts("   IS a  shell");
	}
	if(XtIsTransientShell(w)){
		puts("   IS a 'transient' shell");
	}


	if(XtIsTopLevelShell(XtParent(w))){
		puts("   PARENT is a top level shell");
	}
	if(XtIsShell(XtParent(w))){
		puts("   PARENT is a  shell");
	}
	if(XtIsTransientShell(XtParent(w))){
		puts("   PARENT is a 'transient' shell");
	}

	
#endif /* DEBUG */


	/* Problem here: there are three types of windows we have
	   to deal with:
	   "Option window" type  (shell, transient)
	   multi-match window  (toplevel, shell)
	   seach window (toplevel, shell: but DIFFERENT from multi somehow)
	   XtPopdown works for the first two, but only UnmapWidget works
	   for last kind.
	   The only difference I can see, is that the search window
	   has "toplevel" as its parent, which is not strictly
	   speaking just a window. It is what XtVaAppInitialize() returns.
	   It CONTAINS a window, but is not merely a window.
	   searchwindow is made that way, to remain open, when
	   the main window is iconified.
	   I *could* just special-case it. But i hate special cases.
	*/
	XtPopdown(w);
	if(isMapped(w)){
		/* if it is still showing.. try harder! */
		XtUnmapWidget(w);
	}

}

/* initgc:
 *	Initialises global gc values.
 *      We don't really need this any more. But
 *	GC's are good to have, I suppose.
 */
void initgc(){

	gc =  XCreateGC(display,mainwindow,0,NULL);
	cleargc = XCreateGC(display,mainwindow,0,NULL);

	XSetForeground(display,gc,black);
	XSetBackground(display,gc,white);
	XSetForeground(display,cleargc,white);
	XSetBackground(display,cleargc,black);

}

/* GetOptions
 *	get resource and command line options.
 *	(The nice thing is that thanks to Xt, commandline options
 *	 get auto-translated to resources already
 */

void GetOptions(){
	int tmpnumber;
	char tmpstr[100];


	/* set grade bits appropriately */
	GetXtrmString("gradelevel","Gradelevel",tmpstr);
	parsegrades(tmpstr);

	switchKanaEnglish = !GetXtrmBoolean("notallT","NotallT");
	/* default of nousefile is FALSE. which means
	 * useUsefile defaults to TRUE
	 */
	useUsefile = !GetXtrmBoolean("nousefile","Nousefile");

	doBell = !GetXtrmBoolean("noBell","NoBell");
	showinorder = GetXtrmBoolean("showinorder","Showinorder");

	lowfrequency = GetXtrmNumber("lowfrequency","Lowfrequency");
	if((lowfrequency <0) || (lowfrequency >=MAXTRANSLATIONSALLOWED))
		lowfrequency = 0;
	highfrequency = GetXtrmNumber("highfrequency","Highfrequency");
	if((highfrequency <0) || (highfrequency >=MAXTRANSLATIONSALLOWED))
		highfrequency = 0;

	tmpnumber = GetXtrmNumber("timersec","Timersec");
	setTimeoutLen(tmpnumber);
	

	GetXtrmString("guessmode", "Guessmode", tmpstr);
	if(strcmp(tmpstr, "english")==0){
		choicesmode = GUESS_ENGLISH;
	}else if(strcmp(tmpstr, "kanji")==0){
		choicesmode = GUESS_KANJI;
	} else{
		choicesmode = GUESS_KANA;
	}
	GetXtrmString("questionmode", "Questionmode", tmpstr);
	if(strcmp(tmpstr, "english")==0){
		questionmode=GUESS_ENGLISH;
	} else if (strcmp(tmpstr, "kanji")==0){
		questionmode=GUESS_KANJI;
	} else{
		questionmode=GUESS_KANA;
	}

	if( GetXtrmBoolean("romajiswitch","Romajiswitch"))
		romajiswitch = 1;

}


/* this routine is solely for internalizing various
 *  "Atoms" neccessary to handle the stupid WM_DELETE_WINDOW
 *  message
 */
void setup_deletewindow(Widget winwidget)
{

	/* Must wait for the window to actually appear. sigh.*/
	XFlush(display);
	XSync(display,False); /* This should be redundant, but... */

	if(wm_message==(Atom)NULL){
		wm_message=XInternAtom(display,"WM_PROTOCOLS",False);
		delete_message=XInternAtom(display,"WM_DELETE_WINDOW",False);
		if (wm_message == (Atom) NULL) {
			perror("unable to create wm_message property");
			exit(1);
		}
		if (delete_message == (Atom) NULL) {
			perror("unable to create delete property");
			exit(1);
		}
	}
	XtAddEventHandler(winwidget, NoEventMask, True,
			     handle_delete, (XtPointer)NULL);

	XtAugmentTranslations(winwidget, AllAccel);

	/* I haven't figured out why we would be called when this is 0.
	 * Seems to be a strange bug in X. sigh.
	 */ 
	if(XtWindow(winwidget)==0){
		/*printf("XtWindow is %d\n",XtWindow(winwidget));*/
		return;
	}

        XChangeProperty(display, XtWindow(winwidget),
			wm_message, XA_ATOM, 32, PropModeReplace, 
                        (unsigned char *) &delete_message, 1);


}

#ifndef _POSIX_PATH_MAX
#define _POSIX_PATH_MAX 1024
#endif

/* If we have the appropriate functions (X11R6?)
 * load up our own special user-specific xresources file
 * We need the global 'display' set
 */
void init_xdb()
{
	char XFileName[_POSIX_PATH_MAX];
	XrmDatabase globaldb;

	sprintf(XFileName,"%s/.kdrill", homedir);
	globaldb=XrmGetDatabase(display);

	/* override "global" prefs with user specific ones */
	/* That way, we try to keep working, even if prefs file
	 * is screwed up
	 */
	XrmCombineFileDatabase(XFileName, &globaldb, True);
}

/* initstuffs:
 *	calls the various init routines to setup
 *	GCs, fonts, dictionaries, and widgets
 *	(But initializing the translations is done later)
 */

static Pixmap iconpixmap;

void initstuffs(int *argc,char *argv[])
{
	srand48 (time(NULL));

	bzero(translations, sizeof(struct translationstruct *) * MAXTRANSLATIONSALLOWED);
	lowestkanji = highestkanji = 0;

	homedir = (char *) getenv("HOME");
	if(homedir == NULL){
		puts("WARNING: no 'HOME' environment variable");
		puts("Faking with '.' instead");
		homedir=".";
	}

	toplevel = XtVaAppInitialize(&Context,"KDrill",
 				   optionDescList,XtNumber(optionDescList),
 				   argc,argv,fallback,
 				   NULL,NULL);

	if(*argc >1){
		usage();
	}

	display = XtDisplay(toplevel);

	if(display == NULL) perror("NULL DISPLAY");

#ifndef NOXRMSAVE
	init_xdb();
#endif /*NOXRMSAVE*/


	/* Get command line options... yeah, we should do this in a
	 *  struct, in one go... but some things need to be initalized
	 * later
	 */

	white = XWhitePixel(display,0);
	black = XBlackPixel(display,0);

	GetOptions();

	MakeWidgets();

	XtRealizeWidget(toplevel);

	mainwindow = XtWindow(toplevel);
	if(mainwindow == 0) perror("NULL WINDOW");
	
	setup_deletewindow(toplevel);

	iconpixmap = XCreateBitmapFromData(display,mainwindow,
			   (char *)icon_xbm_bits,
			   icon_xbm_width,icon_xbm_height);

	XtVaSetValues(toplevel,XtNiconName,"kdrill",
			XtNiconPixmap,iconpixmap,NULL);

	/* Why doesnt this work? It should... ? */
	XtVaSetValues(search_popup,XtNiconName,"kdrill_search",
			XtNiconPixmap,iconpixmap,NULL);


	initgc();

}

