#if ( defined DJ || defined EMXOS2 )      /* a.r. */
#define unix
#endif
#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
#include "int32.h"

#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,dev_vhires;
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] [-vhires] [-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("    -dec      Epson color ribbon printers \n");
        printf("    -dlj      To produce output for HP LaserJet printers \n");
        printf("    -dpj      To produce output for HP PaintJet printers \n");
        printf("    -dsx      Sixel graphics, for DEC printers la100's ...\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("    -vhires   Viritcal high resolution for sixel graphics\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,D_EC,D_SX};
int dev_type,dev_noflip,dev_lowmem,dev_low,dev_over,dev_flip;
int dev_nops=false;
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],"-vh",3)==0) dev_vhires = true;
                else if (strncmp(argv[i],"-nops",5)==0) dev_nops = 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],"-dec",4)==0) dev_type = D_EC;
                else if (strncmp(argv[i],"-dsx",4)==0) dev_type = D_SX;
                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 ( defined DJ )   /* a.r. */
        if (dev_type == D_VT)
                strcpy(outbitname, "nul");
        if (strlen(outbitname) == 0)
                {
                  fprintf( stderr, "\nError:\n");
                  fprintf( stderr, "You must specify a *file*-name for output with this version of GLE!\n");
                  fprintf( stderr, "Example:\n");
                  fprintf( stderr, "gle_dvip -dlj -hires -out laserjet.bin\n");
                  fprintf( stderr, "Now your're able to print by copying the output to your printer, e.g.:\n");
                  fprintf( stderr, "copy /b laserjet.bin lpt1\n");
                  exit(1);
                }
#endif
        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();
#ifdef VMS
        return 1;
#else
        return 0;
#endif
}
/*---------------------------------------------------------------------------*/
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;
}
int32 getl(void)
{
        static int32 x;
        fread(&x,sizeof(x),1,inf);
        if (feof(inf)) file_end = true;
        return x;
}


float cur_lwidth,cur_color,cur_fill,cur_dashlen;
int32 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_EC:
                dev_size_ec(&nxbits, &nybits, &devxcm, &devycm);
                break;
          case D_WP:
                dev_size_wp(&nxbits, &nybits, &devxcm, &devycm);
                break;
          case D_SX:
                dev_size_sx(&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_EC:
                dev_print_ec(bb);
                break;
          case D_WP:
                dev_print_wp(bb);
                break;
          case D_SX:
                dev_print_sx(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
#if ( defined DJ || defined EMXOS2 )   /* a.r. absolutely not necessary, but... */
        return getenv("GLE32FONT");
#elif __linux__
        return getenv("GRXFONT");
#endif
}


