/*
 * $Id: pslatex.trm,v 1.18 1995/12/20 21:48:08 drd Exp $
 */

/* GNUPLOT - pslatex.trm */
/*
 * Copyright (C) 1990 - 1993   
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted, 
 * provided that the above copyright notice appear in all copies and 
 * that both that copyright notice and this permission notice appear 
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the modified code.  Modifications are to be distributed 
 * as patches to released version.
 *  
 * This software  is provided "as is" without express or implied warranty.
 * 
 * This file is included by ../term.c.
 *
 * This file supplies the terminal drivers:
 *     pslatex --latex with embedded postscript
 *     pstex   --plain TeX with embedded postscript
 *
 * AUTHORS
 *  George Phillips
 *  Russell Lang
 *  David Kotz
 * 
 * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
 */

#ifndef GOT_DRIVER_H
#include "driver.h"
#endif

#ifdef TERM_REGISTER
register_term(pslatex)
register_term(pstex)
#endif

#ifdef TERM_PROTO
TERM_PUBLIC void PSLATEX_options __P((void));
TERM_PUBLIC void PSLATEX_init __P((void));
TERM_PUBLIC void PSLATEX_graphics __P((void));
TERM_PUBLIC void PSLATEX_put_text __P((unsigned int x, unsigned int y, char str[]));
TERM_PUBLIC int PSLATEX_justify_text __P((enum JUSTIFY mode));
TERM_PUBLIC int PSLATEX_text_angle __P((int angle));
TERM_PUBLIC void PSLATEX_reset __P((void));
TERM_PUBLIC void PSLATEX_text __P((void));
TERM_PUBLIC void PSLATEX_move __P((unsigned int x, unsigned int y));
TERM_PUBLIC void PSLATEX_vector __P((unsigned int x, unsigned int y));
TERM_PUBLIC void PSLATEX_linetype __P((int lt));
TERM_PUBLIC void PSLATEX_point __P((unsigned int x,unsigned int y, int number));

#define PSLATEX_XMAX (5*720)
#define PSLATEX_YMAX (3*720)

/* 10 pt char is about 10 pts high (say) */
#define PSLATEX_VCHAR (100)
/* 10 pt char is about 6 pts wide (say) */
/* I find about 5 points (output from test) - div */
#define PSLATEX_HCHAR (50)
#define GOT_PSLATEX_PROTO
#endif

#ifndef TERM_PROTO_ONLY

#ifdef TERM_BODY
static int PSLATEX_angle;
static int PSLATEX_justify;
static int PSLATEX_rotate = TRUE;
static char PSLATEX_psfile[MAX_ID_LEN+1] = "";
static TBOOLEAN PSLATEX_useAuxFile = FALSE; /* do we write two files? */
static FILE *PSLATEX_auxFile;
static TBOOLEAN PSLATEX_output = TRUE; /* do we write LaTeX? */

struct text_command {
    int x, y, angle, justify;
    char* label;
    struct text_command* next;
};

static struct text_command* PSLATEX_labels;

TERM_PUBLIC void PSLATEX_options()
{
    if (!END_OF_COMMAND) {
	if (almost_equals(c_token, "d$efault")) {
	    ps_color = FALSE;
	    PSLATEX_rotate = TRUE;
	    PSLATEX_useAuxFile = FALSE;
	    c_token++;
	}
    }

    if (!END_OF_COMMAND) {
	if (almost_equals(c_token, "c$olor")) {
	    ps_color = TRUE;
	    c_token++;
	}
    }

    if (!END_OF_COMMAND) {
	if (almost_equals(c_token, "m$onochrome")) {
	    ps_color = FALSE;
	    c_token++;
	}
    }

    if (!END_OF_COMMAND) {
	if (almost_equals(c_token, "r$otate")) {
	    PSLATEX_rotate = TRUE;
	    c_token++;
	}
    }

    if (!END_OF_COMMAND) {
	if (almost_equals(c_token, "n$orotate")) {
	    PSLATEX_rotate = FALSE;
	    c_token++;
	}
    }

    if (!END_OF_COMMAND) {
	if (almost_equals(c_token, "a$uxfile")) {
	    PSLATEX_useAuxFile = TRUE;
	    c_token++;
	}
    }
	/* div */

	if (!END_OF_COMMAND) {
		/* We have font size specified */
		struct value a;
		int ps_fontsize = (int)real(const_express(&a));
		term->v_char = (unsigned int)(ps_fontsize*PS_SC);
		term->h_char = (unsigned int)(ps_fontsize*PS_SC/2);
	}

    /* be sure to generate an options string that PSLATEX_init understands */

    sprintf(term_options, "%s %s%s",
	    ps_color ? "color" : "monochrome",
	    PSLATEX_rotate ? "rotate" : "norotate",
	    PSLATEX_useAuxFile ? " auxfile" : "");
}

TERM_PUBLIC void PSLATEX_init()
{
    extern char outstr[];	/* name of output file in quotes */

    if (strcmp(term->name, "pstex") == 0)
        PSLATEX_output = FALSE;

    /* try to open the auxiliary file for the postscript parts. */
    if (PSLATEX_useAuxFile == TRUE) {
	char *dotIndex;

	/* assume file name is ending in ".tex" */
	strcpy(PSLATEX_psfile, outstr+1);
	dotIndex = strrchr(PSLATEX_psfile,'.');
	if (dotIndex) {
	    strcpy(dotIndex,".ps");
	    if ((PSLATEX_auxFile = fopen(PSLATEX_psfile,"w")) == (FILE *)NULL){
		PSLATEX_useAuxFile = FALSE;
		fprintf(stderr,"Cannot open aux file %s for output\n",
			PSLATEX_psfile);
	    }
	} else {
	    fprintf(stderr,"Cannot make PostScript file name from %s\n",
		    outstr);
	    fprintf(stderr,"Turning off auxfile option\n");
	    PSLATEX_useAuxFile = FALSE;
	}
    }

    if (PSLATEX_output) {
        fprintf(outfile, "%% GNUPLOT: LaTeX picture with Postscript\n");
	fprintf(outfile, "\\setlength{\\unitlength}{0.1bp}\n");
    } else {

        /* write plain TeX header */

        fprintf(outfile, "%% GNUPLOT: plain TeX with Postscript\n");
	fprintf(outfile, "\\expandafter\\ifx\\csname GNUPLOTpicture\\endcsname\\relax\n");
	fprintf(outfile, "  \\newdimen\\GNUPLOTunit\n");
	fprintf(outfile, "  \\GNUPLOTunit=0.1bp\n");
	fprintf(outfile, "  \\def\\GNUPLOTpicture(#1,#2){\\vbox to#2\\GNUPLOTunit\\bgroup\n");
	fprintf(outfile, "    \\def\\put(##1,##2)##3{\\unskip\\raise##2\\GNUPLOTunit\n");
	fprintf(outfile, "      \\hbox to0pt{\\kern##1\\GNUPLOTunit ##3\\hss}\\ignorespaces}%%\n");
	fprintf(outfile, "    \\def\\ljust##1{\\vbox to0pt{\\vss\\hbox to0pt{##1\\hss}\\vss}}%%\n");
	fprintf(outfile, "    \\def\\cjust##1{\\vbox to0pt{\\vss\\hbox to0pt{\\hss ##1\\hss}\\vss}}%%\n");
	fprintf(outfile, "    \\def\\rjust##1{\\vbox to0pt{\\vss\\hbox to0pt{\\hss ##1}\\vss}}%%\n");
	fprintf(outfile, "    \\def\\stack##1{\\let\\\\=\\cr\\tabskip=0pt\\halign{\\hfil ####\\hfil\\cr ##1\\crcr}}%%\n");
	fprintf(outfile, "    \\def\\lstack##1{\\hbox to0pt{\\vbox to0pt{\\vss\\stack{##1}}\\hss}}%%\n");
	fprintf(outfile, "    \\def\\cstack##1{\\hbox to0pt{\\hss\\vbox to0pt{\\vss\\stack{##1}}\\hss}}%%\n");
	fprintf(outfile, "    \\def\\rstack##1{\\hbox to0pt{\\vbox to0pt{\\stack{##1}\\vss}\\hss}}%%\n");
	fprintf(outfile, "    \\vss\\hbox to#1\\GNUPLOTunit\\bgroup\\ignorespaces}%%\n");
	fprintf(outfile, "  \\def\\endGNUPLOTpicture{\\hss\\egroup\\egroup}%%\n");
	fprintf(outfile, "\\fi\n");
    }

	{
		unsigned int xmin = xoffset * PSLATEX_XMAX / PS_SC;
		unsigned int xmax = (xoffset+xsize) * PSLATEX_XMAX / PS_SC;
		unsigned int ymin = yoffset * PSLATEX_YMAX / PS_SC;
		unsigned int ymax = (yoffset+ysize) * PSLATEX_YMAX / PS_SC;

		if (PSLATEX_useAuxFile) {
			FILE *tmp = outfile;
			outfile = PSLATEX_auxFile;
			PS_common_init(1,1,0, 0,0, xmin, ymin, xmax, ymax, NULL);
			outfile = tmp;
		} else {
			fprintf(outfile, "\\special{!\n");
			PS_common_init(1,1,0, 0,0, xmin, ymin, xmax, ymax, NULL);
			fprintf(outfile, "}\n");
		}
	}

    PSLATEX_angle = 0;
    PSLATEX_justify = 0;
    PSLATEX_labels = 0;
}

TERM_PUBLIC void PSLATEX_graphics()
{
    struct termentry *t = term;

	/* bounding box = all if multiplot, or size if not */
	double xscale = multiplot ? 1 : xsize;
	double yscale = multiplot ? 1 : ysize;

    if (PSLATEX_output)
        fprintf(outfile, "\\begin{picture}(%d,%d)(0,0)\n", (int)(xscale*t->xmax), (int)(yscale*t->ymax));
    else
        fprintf(outfile, "\\GNUPLOTpicture(%d,%d)\n", (int)(xscale*t->xmax), (int)(yscale*t->ymax));

    if (PSLATEX_useAuxFile) {
	FILE *tmp;
	/*
	 * these are taken from the post.trm file computation
	 * of the bounding box, but without the X_OFF and Y_OFF
	 */
	int urx = (int)(xscale * (PS_XMAX) / PS_SC + 0.5),
	    ury = (int)(yscale * (PS_YMAX) / PS_SC + 0.5);

	/* generate special which xdvi and dvips can handle */
	fprintf(outfile,
		"\\special{psfile=%s llx=0 lly=0 urx=%d ury=%d rwi=%d}\n",
		PSLATEX_psfile, urx, ury, 10*urx);
	tmp = outfile;
	outfile = PSLATEX_auxFile;
	PS_graphics();
	outfile = tmp;
    } else {
	fprintf(outfile, "\\special{\"\n");
	PS_graphics();
    }

    PSLATEX_labels = (struct text_command *)NULL;
}

TERM_PUBLIC void PSLATEX_put_text(x, y, str)
unsigned int x, y;
char str[];
{
    struct text_command* tc;

    /* ignore empty strings */
    if (str[0] == '\0')
	return;
	
    tc = (struct text_command*)alloc(sizeof(struct text_command), term->name);
    tc->x = x;
    tc->y = y;
    tc->label = (char *)alloc(strlen(str) + 1, term->name);
    strcpy(tc->label, str);
    tc->justify = PSLATEX_justify;
    tc->angle = PSLATEX_angle;

    tc->next = PSLATEX_labels;
    PSLATEX_labels = tc;
}

TERM_PUBLIC int PSLATEX_justify_text(mode)
enum JUSTIFY mode;
{
    PSLATEX_justify = mode;
    return TRUE;
}

TERM_PUBLIC int PSLATEX_text_angle(angle)
int angle;
{
    /* rotated text is put in a short stack, and optionally uses 
     * postscript specials depending on PSLATEX_rotate */
    PSLATEX_angle = angle;
    return TRUE;
}


TERM_PUBLIC void PSLATEX_reset()
{
    if (PSLATEX_useAuxFile && PSLATEX_auxFile) {
	fclose(PSLATEX_auxFile);
	PSLATEX_auxFile=NULL;
    }
}

TERM_PUBLIC void PSLATEX_text()
{
    struct text_command* tc;

    if (PSLATEX_useAuxFile) {
	FILE *tmp = outfile;
	outfile = PSLATEX_auxFile;
	PS_text();
	outfile = tmp;
    } else {
	PS_text();
	fprintf(outfile, "}\n");
    }

    for (tc = PSLATEX_labels; tc != (struct text_command*)NULL; tc = tc->next) {
	fprintf(outfile, "\\put(%d,%d){", tc->x, tc->y);
	switch (tc->angle) {
	case 0:
	    switch (tc->justify) {
	    case LEFT:
		fprintf(outfile, (PSLATEX_output
				  ? "\\makebox(0,0)[l]{%s}"
				  : "\\ljust{%s}"), tc->label);
		break;
	    case CENTRE:
		fprintf(outfile, (PSLATEX_output
				  ? "\\makebox(0,0){%s}"
				  : "\\cjust{%s}"), tc->label);
		break;
	    case RIGHT:
		fprintf(outfile, (PSLATEX_output
				  ? "\\makebox(0,0)[r]{%s}"
				  : "\\rjust{%s}"), tc->label);
		break;
	    }
	    break;
	case 1: /* put text in a short stack */
	    if (PSLATEX_rotate) {
	        fprintf(outfile, "%%\n\\special{ps: gsave currentpoint currentpoint translate\n");
	        fprintf(outfile, "270 rotate neg exch neg exch translate}%%\n");
	    }
	    switch (tc->justify) {
	    case LEFT:
		fprintf(outfile, (PSLATEX_output
				  ? "\\makebox(0,0)[lb]{\\shortstack{%s}}"
				  : "\\lstack{%s}"),
			tc->label);
		break;
	    case CENTRE:
		fprintf(outfile, (PSLATEX_output
				  ? "\\makebox(0,0)[b]{\\shortstack{%s}}"
				  : "\\cstack{%s}"),
			tc->label);
		break;
	    case RIGHT:
		fprintf(outfile, (PSLATEX_output
				  ? "\\makebox(0,0)[lt]{\\shortstack{%s}}"
				  : "\\rstack{%s}"),
			tc->label);
		break;
	    }
	    if (PSLATEX_rotate) {
	        fprintf(outfile, "%%\n\\special{ps: currentpoint grestore moveto}%%\n");
	    }
	}
	fprintf(outfile, "}\n");
    }

    while (PSLATEX_labels) {
	tc = PSLATEX_labels->next;
	free(PSLATEX_labels->label);
	free(PSLATEX_labels);
	PSLATEX_labels = tc;
    }

    if (PSLATEX_output)
        fprintf(outfile, "\\end{picture}\n");
    else
	fprintf(outfile, "\\endGNUPLOTpicture\n");
}

TERM_PUBLIC void PSLATEX_move(x,y)
unsigned int x,y;
{
    if (PSLATEX_useAuxFile) {
	FILE *tmp = outfile;
	outfile = PSLATEX_auxFile;
	PS_move(x,y);
	outfile=tmp;
    } else {
	PS_move(x,y);
    }
}


TERM_PUBLIC void PSLATEX_vector(x,y)
unsigned int x,y;
{

    if (PSLATEX_useAuxFile) {
	FILE *tmp = outfile;
	outfile = PSLATEX_auxFile;
	PS_vector(x,y);
	outfile = tmp;
    } else {
	PS_vector(x,y);
    }
}


TERM_PUBLIC void PSLATEX_linetype(lt)
int lt;
{
    if (PSLATEX_useAuxFile) {
	FILE *tmp = outfile;
	outfile = PSLATEX_auxFile;
	PS_linetype(lt);
	outfile = tmp;
    } else {
	PS_linetype(lt);
    }
}

TERM_PUBLIC void PSLATEX_point(x,y,number)
unsigned int x,y;
int number;
{
    if (PSLATEX_useAuxFile) {
	FILE *tmp = outfile;
	outfile = PSLATEX_auxFile;
	PS_point(x,y,number);
	outfile = tmp;
    } else
	PS_point(x,y,number);
}
#endif /* TERM_BODY */

#ifdef TERM_TABLE

#ifndef GOT_POST_PROTO
#define TERM_PROTO_ONLY
#include "post.trm"
#undef TERM_PROTO_ONLY
#endif

TERM_TABLE_START(pslatex_driver)
    "pslatex", "LaTeX picture environment with PostScript \\specials",
	PSLATEX_XMAX, PSLATEX_YMAX, PSLATEX_VCHAR, PSLATEX_HCHAR,
	PS_VTIC, PS_HTIC, PSLATEX_options, PSLATEX_init, PSLATEX_reset,
	PSLATEX_text, null_scale, PSLATEX_graphics, PSLATEX_move,
	PSLATEX_vector,	PSLATEX_linetype, PSLATEX_put_text, PSLATEX_text_angle,
	PSLATEX_justify_text, PSLATEX_point, do_arrow, PS_set_font
TERM_TABLE_END(pslatex_driver)

#undef LAST_TERM
#define LAST_TERM pslatex_driver

TERM_TABLE_START(pstex_driver)
    "pstex", "plain TeX with PostScript \\specials",
	PSLATEX_XMAX, PSLATEX_YMAX, PSLATEX_VCHAR, PSLATEX_HCHAR,
	PS_VTIC, PS_HTIC, PSLATEX_options, PSLATEX_init, PSLATEX_reset,
	PSLATEX_text, null_scale, PSLATEX_graphics, PSLATEX_move,
	PSLATEX_vector,	PSLATEX_linetype, PSLATEX_put_text, PSLATEX_text_angle,
	PSLATEX_justify_text, PSLATEX_point, do_arrow, PS_set_font
TERM_TABLE_END(pstex_driver)

#undef LAST_TERM
#define LAST_TERM pstex_driver

#endif /* TERM_TABLE */
#endif /* TERM_PROTO_ONLY */


#ifdef TERM_HELP
START_HELP(pslatex)
"1 pslatex",
"?set terminal pslatex",
"?pslatex",
" There are a few options for the pslatex driver.",
"",
" Syntax:",
"         set terminal pslatex {<color>} {<rotate>} {auxfile}",
"",
" <color> is either `color` or `monochrome`.  If `default` is specified, the",
" plot will have rotated text and be in monochrome, all in one file.  <rotate>",
" is either `rotate` or `norotate` and determines if the vertical axis label",
" is rotated.",
" If `auxfile` is specified, it directs the driver to put the PostScript",
" commands into an auxiliary file instead of directly into the LaTeX file.",
" This is useful if your plots are large, and dvips cannot handle the picture.",
" The PostScript file name for this option is determined by replacing the",
" trailing `.tex` with `.ps` in the output file name.",
"",
" Example:",
"         set term pslatex auxfile    # put PostScript parts in file foo.ps",
"         set output \"foo.tex\""
END_HELP(pslatex)
#endif

