/* This file is a whole module unto itself.
 * It's like an "object", that will store up to MAXMULTI different kanji
 *  translations.
 *    (or at least pointers thereof)
 *
 * User can pick whether these translations will be displayed in terms
 * of kanji, kana, or english.
 * Clicking on one will set the search window to display that entry.
 *
 * Basic functions from the outside:
 *  void MakeMulti();                      [create X Widget]
 *  void ShowMulti();                      [ make window visible ]
 *  void AddMultiTranslation(TRANSLATION); [ add to current list]
 *  void ClearAllMulti();
 *  int getMultiMax();   [ return value of MAXMULTI define]
 *  int getMultiCount(); [ return number of translations in current list]
 *
 * And one PRIVATE function that is public because of callbacks:
 *   multicallback(int)
 *
 *  Note: it is expected behaviour that routines outside this file,
 *  will call AddMultiTranslation() a buncha times, but then
 *  call ShowMulti() when they are all done adding. This allows
 *  us to put cleanup routines in ShowMulti()
 */

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

#include <Shell.h>
#include <Xaw/Command.h>
#include <Xaw/Label.h>
#include <Xaw/Form.h>
#include <Xaw/Box.h>
#include <Xaw/Viewport.h>

#include <stdio.h> /* shouldnt be neccessary, but it is. sigh. */
#include "defs.h"
#include "externs.h"
#include "game.h"
#include "init.h"
#include "utils.h"
#include "log.h"
#include "readfile.h"
#include "learn.h"

#include "searchwidgets.h"


/* MAXMULTI == max translation lines we will hold in multi-window */
/* If external routine wants to know this value, call getMultiMax() */
#define MAXMULTI 200 




static Widget      transwin[MAXMULTI];       /* user clicks to select translation*/
static TRANSLATION transptrs[MAXMULTI];	     /* info in each transwin */
static Widget      usefiletoggles[MAXMULTI]; /* is each one in usefile? */

static int transcount=0;
static int overflow=0; /* number of added translations over MAXMULTI */


Widget multikanab, multikanjib, multienglishb;
Widget multiclose;
 
static int displaymode=GUESS_ENGLISH;

static Widget multi_popup;
static Widget multi_form;
static Widget multi_viewport;
static Widget multi_status;


void RefreshMultiLabels();
void AddMultiTranslation(TRANSLATION nt);


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


void ShowMulti(){
	static int doneinit=0;
	XtPopup(multi_popup, XtGrabNone);
	if(doneinit==0){
		setup_deletewindow(multi_popup);
		doneinit=1;
	}
	XawFormDoLayout(multi_form,True);
}

void HideMulti(){
	XtPopdown(multi_popup);
}

/* resizing isn't behaving. so I'll force it to never go too small.
 * Hopefully.
 * Always have string more than 30 chars long. space-pad the end.
 */
static void setmultistatus(char *string){

#define FORCEWIDE

#ifdef FORCEWIDE
	char statusbuff[50];
	int stringlen=strlen(string);
	if(stringlen>49)
		stringlen=49;
		
	if(multi_status==NULL)
		return;

	strcpy(statusbuff,
	       "                                            ");
	bcopy(string, statusbuff, stringlen);
	XtVaSetValues(multi_status, XtNlabel,statusbuff, NULL);
#else /* STUPID */
	XtVaSetValues(multi_status, XtNlabel,string, NULL);
#endif /* STUPID */
}


void ClearAllMulti(){
	int tc;

	overflow=0;

/*	for(tc=transcount -1; tc>=0; tc--){*/
	for(tc=MAXMULTI -1; tc>=0; tc--){

		XUnmapWindow(XtDisplay(transwin[tc]), 
	           XtWindow(transwin[tc]));
		XtVaSetValues(usefiletoggles[tc], XtNfromVert, NULL, NULL);

/*XXX		XUnmapWindow(XtDisplay(usefiletoggles[tc]),
	           XtWindow(usefiletoggles[tc]));
		XtVaSetValues(transwin[tc], XtNfromVert, NULL, NULL);
*/

	}

	bzero(transptrs, sizeof(transptrs));

	transcount=0;

	/* Scroll up to top. Otherwise, it gets stuck at prev pos. */
	XawViewportSetCoordinates(multi_viewport, 0, 0);

	setmultistatus("No matches");
}

/* This callback handles both "Change what mode you display", and
 * 'Hey, show me this one in detail'
 */
void multicallback(Widget button, XtPointer data, XtPointer call_data){

	int newmode=-1;
	int buttoncount;

	if(button==multiclose){
		HideMulti();
		return;
	}
	if(button==multikanab){
		newmode=GUESS_KANA;
	}
	if(button==multikanjib){
		newmode=GUESS_KANJI;
	}
	if(button==multienglishb){
		newmode=GUESS_ENGLISH;
	}

	if(newmode!=-1){
		/*
		 * disable this optimization, becuase we want
		 * romaji/kana to switch more easily
		if(newmode==displaymode)
			return;
		*/
		displaymode = newmode;
		RefreshMultiLabels();
		return;
	}

	for(buttoncount=0;buttoncount<transcount; buttoncount++){
		if(button== transwin[buttoncount]){
			printsearch(transptrs[buttoncount]);
			return;
		}
	}

	puts("Error: multicallback got click on unrecognized button?");
	
}

/* This handles a click on a usefile toggle button, 
 * in the multikanji popup.
 * Parallel function to ToggleUsefile()
 */
void multiUcallback(Widget button, XtPointer data, XtPointer call_data){
	TRANSLATION trans=transptrs[(int)data];
	int kindex=trans_to_index(trans);

	SetUseKanji(kindex,!InUsefile(kindex));

	if(InUsefile(kindex)){
		HighlightButton(button);
	} else {
		UnhighlightButton(button);
	}

	/* Just in case this is for the currently displayed search line*/
	UpdateSearchlabels();
	DisplayLearnChar();

	CountKanji();
}



/* just create the line-item buttons, not "everything" */
/* We pre-create all the buttons, and hide them when not in use.*/
void createallmulti(){
	Widget newbutton,newu;
	Widget prevbutton=NULL;
	int formwidth=GetWidgetWidth(multi_popup);
	char buttname[10],uname[10];
	int transcount;


	if(formwidth>50){
		formwidth-=50;
	}

	
	for(transcount=0;transcount<MAXMULTI;transcount++){
		sprintf(buttname, "multi%x\n", (unsigned int)transcount);
		sprintf(uname, "multiU%x\n", (unsigned int)transcount);

		if(transcount>0){
			/* we use this for XtNfromVert offset */
			prevbutton=transwin[transcount-1];
		}

		newbutton=XtVaCreateManagedWidget(buttname, commandWidgetClass,
			multi_form,
			XtNfromVert,prevbutton,
			XtNwidth, formwidth,
			XtNshapeStyle,XawShapeRoundedRectangle,
			XtNcornerRoundPercent,20,
			/* this is to get the height always right*/
			XtNencoding,XawTextEncodingChar2b,
			XtNfont,largekfont,
			XtNleft,XawChainLeft,
			XtNright,XawChainRight,
			XtNlabel,"\0\0\0\0",
			NULL);

		XtAddCallback(newbutton, XtNcallback, multicallback, NULL);
		transwin[transcount]=newbutton;

		newu=XtVaCreateManagedWidget(buttname, commandWidgetClass,
			multi_form,
			XtNfromVert,prevbutton,
			XtNfromHoriz,newbutton,
			XtNleft,XawChainRight,
			XtNright,XawChainRight,
			XtNencoding,XawTextEncoding8bit,
			XtNfont,englishfont,
			XtNlabel,"u",
			NULL);

		XtAddCallback(newu, XtNcallback, multiUcallback, (XtPointer)transcount);
		usefiletoggles[transcount]=newu;

	}

	XawFormDoLayout(multi_form, True);

	/* Want to do this here.
	 * But need to do this at end of MakeMulti (our calling function)
	 *  instead
	 */
	/* ClearAllMulti(); */
}



#define VWIDTH 400
#define VHEIGHT 300

/* called ONCE at start of program*/
void MakeMulti(){
	Widget multitop, buttonform;
					       

	multi_popup=XtVaCreatePopupShell("multi_popup",
		topLevelShellWidgetClass,
		search_popup,
		XtNwidth, 350,
		XtNheight, 500,
		NULL);


	multitop=XtVaCreateManagedWidget("multitopform",
					     formWidgetClass,
					     multi_popup,
					     NULL);

	multi_viewport=XtVaCreateManagedWidget("multiport",
					viewportWidgetClass,
					multitop,
					XtNforceBars, True,
					XtNallowHoriz,False,
					XtNallowVert,True,
					XtNwidth, VWIDTH,
					XtNheight, VHEIGHT,
					XtNbottom,XawChainBottom,
					XtNright,XawChainRight,
					XtNleft,XawChainLeft,
					NULL);

	/* This is what holds the multiple buttons, that show
	 * all the different matches to a search
	 * YES, we DO need to seed this with an initial height, otherwize
	 * we get irritating behavior the first time we are used.
	 */
	multi_form=XtVaCreateManagedWidget("multikanjiform",
					formWidgetClass,
					/*boxWidgetClass,*/
					multi_viewport,
					NULL);

	/* make all the little things inside multi_form */
	createallmulti();


	multi_status=XtVaCreateManagedWidget("multistatus",
			labelWidgetClass,
			multitop,
			XtNfromVert, multi_viewport,
			XtNtop, XawChainBottom,
			XtNbottom,XawChainBottom,
			XtNleft,XawChainLeft,
			XtNright,XawChainRight,
			XtNlabel, "Status  ",
			XtNwidth, VWIDTH,
			NULL);

	buttonform=XtVaCreateManagedWidget("multibform",
			formWidgetClass, multitop,
			XtNfromVert, multi_status,
			XtNtop, XawChainBottom,
			XtNbottom,XawChainBottom,
			XtNleft,XawChainLeft,
			XtNright,XawChainLeft,
			XtNresizable, False,
			XtNborderWidth,0,
			NULL);

	multikanjib=XtVaCreateManagedWidget("multikanjib",
			commandWidgetClass,
			buttonform,
			XtNshapeStyle,XawShapeEllipse,
			XtNlabel,"Kanji",
			XtNresize, False,
			NULL);
	multienglishb=XtVaCreateManagedWidget("multienglishb",
			commandWidgetClass,
			buttonform,
			XtNshapeStyle,XawShapeEllipse,
			XtNfromHoriz, multikanjib,
			XtNlabel,"English",
			XtNresize, False,
			NULL);
	multikanab=XtVaCreateManagedWidget("multikanab",
			commandWidgetClass,
			buttonform,
			XtNshapeStyle,XawShapeEllipse,
			XtNfromHoriz, multienglishb,
			XtNlabel,"Kana meaning",
			XtNresize, False,
			NULL);


	multiclose=XtVaCreateManagedWidget("multiclose",
			commandWidgetClass,
			buttonform,
			/*XtNfromVert, multi_status,*/
			XtNfromHoriz, multikanab,
			XtNlabel,"Close",
			XtNhorizDistance, 60,
			XtNshapeStyle,XawShapeRoundedRectangle,
			XtNcornerRoundPercent,10,
			XtNborderWidth, 2,
			NULL);
	XtAddCallback(multiclose, XtNcallback, multicallback, NULL);


	XtAddCallback(multikanab, XtNcallback, multicallback, NULL);
	XtAddCallback(multikanjib, XtNcallback, multicallback, NULL);
	XtAddCallback(multienglishb, XtNcallback, multicallback, NULL);


	/* HAVE TO DO THIS NOW, otherwise layout doesn't happen the first
	 * time
	 */

	XtRealizeWidget(multi_popup);

	/* must do this AFTER widgets have been created */
	ClearAllMulti();
}


/* Sometimes, it is good to allow external functions to override
 * current display setting.
 * Like if we are doing radical search, for example.
 * Caller should call this AFTER having done the normal AddTranslations loop,
 * because this will take care of refreshing display if neccessary.
 */
void SetMultiMode(int mode){
	switch(mode){
	    case GUESS_ENGLISH:
	    case GUESS_KANJI:
	    case GUESS_KANA:
		if(displaymode!=mode){
			displaymode=mode;
			RefreshMultiLabels();
		}
		break;
	    default:
		puts("ERROR: SetMultiMode passed in invalid mode?!");
		
	}
}

/* run through all the widgets we have, and set labels appropriately.
 * kinda like printallchoices() 
 * I just LOOOOVE code reuse :-)
 * Call this when usefile status, or kana/romaji status changes.
 */
 
void RefreshMultiLabels(){
	int lc;
	for(lc=0;lc<transcount;lc++){
		switch(displaymode){
		   case GUESS_ENGLISH:
			setenglabel(transwin[lc], transptrs[lc]);
			break;
		   case GUESS_KANA:
			setkanalabel(transwin[lc], transptrs[lc]);
			break;
		   case GUESS_KANJI:
			setkanjilabel(transwin[lc], transptrs[lc]);
			break;
		}
		if(InUsefile(trans_to_index(transptrs[lc]))){
			HighlightButton(usefiletoggles[lc]);
		} else {
			UnhighlightButton(usefiletoggles[lc]);

		}
	}
}

/* We ignore attempts to add more than our MAXMULTI value */
void AddMultiTranslation(TRANSLATION trans){
	int kindex;
	char statusprompt[20];
	/*int formwidth=GetWidgetWidth(multi_popup);*/


	if(transcount>=MAXMULTI){
		char msgbuff[100];
		overflow++;
		
		sprintf(msgbuff, "(only showing %d of %d)",
			MAXMULTI, MAXMULTI+overflow);
		setmultistatus(msgbuff);
		return;
	}

	transptrs[transcount]=trans;
	kindex=trans_to_index(trans);

	if(transcount>0){
		XtVaSetValues(transwin[transcount],
		      XtNfromVert,transwin[transcount-1],
		      NULL);

		XtVaSetValues(usefiletoggles[transcount],
		      XtNfromVert,transwin[transcount-1],
		      NULL);

	}


	if(InUsefile(kindex)){
		HighlightButton(usefiletoggles[transcount]);
	} else {
		UnhighlightButton(usefiletoggles[transcount]);
	}


	switch(displaymode){
	   case GUESS_ENGLISH:
		setenglabel(transwin[transcount], transptrs[transcount]);
		break;
	   case GUESS_KANA:
		setkanalabel(transwin[transcount], transptrs[transcount]);
		break;
	   case GUESS_KANJI:
		setkanjilabel(transwin[transcount], transptrs[transcount]);
		break;
	}
	XMapWindow(XtDisplay(transwin[transcount]), 
	           XtWindow(transwin[transcount]));
	XMapWindow(XtDisplay(usefiletoggles[transcount]),
	           XtWindow(usefiletoggles[transcount]));

	transcount++;

	sprintf(statusprompt,"%d matches",transcount);
	setmultistatus(statusprompt);


}


int getMultiMax(){
	return MAXMULTI;
}

int getMultiCount(){
	return transcount;
}


