#include <u.h>
#include <libc.h>
#include <bio.h>
#include "dict.h"

/* Possible tags */
enum {
	DF,		/* definition */
	DX,		/* definition/example */
	ET,		/* etymology */
	EX,		/* example */
	LA,		/* label */
	ME,		/* main entry */
	NU,		/* sense number */
	PR,		/* pronunciation */
	PS,		/* grammar part */
	XR,		/* cross reference */
	XX		/* cross reference (whole entry) */
};

/* Assoc tables must be sorted on first field */

static Assoc tagtab[] = {
	{"df",	DF},
	{"dx",	DX},
	{"et",	ET},
	{"ex",	EX},
	{"la",	LA},
	{"me",	ME},
	{"nu",	NU},
	{"pr",	PR},
	{"ps",	PS},
	{"xr",	XR},
	{"xx",	XX}
};
static long	sget(char *, char *, char **, char **);
static void	soutpiece(char *, char *);

void
slangprintentry(Entry e, int cmd)
{
	char *p, *pe, *vs, *ve;
	long t;

	p = e.start;
	pe = e.end;
	if(cmd == 'h') {
		t = sget(p, pe, &vs, &ve);
		if(t == ME)
			soutpiece(vs, ve);
		outnl(0);
		return;
	}
	while(p < pe) {
		switch(sget(p, pe, &vs, &ve)) {
		case DF:
			soutpiece(vs, ve);
			outchars(".  ");
			break;
		case DX:
			soutpiece(vs, ve);
			outchars(".  ");
			break;
		case ET:
			outchars("[");
			soutpiece(vs, ve);
			outchars("] ");
			break;
		case EX:
			outchars("E.g., ");
			soutpiece(vs, ve);
			outchars(".  ");
			break;
		case LA:
			outchars("(");
			soutpiece(vs, ve);
			outchars(") ");
			break;
		case ME:
			outnl(0);
			soutpiece(vs, ve);
			outnl(0);
			break;
		case NU:
			outnl(2);
			soutpiece(vs, ve);
			outchars(".  ");
			break;
		case PR:
			outchars("[");
			soutpiece(vs, ve);
			outchars("] ");
			break;
		case PS:
			outnl(1);
			soutpiece(vs, ve);
			outchars(". ");
			break;
		case XR:
			outchars("See ");
			soutpiece(vs, ve);
			outchars(".  ");
			break;
		case XX:
			outchars("See ");
			soutpiece(vs, ve);
			outchars(".  ");
			break;
		default:
			ve = pe;	/* will end loop */
			break;
		}
		p = ve;
	}
	outnl(0);
}

long
slangnextoff(long fromoff)
{
	long a;
	char *p;

	a = Bseek(bdict, fromoff, 0);
	if(a < 0)
		return -1;
	for(;;) {
		p = Brdline(bdict, '\n');
		if(!p)
			break;
		if(p[0] == 'm' && p[1] == 'e' && p[2] == ' ')
			return (Boffset(bdict)-Blinelen(bdict));
	}
	return -1;
}

void
slangprintkey(void)
{
	Bprint(bout, "No key\n");
}

/*
 * Starting from b, find next line beginning with a tag.
 * Don't go past e, but assume *e==0.
 * Return tag value, or -1 if no more tags before e.
 * Set pvb to beginning of value (after tag).
 * Set pve to point at newline that ends the value.
 */
static long
sget(char *b, char *e, char **pvb, char **pve)
{
	char *p;
	char buf[3];
	long t, tans;

	buf[2] = 0;
	tans = -1;
	for(p = b;;) {
		if(p[2] == ' ') {
			buf[0] = p[0];
			buf[1] = p[1];
			t = lookassoc(tagtab, asize(tagtab), buf);
			if(t < 0) {
				if(debug)
					err("tag %s\n", buf);
				p += 3;
			} else {
				if(tans < 0) {
					p += 3;
					tans = t;
					*pvb = p;
				} else {
					*pve = p;
					break;
				}
			}
		}
		p = strchr(p, '\n');
		if(!p || ++p >= e) {
			if(tans >= 0)
				*pve = e-1;
			break;
		}
	}
	return tans;
}

static void
soutpiece(char *b, char *e)
{
	int c, lastc;

	lastc = 0;
	while(b < e) {
		c = *b++;
		if(c == '\n')
			c = ' ';
		if(!(c == ' ' && lastc == ' ') && c != '@')
			outchar(c);
		lastc = c;
	}
}
