#include	"defs.h"
#include	"global.h"
#include	"commands.h"

int dvi_h = 0;			/* current h on output dvi */
int dvi_v = 0;			/* current v on output dvi */
int *dvi_move;

static DEV_FONT dvi_curf;
int spmax = 0;

long dvipos;
long lpagep;

static int vert_moveovercom;
static BOOLEAN dir_used;

extern int command;
extern int num, den;
extern long postambleptr;
extern int dirmode;
extern char *dir_spec_vert;
extern char *dir_spec_end;
extern int dir_spec_vert_len;
extern int dir_spec_end_len;

/* ARGSUSED */
dev_arg(option, c)
char option;
char *c;
{
}

dev_init()
{
}

dev_setup()
{
    if (dirmode == DIR_KEEP) {
	dfd_dirkeep();
	vfd_dirkeep();
	vert_moveovercom = RIGHT1-1;
    } else
	vert_moveovercom = DOWN1-1;
    init_begend_str();
    dir_used = FALSE;
}

dev_endsetup()
{
    struct font_entry *fe;
    int k;

/*
    for (fe = hdfontent, k = 0; fe != NULL; fe = fe->next)
	if (fe->fnt_use == FU_USED) {
	    fe->k = k;
	    fe->fnt_use = FU_NOTUSED;
	    k++;
	}
*/

    /* output preamble */
    putbyte(outfp, PRE);
    putnint(outfp, DVIFORMAT, 1);
    putnint(outfp, num, 4);
    putnint(outfp, den, 4);
    putnint(outfp, mag, 4);
    (void)fseek(dvifp, (long)14, 0);
    putnint(outfp, k = getuint(dvifp, 1), 1);
    copybytes(dvifp, outfp, k);
    dvipos = 15+k;
    lpagep = -1;
}

dev_finish()
{
    long postpos;
    int i;
    struct font_entry *fe;

    end_string();
    postpos = dvipos;
    /* output postamble */
    putbyte(outfp, POST);
    putnint(outfp, lpagep, 4);
    putnint(outfp, num, 4);
    putnint(outfp, den, 4);
    putnint(outfp, mag, 4);
    (void)fseek(dvifp, postambleptr+17, 0);
    copybytes(dvifp, outfp, 8);
    putnint(outfp, spmax+1, 2);
    (void)fseek(dvifp, (long)2, 1);
    copybytes(dvifp, outfp, 2);
    dvipos += 29;

    for (fe = hdfontent; fe != NULL; fe = fe->next)
	if (fe->fnt_use == FU_USED)
	    putfontdef(fe);

    putbyte(outfp, POST_POST);
    putnint(outfp, postpos, 4);
    putnint(outfp, dir_used ? EXTDVIFORMAT : DVIFORMAT, 1);
    dvipos += 6;
    for (i = 0; i < 7 - (dvipos+3) % 4; i++)
	putbyte(outfp, 223);
}

putfontdef(fe)
struct font_entry *fe;
{
    byte b[sizeof(int)];
    int n;

    n = uinttob(b, fe->k);
    putbyte(outfp, FNT_DEF1+n-1);
    putbytes(outfp, b, n);
    putnint(outfp, fe->c, 4);
    putnint(outfp, fe->s, 4);
    putnint(outfp, fe->d, 4);
    putnint(outfp, fe->a, 1);
    putnint(outfp, fe->l, 1);
    putbytes(outfp, fe->n, fe->a+fe->l);
    dvipos += n+15+fe->a+fe->l;
}


static int devicefont = 0;

dev_initpage()
{
    dvi_h = dvi_v = 0;
    dev_initfont();
}

dev_bop(count)
int count[];
{
    int i;

    end_string();
    putbyte(outfp, BOP);
    for (i = 0; i < 10; i++)
	putnint(outfp, count[i], 4);
    putnint(outfp, lpagep, 4);
    lpagep = dvipos;
    dvipos += 45;
}

dev_eop()
{
    end_string();
    putbyte(outfp, EOP);
    dvipos++;
}

dvi_push()
{
    extern int sp;

    putbyte(outfp, PUSH);
    dvipos++;
    if (sp > spmax)
	spmax = sp;
}

dev_push()
{
    end_string();
    dvi_push();
}

dvi_pop()
{
    putbyte(outfp, POP);
    dvipos++;
}

dev_pop()
{
    end_string();
    dvi_pop();
}

dev_initfont()
{
    dvi_curf = DEV_NULLFONT;
}

dev_setfont(dvif)
DEV_FONT dvif;
{
    byte b[sizeof(int)];
    int n;

    if (dvif != dvi_curf) {
	end_string();
	if (dvif->fnt_use == FU_NOTUSED) {
	    dvif->k = devicefont++;
	    putfontdef(dvif);
	    dvif->fnt_use = FU_USED;
	}
	if (0 <= dvif->k && dvif->k <= 63) {
	    putbyte(outfp, FONT_00+dvif->k);
	    dvipos++;
	} else {
	    n = uinttob(b, dvif->k);
	    putbyte(outfp, FNT1+n-1);
	    putbytes(outfp, b, n);
	    dvipos += n+1;
	}
	dvi_curf = dvif;
    }
}

dev_move0(com)
int com;
{
    end_string();
    putbyte(outfp, com);
    dvipos++;
}

dev_move(x, n, com)
byte *x;
int n, com;
{
    end_string();
    putbyte(outfp, com+n);
    putbytes(outfp, x, n);
    dvipos += n+1;
}

dev_makemove(x, com)
int x, com;
{
    byte s[sizeof(int)];
    int n;

    /* use resolution as drift!! */
    if (-resolution < x && x < resolution)
	return;
    n = inttob(s, x);
    dev_move(s, n, com);
}

dev_makemoveover(x)
int x;
{
    dev_makemove(x, dir == HOR ? RIGHT1-1 : vert_moveovercom);
}

/* ARGSUSED */
dev_setposn(x, y)
int x, y;
{
}

dvi_setrule(a, b, com)
int a, b, com;
{
    putbyte(outfp, com);
    putnint(outfp, a, 4);
    putnint(outfp, b, 4);
    dvipos += 9;
}

dev_setrule(a, b, com)
int a, b, com;
{
    end_string();
    dvi_setrule(a, b, com);
}

dvi_dir(d)
int d;
{
    dir_used = TRUE;
    putbyte(outfp, DIR);
    putnint(outfp, d, 1);
    dvipos += 2;
}

dev_dir(d)
int d;
{
    if (d == HOR)
	dvi_move = &dvi_h;
    else if (d == VER)
	dvi_move = &dvi_v;
    if (dirmode == DIR_KEEP)
	dvi_dir(d);
}

BOOLEAN instring = FALSE;
int (*begstr)();
int (*endstr)();
int dvi_move_beg;

begin_string()
{
    if (dirmode != DIR_KEEP && !instring && dir != HOR) {
	instring = TRUE;
	begstr();
    }
}

end_string()
{
    if (dirmode != DIR_KEEP && instring) {
	instring = FALSE;
	endstr();
    }
}

bs_elim()
{
    dvi_dir(dir);
}

es_elim()
{
    dvi_dir(HOR);
}

bs_spec()
{
    dvi_move_beg = *dvi_move;
    dvi_push();
    putbytes(outfp, dir_spec_vert, dir_spec_vert_len);
    dvipos += dir_spec_vert_len;
}

es_spec()
{
    putbytes(outfp, dir_spec_end, dir_spec_end_len);
    dvipos += dir_spec_end_len;
    dvi_pop();
    dev_makemove(*dvi_move-dvi_move_beg, DOWN1-1);
}

bs_ignore()
{
    dvi_move_beg = *dvi_move;
}

es_ignore()
{
    dev_makemove(*dvi_move-dvi_move_beg, DOWN1-1);
}

#define	MARKWIDTH	50000

bs_mline()
{
    dvi_move_beg = *dvi_move;
}

es_mline()
{
    dev_makemove(*dvi_move-dvi_move_beg, DOWN1-1);
    dvi_setrule(*dvi_move-dvi_move_beg, MARKWIDTH, PUT_RULE);
}

bs_mchar()
{
}

es_mchar()
{
}

init_begend_str()
{
    if (dirmode == DIR_ELIM) {
	begstr = bs_elim;
	endstr = es_elim;
    } else if (dirmode == DIR_SPECIAL) {
	begstr = bs_spec;
	endstr = es_spec;
    } else if (dirmode == DIR_IGNORE) {
	begstr = bs_ignore;
	endstr = es_ignore;
    } else if (dirmode == DIR_MARKLINE) {
	begstr = bs_mline;
	endstr = es_mline;
    } else if (dirmode == DIR_MARKCHAR) {
	begstr = bs_mchar;
	endstr = es_mchar;
    }
}

/* ARGSUSED */
void
dev_predospecial(str, n)
byte *str;
int n;
{
}

void
dev_dospecial(str, n)
byte *str;
int n;
{
    end_string();
    putbyte(outfp, command);
    putnint(outfp, n, command-XXX1+1);
    putbytes(outfp, str, n);
    dvipos += n+1+command-XXX1+1;
}
