#include <stdio.h>
#include <ctype.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include "ztypes.h"
#include "xio.h"
#include "arguments.h"

#define DEFAULTGEOMETRY "500x600+100+100"
#define DEFAULTSTATGEOMETRY "80x24+100+50"

static char *defaultfonts[NUMFONTS] = {
    FND0, FND0,
    FND1, FND1,
    FND2, FND2,
    FND3, FND3,
    FND4, FND4,
    FND5, FND5,
    FND6, FND6,
    FND7, FND7
};

static char *attrnames[NUMFONTS] = {
    "n",
    "r",
    "b",
    "rb",
    "i",
    "ri",
    "bi",
    "rbi",
    "f",
    "rf",
    "bf",
    "rbf",
    "if",
    "rif",
    "bif",
    "rbif"
};

#ifdef __STDC__
static char *findoption(int key);
static int str_to_attr(char *cx);
static int str_to_bool(char *cx);
#else
static char *findoption();
static int str_to_attr();
static int str_to_bool();
#endif

#ifdef __STDC__
void xinit_defaultprefs()
#else
void xinit_defaultprefs()
#endif
{
    int ix;
    strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE;
    strictz_declare_spec = FALSE;
    prefs.leading = 3;
    prefs.marginx = 4;
    prefs.marginy = 4;
    prefs.inputattr = BOLD;
    prefs.historylength = 20;
    prefs.paging = FALSE;
    prefs.fulljustify = TRUE;
    prefs.buffersize = 4000;
    prefs.bufferslack = 1000;
    for (ix=0; ix<NUMFONTS; ix++)
	prefs.font[ix] = NULL;
    prefs.statwid = 80;
    prefs.stathgt = 24;
    prefs.autoresize = TRUE;
    prefs.resizeupward = FALSE;
    prefs.autoclear = TRUE;
    /* can't set up colors yet */

    xkey_init();
}

/* set xiodpy, xioscn, xiodepth, fontstr[] */
#ifdef __STDC__
void xinit_openconnection()
#else
void xinit_openconnection()
#endif
{
    int ix;
    int direction;
    int ascent, descent;
    XCharStruct overall;
    XColor col, realcol;
    Colormap colormap;
    char *cx;

    xiodpy = XOpenDisplay(NULL);
    if (!xiodpy) {
	fprintf(stderr, "%s: could not open display.\n", PROGRAMNAME);
	exit(-1);
    }

    /* init all the X stuff */
    xioscn = DefaultScreen(xiodpy);
    xiodepth = DefaultDepth(xiodpy, xioscn);
    if (DoesBackingStore(ScreenOfDisplay(xiodpy, xioscn)) == NotUseful)
	xiobackstore = FALSE;
    else
	xiobackstore = TRUE;
    colormap = DefaultColormap(xiodpy, xioscn);

    xinit_defaultprefs(); /* ### should be before argv[] parsing? */
    prefs.forecolor = BlackPixel(xiodpy, xioscn);
    prefs.backcolor = WhitePixel(xiodpy, xioscn);
    for (ix=0; ix<NUMFONTS; ix++) {
	prefs.textcolor[ix] = prefs.forecolor;
    }

    /* suck in the preferences */
    cx = findoption(OPT_BINDINGS);
    if (cx) {
	xkey_parse_bindings(cx);
    }
    cx = findoption(OPT_GEOMETRY);
    if (!cx) {
	cx = DEFAULTGEOMETRY;
    }
    XGeometry(xiodpy, xioscn, cx, DEFAULTGEOMETRY, 1, 1, 1, 0, 0, &prefs.winx, &prefs.winy, &prefs.winw, &prefs.winh);
    cx = findoption(OPT_STATGEOMETRY);
    if (!cx) {
	cx = DEFAULTSTATGEOMETRY;
    }
    XGeometry(xiodpy, xioscn, cx, DEFAULTSTATGEOMETRY, 1, 1, 1, 0, 0, &prefs.statwinx, &prefs.statwiny, &prefs.statwid, &prefs.stathgt);
    cx = findoption(OPT_STRICTZ);
    if (cx) {
        ix = atoi(cx);
        if (ix >= STRICTZ_REPORT_NEVER && ix <= STRICTZ_REPORT_FATAL)
	    strictz_report_mode = ix;
    }
    cx = findoption(OPT_SPEC);
    if (cx)
	strictz_declare_spec = str_to_bool(cx);
    cx = findoption(OPT_INPUTSTYLE);
    if (cx)
	prefs.inputattr = str_to_attr(cx);
    cx = findoption(OPT_MARGINX);
    if (cx)
	prefs.marginx = atoi(cx);
    cx = findoption(OPT_LEADING);
    if (cx)
	prefs.leading = atoi(cx);
    cx = findoption(OPT_JUSTIFY);
    if (cx)
	prefs.fulljustify = str_to_bool(cx);
    cx = findoption(OPT_AUTORESIZE);
    if (cx)
	prefs.autoresize = str_to_bool(cx);
    cx = findoption(OPT_RESIZEUPWARD);
    if (cx)
	prefs.resizeupward = str_to_bool(cx);
    cx = findoption(OPT_AUTOCLEAR);
    if (cx)
	prefs.autoclear = str_to_bool(cx);
    cx = findoption(OPT_HISTORY);
    if (cx)
	prefs.historylength = atoi(cx);
    cx = findoption(OPT_BUFFER);
    if (cx)
	prefs.buffersize = atol(cx);

    cx = findoption(OPT_BACKGROUND);
    if (cx
	&& XAllocNamedColor(xiodpy, colormap, cx, &col, &realcol)) {
	prefs.backcolor = col.pixel;
    }
    cx = findoption(OPT_FOREGROUND);
    if (cx
	&& XAllocNamedColor(xiodpy, colormap, cx, &col, &realcol)) {
	prefs.forecolor = col.pixel;
	for (ix=0; ix<NUMFONTS; ix++) 
	    prefs.textcolor[ix] = col.pixel;
    }
    cx = findoption(OPT_GREYCOLOR);
    if (!cx)
	cx = "grey60";
    if (cx
	&& XAllocNamedColor(xiodpy, colormap, cx, &col, &realcol)) {
	prefs.greycolor = col.pixel;
    }
    else {
	prefs.greycolor = prefs.forecolor;
    }
    if (xiodepth > 1) {
	for (ix=0; ix<NUMFONTS; ix++) {
	    cx = findoption(OPT_STYLECOLOR+ix);
	    if (cx
		&& XAllocNamedColor(xiodpy, colormap, cx, &col, &realcol)) {
		prefs.textcolor[ix] = col.pixel;
	    }
	}
    }
    for (ix=0; ix<NUMFONTS; ix++) {
	cx = findoption(OPT_STYLEFONT+ix);
	if (cx) {
	    prefs.font[ix] = cx;
	}
    }

    for (ix=0; ix<NUMFONTS; ix++) {
	if (!(ix & REVERSE)) {
	    fontstr[ix] = NULL;
	    if (prefs.font[ix])
		fontstr[ix] = XLoadQueryFont(xiodpy, prefs.font[ix]);
	    if (!fontstr[ix]) {
		if (prefs.font[ix]) {
		    fprintf(stderr, "%s: unable to load font <%s>, defaulting to <%s>...\n", PROGRAMNAME, prefs.font[ix], defaultfonts[ix]);
		}
		fontstr[ix] = XLoadQueryFont(xiodpy, defaultfonts[ix]);
		if (!fontstr[ix]) {
		    fprintf(stderr, "%s: fatal error: unable to load font <%s>\n", PROGRAMNAME, defaultfonts[ix]);
		    exit(1);
		}
	    }
	}
	else
	    fontstr[ix] = fontstr[ix & (~REVERSE)];
    }

    /* figure out font foo */
    for (ix=0; ix<NUMFONTS; ix++) {
	XTextExtents(fontstr[ix], " ", 1, &direction, &ascent, &descent, &overall);
	spacewidth[ix] = overall.width;
	if (fontstr[ix]->ascent + fontstr[ix]->descent > lineheight)
	    lineheight = fontstr[ix]->ascent + fontstr[ix]->descent;
	if (fontstr[ix]->ascent > lineheightoff)
	    lineheightoff = fontstr[ix]->ascent;
    }
    lineheight += prefs.leading;

    /* ensure all cut buffers exist */
    for (ix=0; ix<8; ix++) {
	int size;
	char *cx = XFetchBuffer(xiodpy, &size, ix);
	if (!cx) {
	    XStoreBuffer(xiodpy, "#", sizeof(char), ix);
	}
	else {
	    free(cx);
	}
    }

}

#ifdef __STDC__
static char *findoption(int key)
#else
static char *findoption(key)
int key;
#endif
{
    char *cx;
    unixoption *opt;

    opt = (&unixoptionlist[key]);
    if (!opt->name) {
	fprintf(stderr, "%s: internal option error on key %d\n", PROGRAMNAME, key);
	exit(1);
    }

    if (opt->val)
	cx = opt->val;
    else
	cx = XGetDefault(xiodpy, PROGRAMNAME, opt->name);

    return cx;
}

#ifdef __STDC__
static int str_to_attr(char *cx)
#else
static int str_to_attr(cx)
char *cx;
#endif
{
    int ix;
    for (ix=0; ix<NUMFONTS; ix++) {
	if (!strcmp(attrnames[ix], cx))
	    return ix;
    }
    return 0;
}

#ifdef __STDC__
static int str_to_bool(char *cx)
#else
static int str_to_bool(cx)
char *cx;
#endif
{
    if (*cx=='y' || *cx=='Y' || *cx=='t' || *cx=='T')
	return TRUE;

    if (*cx=='o' || *cx=='O') {
	cx++;
	if (*cx=='n' || *cx=='N')
	    return TRUE;
    }

    return FALSE;
}

