#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#ifdef __TURBOC__
extern unsigned _stklen=20000;
#include <alloc.h>
#else
#define huge
#endif

#define true (!false)
#define false 0
#include "bmp.h"
#include "dvipath.h"

double d_xscale, d_yscale;
int gdebug=false;
int fittobit;	/* true if picture should be scaled up to fit bitmap, wp-tiff */

#define scx(v) ( ((v) * d_xscale + 1))
#define scy(v) ( ((v) * d_yscale + 1))
#define dbg if (gdebug)

char *bgidir();
int path_bezier(int  x1, int  y1, int  x2, int  y2, int  x3, int  y3);
int path_alloc(void);
int path_move(int  x1, int  y1);
int path_line(int  x1, int  y1);
int path_closepath(void);

int dev_print(Bitmap *b);
int dev_size(int *nxbits, int *nybits, double *devxcm, double *devycm);
int dev_hpplus;
int dev_hires;
int dev_noff;
int dev_noclip;
int dev_nosquash;
int dev_wide;
double devxcm,devycm;
double uxcm,uycm;

Bitmap *bb;
/*---------------------------------------------------------------------------*/
/*		Local stuff */
int flipit;
FILE *outbit;
FILE *inf;
/*---------------------------------------------------------------------------*/
main_usage()
{
	printf("Usage: dviprint [-depson | -dlj] [-old] [-hires] [-debug] [-output xx.prt]\n");
	printf("	-depson   To produce output for epson printers \n");
	printf("	-dwp      To add tiff image to wp .eps file \n");
	printf("	-dlj      To produce output for HP LaserJet printers \n");
	printf("	-dpj      To produce output for HP PaintJet printers \n");
	printf("	-dvt      To print bitmap to screen (preview) \n");
	printf("	-over     Overhead transparency mode for PaintJet\n");
	printf("	-old	  For old HP Laser Jet printers (no compression)\n");
	printf(" 	-hires	  Uses high resolution for that printer (slower)\n");
	printf(" 	-wide     If your printer has a wide carriage \n");
	printf(" 	-noflip   Disable's auto flipping \n");
	printf(" 	-flip     Forces flip  \n");
	printf(" 	-nosquash Tries to print it full size\n");
	printf(" 	-compress Force internal bitmap compression (slow) \n");
	printf(" 	-noff     No form feed\n");
	printf(" 	-debug    Prints debug messages\n");
	printf(" 	-out x.x  Prints output to file instead of printer port\n");
	printf("\n");
}
enum {D_EPSON=1,D_LJ,D_VT,D_PJ,D_WP};
int dev_type,dev_noflip,dev_lowmem,dev_low,dev_over,dev_flip;
int bmp_compress;
char outbitname[80];
char gleroot[90];
main(int argc, char **argv)
{
	int i;
	char *ss;
	strcpy(gleroot,argv[0]);
#ifdef __TURBOC__
	ss = strchr(gleroot,'\\');
	if (ss==NULL) printf("Unable to locate files AGRV[0] wrong");
	for (;strchr(ss+1,'\\')!=NULL;) ss = strchr(ss+1,'\\');
	*(ss+1) = 0;
#endif

	if (argc<=1) { main_usage(); exit(0);}

	inf = fopen("out.dvi","rb");
	if (inf==NULL) {
		printf("Unable to open OUT.DVI for input, run DVIGLE first\n");
		gle_abort("");
	}

	dev_hpplus = true;
	for (i=1;i<argc; i++) {
#ifdef __TURBOC__
		strlwr(argv[i]);
#endif
		if (strncmp(argv[i],"/o",2)==0) dev_hpplus = false;
		else if (strncmp(argv[i],"/h",2)==0) dev_hires = true;
		else if (strncmp(argv[i],"-ol",3)==0) dev_hpplus = false;
		else if (strncmp(argv[i],"-ov",3)==0) dev_over = true;
		else if (strncmp(argv[i],"-me",3)==0) dev_lowmem = false;
		else if (strncmp(argv[i],"-co",3)==0) bmp_compress = true;
		else if (strncmp(argv[i],"-lo",3)==0) dev_low = true;
		else if (strncmp(argv[i],"-h",2)==0) dev_hires = true;
		else if (strncmp(argv[i],"-nosq",5)==0) dev_nosquash = true;
		else if (strncmp(argv[i],"-wi",3)==0) dev_wide = true;
		else if (strncmp(argv[i],"-noff",5)==0) dev_noff = true;
		else if (strncmp(argv[i],"-nocl",5)==0) dev_noclip = true;
		else if (strncmp(argv[i],"-n",2)==0) dev_noflip = true;
		else if (strncmp(argv[i],"-fl",3)==0) dev_flip = true;
		else if (strncmp(argv[i],"-deb",4)==0) gdebug = true;
		else if (strncmp(argv[i],"-dwp",4)==0) dev_type = D_WP;
		else if (strncmp(argv[i],"-dep",4)==0) dev_type = D_EPSON;
		else if (strncmp(argv[i],"-dl",3)==0) dev_type = D_LJ;
		else if (strncmp(argv[i],"-dv",3)==0) dev_type = D_VT;
		else if (strncmp(argv[i],"-dp",3)==0) dev_type = D_PJ;
		else if (strncmp(argv[i],"-o",2)==0) {
			strcpy(outbitname,argv[++i]);
		}
		else {
			printf("Unrecognised qualifier, {%s} \n",argv[i]);
			main_usage();
			exit(0);
		}
	}
	if (dev_type==0) { main_usage(); exit(0);}
	if (dev_type==D_WP) {
	  if (strcmp(outbitname,"out.dvi")==0) {
		printf("Must specify name of .eps file to add tiff too.\n");
		exit(0);
	  }
	  if (strstr(outbitname,".")!=0) {
	    * strchr(outbitname,'.') = 0;
	  }
	  strcat(outbitname,".epf");
	}
	if (strstr(outbitname,".gle")!=0) {
		printf("Will not erase a .gle file\n");
		exit(0);
	}
	open_outbit(outbitname);
	draw_file();
	close_output();
}
/*---------------------------------------------------------------------------*/
open_outbit(char *outbitname)
{
#if __TURBOC__
	if (strlen(outbitname)!=0) {
	  printf("Writing output to file {%s} \n",outbitname);
	  outbit = fopen(outbitname,"wb");
	  if (outbit==NULL) {
		printf("Could not open that FILE for output {%s} \n",outbitname);
		perror("");
		exit(1);
	  }
	} else 	printf("Printing to LPT1 \n");
#else

	    /* Special binary open for VMS */
/*	strcpy(outbitname,"out.prt"); */
	printf("Writing output to file {%s} \n",outbitname);
#ifdef unix
	if ((outbit = fopen(outbitname,"wb")) == NULL)
#else
	if ((outbit = fopen (outbitname,"wb","rfm=fix","bls=512","mrs=512")) == NULL)
#endif
	{   printf ("Can't open output bitmap file.\n");
            abort();
        }
#endif
}
/*---------------------------------------------------------------------------*/
/*   Path variables for bitmap */
int *path;
int npath;
int npath_alloc;

int file_end = false;
float getf(void);
int getfxy(int *x, int *y);
getfxy(int *x, int  *y)
{
	float u,xx,yy;
	xx = getf();
	yy = getf();
	if (flipit) {
		u = yy;
		yy = uxcm - xx;
		xx = u;
	}
	/*printf("fxy %g %g \n",xx,yy); */
	*x = (int) .5+scx(xx);
	*y = (int) .5+scy(yy);
}
float getf(void)
{
	static float x;
	fread(&x,sizeof(x),1,inf);
	if (feof(inf)) file_end = true;
	return x;
}
long getl(void)
{
	static long x;
	fread(&x,sizeof(x),1,inf);
	if (feof(inf)) file_end = true;
	return x;
}


float cur_lwidth,cur_color,cur_fill,cur_dashlen;
long cur_lstyle;

draw_file(void)
{
	int x2,y2,x3,y3,sx,sy;
	int x,y,cx,cy;
	int g=0;
	float fx,fy;
	int i,dot;

	for (;!file_end;) {
	  i = getl();
	  if (file_end) break;
	  switch (i) {
		case p_size:
			dbg printf("#size \n");
			fx = getf(); fy = getf();
			d_open(fx,fy);
			dbg printf(":");
		case p_newpath:
			dbg printf("#newpath \n");
			npath = 0;
			break;
		case p_move:
			getfxy(&x,&y);
			cx = x; cy = y;
			dbg printf("#move (%d) %d %d  \n",npath,x,y);
			path_move(x,y);
			sx = cx; sy = cy;
			break;
		case p_line:
			dbg {g++; if (g>200) {printf(":"); g=0;}}
			getfxy(&x,&y);
			cx = x; cy = y;
			dbg printf("#line (%d) %d %d  \n",npath,x,y);
			path_line(x,y);
			break;
		case p_closepath:
			dbg printf("#closepath %d %d \n",sx,sy);
			path_closepath();
			cx = sx; cy = sy;
			break;
		case p_dline:
			dbg {g++; if (g>200) {printf(":"); g=0;}}
			getfxy(&x,&y);
			bmp_line(bb,cx,cy,x,y);
			npath = 0;
			dbg printf("#(nopath)line %d %d %d %d  \n",cx,cy,x,y);
			cx = x; cy = y;
			break;
		case p_bezier:
			getfxy(&x,&y);
			getfxy(&x2,&y2);
			getfxy(&x3,&y3);
			path_bezier(x,y,x2,y2,x3,y3);
			dbg printf("#bezier (%d)\n",npath);
			cx = x3; cy = y3;
			break;
		case p_stroke:
			dbg printf("#stroke \n");
			path_stroke();
			break;
		case p_fill:
			dbg printf("#fill \n");
			path_fill();
			break;
		case p_lwidth:
			dbg printf("#lwidth \n");
			cur_lwidth = getf();
			bmp_lwidth(bb,(int) scx(cur_lwidth));
			break;
		case p_dashlen:
			dbg printf("#dashlen \n");
			cur_dashlen = getf();
                        dot=(int)(0.5+d_yscale*cur_dashlen);
                        dot = dot > 0 ? dot : 1;
			bmp_lstyle(bb,cur_lstyle,dot);
			break;
		case p_lstyle:
			dbg printf("#lstyle \n");
			cur_lstyle = getl();
                        dot=(int)(0.5+d_yscale*cur_dashlen);
                        dot = dot > 0 ? dot : 1;
			bmp_lstyle(bb,cur_lstyle,dot);
			break;
		case p_setcolor:
			x = getl(); x2 = getl(); x3 = getl(); y = getl();
			dbg printf("#setcolor %d %d %d f=%d \n",x,x2,x3,y);
			bmp_setcolor(bb,x,x2,x3,y); /* r,g,b,f */
			break;
		case p_clip:
			dbg printf("#clipcurpath \n");
			path_clip();
			break;
		case p_saveclip:
			dbg printf("#save clip \n");
			bmp_saveclip(bb);
			break;
		case p_restoreclip:
			dbg printf("#restore clip \n");
			bmp_restoreclip(bb);
			break;
		case p_null:
			dbg printf("Null \n");
			break;
		default:
			printf("Error in PATH codes in .DVI file %d\n",i);
			break;
	  }
	}
	d_close();
}
gle_abort(char *s)
{
	printf("%s",s);
	exit(1);
}
path_send()
{
	int sx=0,sy=0,cx=0,cy=0,x1,y1,x2,y2,x3,y3;
	int closed=true;
	int i,j,p1,p2;

	bmp_newpath(bb);
	for (i=0;i<npath;i++) {
	  switch(path[i]) {
	    case p_move:
		sx = path[++i];
		sy = path[++i];
		bmp_pmove(bb,sx,sy);
		cx = sx; cy = sy;
		break;
	    case p_line:
		x1 = path[++i];
		y1 = path[++i];
		dbg printf("pline %d %d \n",x1,y1);
		bmp_pline(bb,x1,y1);
		cx = x1; cy = y1;
		break;
	    case p_bezier:
		x1 = path[++i];  y1 = path[++i];
		x2 = path[++i];  y2 = path[++i];
		x3 = path[++i];  y3 = path[++i];
		dbg printf("pbezier %d %d   %d %d   %d %d\n",x1,y1,x2,y2,x3,y3);
		bmp_pbezier(bb,cx,cy,x1,y1,x2,y2,x3,y3);
		cx = x3; cy = y3;
		break;
	    case p_closepath:
		dbg if (cx!=sx || cy!=sy) printf("pclosepath %d %d \n",sx,sy);
		if (cx!=sx || cy!=sy) bmp_pline(bb,sx,sy);
		cx = sx; cy = sy;
		break;
	    default:
		printf("Error in path_fill code path[%d] %d \n",i,path[i]);
	  }
	}
}
path_fill(void)
{
	path_send();
	bmp_fill(bb);
}
path_clip(void)
{
	path_send();
	bmp_clip(bb);
}
path_stroke(void)
{
	int sx=0,sy=0,cx=0,cy=0,x1,y1,x2,y2,x3,y3;
	int closed=true;
	int i,j,p1,p2;

	bmp_newpath(bb);
	for (i=0;i<npath;i++) {
	  switch(path[i]) {
	    case p_move:
		sx = path[++i];
		sy = path[++i];
		cx = sx; cy = sy;
		break;
	    case p_line:
		x1 = path[++i];
		y1 = path[++i];
		bmp_line(bb,cx,cy,x1,y1);
		cx = x1; cy = y1;
		break;
	    case p_bezier:
		x1 = path[++i];  y1 = path[++i];
		x2 = path[++i];  y2 = path[++i];
		x3 = path[++i];  y3 = path[++i];
		bmp_bezier(bb,cx,cy,x1,y1,x2,y2,x3,y3);
		cx = x3; cy = y3;
		break;
	    case p_closepath:
		if (cx!=sx || cy!=sy) bmp_line(bb,cx,cy,sx,sy);
		cx = sx; cy = sy;
		break;
	    default:
		printf("Error in path_fill code path[%d] %d \n",i,path[i]);
	  }
	}
}
path_move(int  x,int y)
{
	path_alloc();
	path[npath++] = p_move;
	path[npath++] = x;
	path[npath++] = y;
}
path_line(int x,int y)
{
	path_alloc();
	path[npath++] = p_line;
	path[npath++] = x;
	path[npath++] = y;
}
path_bezier(int x1, int y1, int x2, int y2,int x3, int y3)
{
	path_alloc();
	path[npath++] = p_bezier;
	path[npath++] = x1;	path[npath++] = y1;
	path[npath++] = x2;	path[npath++] = y2;
	path[npath++] = x3;	path[npath++] = y3;
}
path_closepath()
{
	path_alloc();
	path[npath++] = p_closepath;
}
path_alloc(void)
{
	static int npa;
	int *a;

	if (npath < (npath_alloc-10)) return;
	npath_alloc = 20 + 2 * npath;
	if (npath_alloc<300) npath_alloc = 300;
	dbg  printf("=== Allocate %d %d \n",npath_alloc,npath);
	a = (int *) calloc(1,npath_alloc*sizeof(int));
	if (a==NULL) {
		gle_abort("Unable to allocate memory for path \n");
	}
	if (path != NULL) {
		dbg printf("path reallocate, copy \n");
		memcpy(a,path,(npa)*sizeof(int));
		free(path);
	}
	npa = npath_alloc;
	path = a;
}
path_free(void)
{
	if (path==NULL) return;
	free(path);
	path = NULL;
	npath = 0;
	npath_alloc = 0;
}

d_open(double width, double height)
{
	double f,f1,f2,fx,fy;
	double d_scale;
	int nxbits,nybits;

	{devxcm = width; devycm = height;}
	if (!dev_noflip &&  width>height &&!dev_wide) {devxcm = height; devycm = width;}
	switch (dev_type) {
	  case D_EPSON:
		dev_size_ep(&nxbits, &nybits, &devxcm, &devycm);
		break;
	  case D_WP:
		dev_size_wp(&nxbits, &nybits, &devxcm, &devycm);
		break;
	  case D_LJ:
		dev_size_lj(&nxbits, &nybits, &devxcm, &devycm);
		break;
	  case D_VT:
		dev_size_vt(&nxbits, &nybits, &devxcm, &devycm);
		break;
	  case D_PJ:
		dev_size_pj(&nxbits, &nybits, &devxcm, &devycm);
		break;
	}
	uxcm = width; uycm = height;

	d_scale = devxcm / width;
	f = devycm / height;
	if (f<d_scale) d_scale = f;

	if (fittobit) {
		fx = devxcm / width;
		d_scale = 1;
		fy = devycm / height;
	}
	if (d_scale<.98) {
		if ( dev_flip
		|| (dev_wide && !dev_noflip && height>width )
		||   ( !dev_wide && width>height && !dev_noflip)
		) {
			d_scale = devycm/width;
			f = devxcm/height;
			if (f<d_scale) d_scale = f;
			flipit = true;
			printf("Flipping graph to fit on page better \n");
		}
	}

	/* Get correct size of drawing */
	if (d_scale > 1.001) d_scale = 1;
	else {
		if (d_scale < .99) printf("Squashing onto page by factor %g \n",d_scale);
	}

	d_xscale = d_scale * (nxbits-2) / devxcm; /* Device Scale X, Device Scale y */
	d_yscale = d_scale * (nybits-2) / devycm;
	if (fittobit) {
		d_xscale = fx * (nxbits-2) / devxcm;
		d_yscale = fy * (nybits-2) / devycm;
	}
	bb = bmp_open(nxbits,nybits,1,bmp_compress);
	if (bb==NULL) gle_abort("Unable to create bitmap\n");
}
/*---------------------------------------------------------------------------*/
d_close()
{
	path_free();
	printf("Bitmap image created.\n");
	switch (dev_type) {
	  case D_EPSON:
		dev_print_ep(bb);
		break;
	  case D_WP:
		dev_print_wp(bb);
		break;
	  case D_LJ:
		dev_print_lj(bb);
		break;
	  case D_PJ:
		dev_print_pj(bb);
		break;
	  case D_VT:
		dev_print_vt(bb);
		break;
	}
	bmp_close(bb);
}

#ifdef __TURBOC__
#include <dos.h>
char put_out(char c);
int status(void);
status(void)
{
	union REGS reg;

	reg.h.ah = 2;
	reg.x.dx = 0;
	int86(0x17, &reg, &reg);
	return (reg.h.ah & 0x80);
}
char put_out(char c)
{
	union REGS reg;
	int w=0;
	static int ft=0;

	if (outbit!=NULL) {
		fputc(c,outbit);
		return;
	}
	while (!status()) {
		w++;
		if (w>10000) if (ft==0) {printf("Printer Busy\n"); w=0; ft=1;}
		if (w>10000) {printf(".");  w=0;}
	}
	/* if (ft==1) printf("\n"); */
	reg.h.ah = 0;
	reg.h.al = c;
	reg.x.dx = 0;
	int86(0x17,&reg,&reg);
	return (reg.h.ah);
}
close_output()
{
	if (outbit!=NULL) fclose(outbit);
}

#else

#include <stdio.h>
#ifdef VAXC
#include <file.h>
#endif
char zzbuff[512];
int nzz=0;
put_out(char c)
{
	zzbuff[nzz++] = c;
	if (nzz==512) {
	    fwrite(zzbuff,nzz,1,outbit);
	    nzz = 0;
	}
}
close_output()
{
	if (nzz > 0)  { /* for vax, must send whole blocks */
		memset(zzbuff+nzz,0,512-nzz);
		fwrite(zzbuff,512,1,outbit);
	}
	fclose(outbit);
}

#endif
printmem(char *s, int n)
{
	for (;n>0;n--) put_out(*s++);
}

char *bgidir()
{
#ifdef __TURBOC__
	char *s;
	static char xx[80];
	s = getenv("GLE_BGI");
	if (s==NULL) {
		strcpy(xx,gleroot);
		strcat(xx,"exe\\");
		s = xx;
	}
	return s;
#endif
}


