/* utils.c:
 * helper routines that dont really belong anywhere else
 */


#include <stdio.h>

#include <Intrinsic.h>
#include <IntrinsicP.h>

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

#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <errno.h>

#include "defs.h"
#include "externs.h"

/* Is a widget "mapped'? */
/* We need this because we do our own popupshell type management */
/* and we also try to handle WM_DELETE messages elegantly */
Boolean isMapped(Widget w){
	XWindowAttributes wattrs;
	XWindowAttributes *wptr=&wattrs;
	Window win;

	if(w==NULL)
		return False;

	win=XtWindow(w);
	if(win==0)
		return False;
	
	XGetWindowAttributes(display, win, wptr);

	if( (wptr->map_state)==IsUnmapped){
		return False;
	} else {
		return True;
	}
}

/* return 1 if a pipe, 0 if not */
int isapipe(FILE *fp){
	struct stat statbuf;
	int fd = fileno(fp);
	if(fstat(fd, &statbuf)==0){
		switch(errno){
		   case ENOENT:
			return 1;/* pipe, under solaris */
		   default:
			/* until I hear otherwise, I'll assume any OTHER
			 * kind of error is also meaning "pipe"
			 */
			return 1;
		}
	}

	return 0;
}

/* Generic Beep routine that we can call from anywhere.
 * This way we don't have to check for enabled bell every time in the code.
 * We can just put Beep() whereever we feel like it.
 */
void Beep(){
	if(doBell)
		XBell(display,100);
}

/* Since there is no standard util to convert hex ascii to int,...
 *  have to supply our own..
 *  It isn't incredibly efficient.. let's hope the compiler is smart.
 *
 * Note that we take char* as a hex string, EVEN IF it does not
 * start with 0x
 */
int xtoi(char * s)
{
	int out=0;
	sscanf(s,"%x",&out);
	return out;
}

/* nextword:
 *	Goes to first whitespace, then sets pointer to
 *	beginning of non-white-space.
 *
 *	Returns 1 on success, 0 on fail
 */
int nextword(unsigned char **stringp)
{
	while(!isspace(**stringp)){
		if(stringp == '\0')
			return 0;
		*stringp +=1;
	}
	/* now on space */
	while(isspace(**stringp)){
		if(stringp == '\0')
			return 0;
		*stringp +=1;
	}
	return 1;
	
}

/* nextchar:
 * returns pointer to next non-whitespace char
*/
unsigned char *nextchar(unsigned char *c)
{
	while(isspace(*c)){
		if(*c == '\0') break;
		c++;
	}
	return c;
}

XChar2b *dup_16(XChar2b *kanabuffer){
	int pronun_len;
	XChar2b *ret_str;
	
	pronun_len = strlen((char *) kanabuffer);

	ret_str = (XChar2b *) malloc(sizeof(char) * (pronun_len+4));
	if(ret_str== NULL){
		fprintf(stderr,"Not enough memory to read in dictionary\n");
		exit(0);
	}
	bcopy(kanabuffer, ret_str, sizeof(char) * (pronun_len+1));
	return ret_str;
}


/* random debugging util? */
void printline(unsigned char *s)
{
	while(*s){
		putchar(*s++);
	}
	putchar('\n');
}

FILE * open_compressed(char *dictname){
	FILE *fp;
	char command_string[100];
	int namelen;/* length of filename, and flag */
	int extlen;

	if(access(dictname,R_OK)!= 0){
		return NULL;
	}

#ifdef UNCOMPRESS
	namelen = strlen(dictname);
	extlen = strlen(UNCOMPRESSEXT);
	if(strncmp(&dictname[namelen-extlen],UNCOMPRESSEXT,extlen) != 0 ){
		namelen = 0;/* flag for later on */
		fp = fopen(dictname,"r");
	} else {
		sprintf(command_string,"%s %s",UNCOMPRESS,dictname);
		fp = (FILE *) popen(command_string,"r");
	}
#else
	fp = fopen(dictname,"r");
#endif /* UNCOMPRESS */
	if(fp == NULL){
		perror("Cannot open translation file");
		fprintf(stderr,"We were attempting to open %s\n",dictname);
#ifdef UNCOMPRESS
		if(namelen >0)
			fprintf(stderr,"Using uncompression method \"%s\"\n",
				UNCOMPRESS);
#endif
		return NULL;
	}
	return fp;

}



TRANSLATION FindField(TRANSLATION startK,
		      Boolean (*testfunc )(TRANSLATION,void *),
		      void * funcdata)
{


	/*static TRANSLATION startpoint= NULL;
	 * in case we later want
	 * to use this..
	 */

	TRANSLATION checkpoint;


	checkpoint = translations[lowestkanji];

	while(checkpoint != NULL) {
		if(testfunc(checkpoint,funcdata)){
			break;
		}
		checkpoint = checkpoint->nextk;
	}
	

	return checkpoint;
}


/*
 *	set the text field of a textwigdet to the passed integer value.
 */
void SetWidgetNumberval(Widget w,int val){
	char tempstr[100];
	if(val == 0)
		tempstr[0] = '\0';
	else
		sprintf(tempstr,"%d",val);
	XtVaSetValues(w,XtNstring,tempstr,NULL);
	return;
}
/*
 *	set the text field of a textwigdet to the passed HEX integer value.
 */
void SetWidgetHexval(Widget w,int val){
	char tempstr[100];
	if(val == 0)
		tempstr[0] = '\0';
	else
		sprintf(tempstr,"%x",val);
	XtVaSetValues(w,XtNstring,tempstr,NULL);
	return;
}


/* GetWidgetNumberval
 *	Get the asciiText from an input widget.
 *	Attempt to look up kanji index
 *	Set asciiText label to null if not found, or
 *	a clean decimal print of index otherwise.
 *
 *	Calls FindIndex, which accepts special prefixes.
 */
int GetWidgetNumberval(Widget w){
	String str;
	int retval=0;


	XtVaGetValues(w,XtNstring,&str,NULL);
	retval=atoi(str);
	SetWidgetNumberval(w,retval);

/*
	if(w == currentkanjiNum){
		retval = xtoi(str);
		SetWidgetHexval(w,retval);
	} else {
		retval = FindIndex(str);
		SetWidgetNumberval(w,retval);
	}
*/
	return (retval);
}

/* GetWidgetHexval
 *	Like GetWidgetNumberval(), except assumes that
 *	the widget value MUST BE A HEX STRING
 *	Get the asciiText from an input widget.
 *	Set asciiText label to null if not found, or
 *	a clean print of index otherwise.
 *
 *	Calls FindIndex, which accepts special prefixes.
 */
int GetWidgetHexval(Widget w){
	String str;
	int retval=0;


	XtVaGetValues(w,XtNstring,&str,NULL);
	retval = xtoi(str);
	SetWidgetHexval(w,retval);

	return (retval);
}

int GetWidgetWidth(Widget w){
	Dimension wwidth;
	XtVaGetValues(w, XtNwidth, &wwidth, NULL);
	return wwidth;
}
int GetWidgetBWidth(Widget w){
	Dimension wwidth;
	XtVaGetValues(w, XtNborderWidth, &wwidth, NULL);
	return wwidth;
}int GetWidgetHeight(Widget w){
	Dimension wheight;
	XtVaGetValues(w, XtNheight, &wheight, NULL);
	return wheight;
}

/* Note that this sets borderwidth to 0!! */
void WidenWidget(Widget w, int newwidth){
	int height, bwidth;

	height=GetWidgetHeight(w);
	bwidth=GetWidgetBWidth(w);
	
#ifdef NONO
	/*XtResizeWidget(w, newwidth, height, bwidth);*/
#else
	printf("Resizing some window to width %d\n",newwidth);
	XtVaSetValues(w,XtNwidth,newwidth,NULL);
	XtResizeWindow(w);
#endif

}




/* We take a tip from java, and use the PARENT to determine background
 * and foreground.
 *
 * This takes a button, and sets it to "highlighted", reguardless
 * of what it was before.
 *
 * UNFORTUNATELY... foreground never seems to work. so we'll fake
 * it with black. sigh.
 *
 * See SetWhiteOnBlack() comments about bug in Xaw, and not using this
 * from a callback
 */
void HighlightButton(Widget button)
{
	Pixel fg, bg;
	XtVaGetValues(XtParent(button), XtNforeground, &fg,NULL);
	XtVaGetValues(XtParent(button), XtNbackground, &bg, NULL);

	fg=black;

	XtVaSetValues(button, XtNforeground, bg,
		      XtNbackground, fg,
		      NULL);
}
/*
 * This takes a button, and sets it to NON-"highlighted", reguardless
 * of what it was before.
 */
void UnhighlightButton(Widget button)
{
	Pixel fg, bg;
	XtVaGetValues(XtParent(button), XtNforeground, &fg,NULL);
	XtVaGetValues(XtParent(button), XtNbackground, &bg, NULL);

	fg=black;

	XtVaSetValues(button, XtNforeground, fg,
		      XtNbackground, bg,
		      NULL);
}

/* Whatever it is now, reverse the colors of a button/widget */
void ReverseButton(Widget button)
{
	Pixel fg, bg;

	XtVaGetValues(button, XtNforeground, &fg,
		      XtNbackground, &bg, NULL);

	XtVaSetValues(button, XtNforeground, bg,
		      XtNbackground, fg,
		      NULL);
}


/*
 * Sets widget to have white text on a black background
 * bug in Xaw.so.6 means can only call at setup time, not in callback
 */
void SetWhiteOnBlack(Widget w){
	XtVaSetValues(w,XtNbackground,black,
		       XtNforeground,white,
		       NULL);
}

/*
 * Sets widget to have black text on a white background
 * bug in Xaw.so.6 means can only call at setup time, not in callback
 */
void SetBlackOnWhite(Widget w){
	XtVaSetValues(w,XtNbackground,white,
		       XtNforeground,black,
		       NULL);
}

