#include <u.h>
#include <libc.h>
#include <bio.h>
#include "hdr.h"
#include "conv.h"

typedef struct Hchar Hchar;
struct Hchar
{
	char *s;
	Rune r;
};

/* &lt;, &gt;, &quot;, &amp; intentionally omitted */

/*
 * Names beginning with _ are names we recognize
 * (without the underscore) but will not generate,
 * because they are nonstandard.
 */
static Hchar byname[] =
{
	{"AElig", 198},
	{"Aacute", 193},
	{"Acirc", 194},
	{"Agrave", 192},
	{"Alpha", 913},
	{"Aring", 197},
	{"Atilde", 195},
	{"Auml", 196},
	{"Beta", 914},
	{"Ccedil", 199},
	{"Chi", 935},
	{"Dagger", 8225},
	{"Delta", 916},
	{"ETH", 208},
	{"Eacute", 201},
	{"Ecirc", 202},
	{"Egrave", 200},
	{"Epsilon", 917},
	{"Eta", 919},
	{"Euml", 203},
	{"Gamma", 915},
	{"Iacute", 205},
	{"Icirc", 206},
	{"Igrave", 204},
	{"Iota", 921},
	{"Iuml", 207},
	{"Kappa", 922},
	{"Lambda", 923},
	{"Mu", 924},
	{"Ntilde", 209},
	{"Nu", 925},
	{"OElig", 338},
	{"Oacute", 211},
	{"Ocirc", 212},
	{"Ograve", 210},
	{"Omega", 937},
	{"Omicron", 927},
	{"Oslash", 216},
	{"Otilde", 213},
	{"Ouml", 214},
	{"Phi", 934},
	{"Pi", 928},
	{"Prime", 8243},
	{"Psi", 936},
	{"Rho", 929},
	{"Scaron", 352},
	{"Sigma", 931},
	{"THORN", 222},
	{"Tau", 932},
	{"Theta", 920},
	{"Uacute", 218},
	{"Ucirc", 219},
	{"Ugrave", 217},
	{"Upsilon", 933},
	{"Uuml", 220},
	{"Xi", 926},
	{"Yacute", 221},
	{"Yuml", 376},
	{"Zeta", 918},
	{"aacute", 225},
	{"acirc", 226},
	{"acute", 180},
	{"aelig", 230},
	{"agrave", 224},
	{"alefsym", 8501},
	{"alpha", 945},
	{"amp", 38},
	{"and", 8743},
	{"ang", 8736},
	{"aring", 229},
	{"asymp", 8776},
	{"atilde", 227},
	{"auml", 228},
	{"bdquo", 8222},
	{"beta", 946},
	{"brvbar", 166},
	{"bull", 8226},
	{"cap", 8745},
	{"ccedil", 231},
	{"cdots", 8943},
	{"cedil", 184},
	{"cent", 162},
	{"chi", 967},
	{"circ", 710},
	{"clubs", 9827},
	{"cong", 8773},
	{"copy", 169},
	{"crarr", 8629},
	{"cup", 8746},
	{"curren", 164},
	{"dArr", 8659},
	{"dagger", 8224},
	{"darr", 8595},
	{"ddots", 8945},
	{"deg", 176},
	{"delta", 948},
	{"diams", 9830},
	{"divide", 247},
	{"eacute", 233},
	{"ecirc", 234},
	{"egrave", 232},
	{"_emdash", 8212},	/* non-standard but commonly used */
	{"empty", 8709},
	{"emsp", 8195},
	{"_endash", 8211},	/* non-standard but commonly used */
	{"ensp", 8194},
	{"epsilon", 949},
	{"equiv", 8801},
	{"eta", 951},
	{"eth", 240},
	{"euml", 235},
	{"euro", 8364},
	{"exist", 8707},
	{"fnof", 402},
	{"forall", 8704},
	{"frac12", 189},
	{"frac14", 188},
	{"frac34", 190},
	{"frasl", 8260},
	{"gamma", 947},
	{"ge", 8805},
	{"gt", 62},
	{"hArr", 8660},
	{"harr", 8596},
	{"hearts", 9829},
	{"hellip", 8230},
	{"iacute", 237},
	{"icirc", 238},
	{"iexcl", 161},
	{"igrave", 236},
	{"image", 8465},
	{"infin", 8734},
	{"int", 8747},
	{"iota", 953},
	{"iquest", 191},
	{"isin", 8712},
	{"iuml", 239},
	{"kappa", 954},
	{"lArr", 8656},
	{"lambda", 955},
	{"lang", 9001},
	{"laquo", 171},
	{"larr", 8592},
	{"lceil", 8968},
	{"_ldots", 8230},
	{"ldquo", 8220},
	{"le", 8804},
	{"lfloor", 8970},
	{"lowast", 8727},
	{"loz", 9674},
	{"lrm", 8206},
	{"lsaquo", 8249},
	{"lsquo", 8216},
	{"lt", 60},
	{"macr", 175},
	{"mdash", 8212},
	{"micro", 181},
	{"middot", 183},
	{"minus", 8722},
	{"mu", 956},
	{"nabla", 8711},
	{"nbsp", 160},
	{"ndash", 8211},
	{"ne", 8800},
	{"ni", 8715},
	{"not", 172},
	{"notin", 8713},
	{"nsub", 8836},
	{"ntilde", 241},
	{"nu", 957},
	{"oacute", 243},
	{"ocirc", 244},
	{"oelig", 339},
	{"ograve", 242},
	{"oline", 8254},
	{"omega", 969},
	{"omicron", 959},
	{"oplus", 8853},
	{"or", 8744},
	{"ordf", 170},
	{"ordm", 186},
	{"oslash", 248},
	{"otilde", 245},
	{"otimes", 8855},
	{"ouml", 246},
	{"para", 182},
	{"part", 8706},
	{"permil", 8240},
	{"perp", 8869},
	{"phi", 966},
	{"pi", 960},
	{"piv", 982},
	{"plusmn", 177},
	{"pound", 163},
	{"prime", 8242},
	{"prod", 8719},
	{"prop", 8733},
	{"psi", 968},
	{"quad", 8193},
	{"quot", 34},
	{"rArr", 8658},
	{"radic", 8730},
	{"rang", 9002},
	{"raquo", 187},
	{"rarr", 8594},
	{"rceil", 8969},
	{"rdquo", 8221},
	{"real", 8476},
	{"reg", 174},
	{"rfloor", 8971},
	{"rho", 961},
	{"rlm", 8207},
	{"rsaquo", 8250},
	{"rsquo", 8217},
	{"sbquo", 8218},
	{"scaron", 353},
	{"sdot", 8901},
	{"sect", 167},
	{"shy", 173},
	{"sigma", 963},
	{"sigmaf", 962},
	{"sim", 8764},
	{"_sp", 8194},
	{"spades", 9824},
	{"sub", 8834},
	{"sube", 8838},
	{"sum", 8721},
	{"sup", 8835},
	{"sup1", 185},
	{"sup2", 178},
	{"sup3", 179},
	{"supe", 8839},
	{"szlig", 223},
	{"tau", 964},
	{"there4", 8756},
	{"theta", 952},
	{"thetasym", 977},
	{"thinsp", 8201},
	{"thorn", 254},
	{"tilde", 732},
	{"times", 215},
	{"trade", 8482},
	{"uArr", 8657},
	{"uacute", 250},
	{"uarr", 8593},
	{"ucirc", 251},
	{"ugrave", 249},
	{"uml", 168},
	{"upsih", 978},
	{"upsilon", 965},
	{"uuml", 252},
	{"_varepsilon", 8712},
	{"varphi", 981},
	{"_varpi", 982},
	{"varrho", 1009},
	{"vdots", 8942},
	{"_vsigma", 962},
	{"_vtheta", 977},
	{"weierp", 8472},
	{"xi", 958},
	{"yacute", 253},
	{"yen", 165},
	{"yuml", 255},
	{"zeta", 950},
	{"zwj", 8205},
	{"zwnj", 8204}
};

static Hchar byrune[nelem(byname)];

static int
hnamecmp(const void *va, const void *vb)
{
	Hchar *a, *b;
	
	a = (Hchar*)va;
	b = (Hchar*)vb;
	return strcmp(a->s, b->s);
}

static int
hrunecmp(const void *va, const void *vb)
{
	Hchar *a, *b;
	
	a = (Hchar*)va;
	b = (Hchar*)vb;
	return a->r - b->r;
}

static void
html_init(void)
{
	static int init;
	int i;
	
	if(init)
		return;
	init = 1;
	memmove(byrune, byname, sizeof byrune);
	
	/* Eliminate names we aren't allowed to generate. */
	for(i=0; i<nelem(byrune); i++){
		if(byrune[i].s[0] == '_'){
			byrune[i].r = Runeerror;
			byname[i].s++;
		}
	}
	
	qsort(byname, nelem(byname), sizeof byname[0], hnamecmp);
	qsort(byrune, nelem(byrune), sizeof byrune[0], hrunecmp);
}

static Rune
findbyname(char *s)
{
	Hchar *h;
	int n, m, x;
	
	h = byname;
	n = nelem(byname);
	while(n > 0){
		m = n/2;
		x = strcmp(h[m].s, s);
		if(x == 0)
			return h[m].r;
		if(x < 0){
			h += m+1;
			n -= m+1;
		}else
			n = m;
	}
	return Runeerror;
}

static char*
findbyrune(Rune r)
{
	Hchar *h;
	int n, m;

	if(r == Runeerror)
		return nil;
	h = byrune;
	n = nelem(byrune);
	while(n > 0){
		m = n/2;
		if(h[m].r == r)
			return h[m].s;
		if(h[m].r < r){
			h += m+1;
			n -= m+1;
		}else
			n = m;
	}
	return nil;
}

void
html_in(int fd, long *x, struct convert *out)
{
	char buf[100], *p;
	Biobuf b;
	Rune rbuf[N];
	Rune *r, *er;
	int c, i;
	
	USED(x);
	
	html_init();
	r = rbuf;
	er = rbuf+N;
	Binit(&b, fd, OREAD);
	while((c = Bgetrune(&b)) != Beof){
		if(r >= er){
			OUT(out, rbuf, r-rbuf);
			r = rbuf;
		}
		if(c == '&'){
			buf[0] = c;
			for(i=1; i<nelem(buf)-1;){
				c = Bgetc(&b);
				if(c == Beof)
					break;
				buf[i++] = c;
				if(strchr("; \t\r\n", c))
					break;
			}
			buf[i] = 0;
			if(buf[i-1] == ';'){
				buf[i-1] = 0;
				if((c = findbyname(buf+1)) != Runeerror){
					*r++ = c;
					continue;
				}
				buf[i-1] = ';';
				if(buf[1] == '#'){
					if(buf[2] == 'x')
						c = strtol(buf+3, &p, 16);
					else
						c = strtol(buf+2, &p, 10);
					if(*p != ';' || c >= NRUNE || c < 0)
						goto bad;
					*r++ = c;
					continue;
				}
			}
		bad:
			for(p=buf; p<buf+i; ){
				p += chartorune(r++, p);
				if(r >= er){
					OUT(out, rbuf, r-rbuf);
					r = rbuf;
				}
			}
			continue;
		}
		*r++ = c;
	}
	if(r > rbuf)
		OUT(out, rbuf, r-rbuf);
	OUT(out, rbuf, 0);
}

/*
 * use biobuf because can use more than UTFmax bytes per rune
 */
void
html_out(Rune *r, int n, long *x)
{
	char *s;
	Biobuf b;
	Rune *er;
	
	USED(x);
	html_init();
	Binit(&b, 1, OWRITE);
	er = r+n;
	for(; r<er; r++){
		if(*r < Runeself)
			Bputrune(&b, *r);
		else if((s = findbyrune(*r)) != nil)
			Bprint(&b, "&%s;", s);
		else
			Bprint(&b, "&#%d;", *r);
	}
	Bflush(&b);
}

