/*
 * FIG : Facility for Interactive Generation of figures
 * Copyright (c) 1985-1988 by Supoj Sutanthavibul
 * Parts Copyright (c) 1989-2002 by Brian V. Smith
 * Parts Copyright (c) 1991 by Paul King
 *
 * Any party obtaining a copy of these files is granted, free of charge, a
 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
 * nonexclusive right and license to deal in this software and
 * documentation files (the "Software"), including without limitation the
 * rights to use, copy, modify, merge, publish and/or distribute copies of
 * the Software, and to permit persons who receive copies from any such 
 * party to do so, with the only requirement being that this copyright 
 * notice remain intact.
 *
 */

#include "fig.h"
#include "resources.h"
#include "mode.h"
#include "w_layers.h"
#include "w_msgpanel.h"
#include "w_print.h"
#include "w_setup.h"

extern void	init_write_tmpfile();
extern void	end_write_tmpfile();

static int	exec_prcmd();
static char	layers[PATH_MAX];
static char	prcmd[2*PATH_MAX+200], tmpcmd[255];

/*
 * Protect a string by enclosing it in apostrophes. Escape any apostrophes
 * in the string with a backslash ('\').
 * Beware!  The string returned by this function is static and is
 * reused the next time the function is called!
 */

char *shell_protect_string(string)
    char	   *string;
{
    static char *buf = 0;
    static int buflen = 0;
    int len = 2 * strlen(string) + 1;
    char *cp, *cp2;

    if (strlen(string) == 0)
	return string;

    if (! buf) {
	buf = XtMalloc(len);
	buflen = len;
    }
    else if (buflen < len) {
	buf = XtRealloc(buf, len);
	buflen = len;
    }

    cp2 = buf;
    *cp2++ = '\'';
    for (cp = string; *cp; cp++) {
	if (*cp == '\'') {
	    /* an apostrophe in the string, close quotes, add \' and open again */
	    *cp2++ = '\'';
	    *cp2++ = '\\';
	    *cp2++ = '\'';
	}
	*cp2++ = *cp;
    }
    *cp2++ = '\'';

    *cp2 = '\0';

    return(buf);
}

print_to_printer(printer, backgrnd, mag, print_all_layers, grid, params)
    char	    printer[];
    char	   *backgrnd;
    float	    mag;
    Boolean	    print_all_layers;
    char	   *grid, params[];
{
    char	    syspr[2*PATH_MAX+200];
    char	    tmpfile[PATH_MAX];
    char	   *name;

    sprintf(tmpfile, "%s/%s%06d", TMPDIR, "xfig-print", getpid());
    warnexist = False;
    init_write_tmpfile();
    if (write_file(tmpfile, False)) {
      end_write_tmpfile();
      return;
    }
    end_write_tmpfile();

    /* if the user only wants the active layers, build that list */
    build_layer_list(layers);

    if (strlen(cur_filename) == 0)
	name = tmpfile;
    else
	name = shell_protect_string(cur_filename);

#ifdef I18N
    sprintf(tmpcmd, "%s %s -L ps -z %s -m %f %s -n %s",
	    fig2dev_cmd, appres.international ? appres.fig2dev_localize_option : "",
#else
    sprintf(tmpcmd, "%s -L ps -z %s -m %f %s -n %s",
	    fig2dev_cmd,
#endif /* I18N */
	    paper_sizes[appres.papersize].sname, mag/100.0,
	    appres.landscape ? "-l xxx" : "-p xxx", name);

    if (appres.correct_font_size)
	strcat(tmpcmd," -F ");
    if (!appres.multiple && !appres.flushleft)
	strcat(tmpcmd," -c ");
    if (appres.multiple)
	strcat(tmpcmd," -M ");
    if (strlen(grid) && strcasecmp(grid,"none") !=0 ) {
	strcat(tmpcmd," -G ");
	strcat(tmpcmd,grid);
    }
    if (backgrnd[0]) {
	strcat(tmpcmd," -g \\");	/* must escape the #rrggbb color spec */
	strcat(tmpcmd,backgrnd);
    }
    /* add the -D +list if user doesn't want all layers printed */
    if (!print_all_layers)
	strcat(tmpcmd, layers);

    /* make the print command with no filename (it will be in stdin) */
    gen_print_cmd(syspr, "", printer, params);

    /* make up the whole translate/print command */
    sprintf(prcmd, "%s %s | %s", tmpcmd, tmpfile, syspr);
    if (exec_prcmd(prcmd, "PRINT") == 0) {
	if (emptyname(printer))
	    put_msg("Printing on default printer with %s paper size in %s mode ... done",
		paper_sizes[appres.papersize].sname,
		appres.landscape ? "LANDSCAPE" : "PORTRAIT");
	else
	    put_msg("Printing on \"%s\" with %s paper size in %s mode ... done",
		printer, paper_sizes[appres.papersize].sname,
		appres.landscape ? "LANDSCAPE" : "PORTRAIT");
    }
    unlink(tmpfile);
}

/* xoff and yoff are in fig2dev print units (1/72 inch) */

print_to_file(file, lang, mag, xoff, yoff, backgrnd, transparent, 
		use_transp_backg, print_all_layers, border, smooth, grid)
    char	   *file, *lang;
    float	    mag;
    int		    xoff, yoff;
    char	   *backgrnd, *transparent;
    Boolean	    use_transp_backg;
    Boolean	    print_all_layers;
    int		    border;
    Boolean	    smooth;
    char	   *grid;
{
    char	    tmp_name[PATH_MAX];
    char	    tmp_fig_file[PATH_MAX];
    char	   *outfile, *name, *real_lang;

    /* if file exists, ask if ok */
    if (!ok_to_write(file, "EXPORT"))
	return (1);

    sprintf(tmp_fig_file, "%s/%s%06d", TMPDIR, "xfig-fig", getpid());
    /* write the fig objects to a temporary file */
    warnexist = False;
    init_write_tmpfile();
    if (write_file(tmp_fig_file, False)) {
      end_write_tmpfile();
      return (1);
    }
    end_write_tmpfile();

    /* if the user only wants the active layers, build that list */
    build_layer_list(layers);

    outfile = my_strdup(shell_protect_string(file));
    if (strlen(cur_filename) == 0)
	name = my_strdup(file);
    else
	name = my_strdup(shell_protect_string(cur_filename));

    put_msg("Exporting to file \"%s\" in %s mode ...     ",
	    file, appres.landscape ? "LANDSCAPE" : "PORTRAIT");
    app_flush();		/* make sure message gets displayed */
   
    /* change "hpl" to "ibmgl" */
    if (!strcmp(lang, "hpl"))
	lang = "ibmgl";

    real_lang = lang;
    /* if lang is eps_ascii, eps_mono_tiff or eps_color_tiff, call fig2dev with just "eps" */
    if (!strncmp(lang, "eps", 3))
	real_lang = "eps";

    /* if binary CGM, real language is cgm */
    if (!strcmp(lang, "bcgm"))
	real_lang = "cgm";

    /* start with the command, language and internationalization, if applicable */
#ifdef I18N
    sprintf(prcmd, "%s %s -L %s -m %f ", 
		fig2dev_cmd, appres.international ? appres.fig2dev_localize_option : "",
		real_lang, mag/100.0);
#else
    sprintf(prcmd, "%s -L %s -m %f ", fig2dev_cmd, real_lang, mag/100.0);
#endif  /* I18N */

    /* add the -D +list if user doesn't want all layers printed */
    if (!print_all_layers)
	strcat(prcmd, layers);

    /* any grid spec */
    if (strlen(grid) && strcasecmp(grid,"none") !=0 ) {
	strcat(prcmd," -G ");
	strcat(prcmd,grid);
	strcat(prcmd," ");
    }

    /* PostScript or PDF output */
    if (!strcmp(lang, "ps") || !strcmp(lang, "pdf")) {
	sprintf(tmpcmd, "-z %s %s -n %s -x %d -y %d -b %d", 
		paper_sizes[appres.papersize].sname,
		appres.landscape ? "-l xxx" : "-p xxx", 
		name, xoff, yoff, border);
	strcat(prcmd, tmpcmd);

	if (appres.correct_font_size)
	    strcat(prcmd," -F ");
	if (!appres.multiple && !appres.flushleft)
	    strcat(prcmd," -c ");
	if (appres.multiple)
	    strcat(prcmd," -M ");
	if (backgrnd[0]) {
	    strcat(prcmd," -g \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,backgrnd);
	}
	strcat(prcmd," ");
	strcat(prcmd,tmp_fig_file);
	strcat(prcmd," ");
	strcat(prcmd,outfile);

    /* EPS (Encapsulated PostScript) output */
    } else if (!strncmp(lang, "eps", 3)) {	
	/* matches all "eps", "eps_ascii", "eps_mono_tiff" and "eps_color_tiff" */
	sprintf(tmpcmd, "-b %d -n %s", border, name);
	strcat(prcmd, tmpcmd);
	if (appres.correct_font_size)
	    strcat(prcmd," -F ");
	/* add -A, -T or -C for ASCII or mono or color TIFF preview respectively */
	if (!strcmp(lang, "eps_ascii"))
	    strcat(prcmd," -A");
	if (!strcmp(lang, "eps_mono_tiff"))
	    strcat(prcmd," -T");
	else if (!strcmp(lang, "eps_color_tiff"))
	    strcat(prcmd," -C dummy");

	if (backgrnd[0]) {
	    strcat(prcmd," -g \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,backgrnd);
	}
	strcat(prcmd," ");
	strcat(prcmd,tmp_fig_file);
	strcat(prcmd," ");
	strcat(prcmd,outfile);

    /* IBMGL (we know it as "hpl" but it was changed above) */
    } else if (!strcmp(lang, "ibmgl")) {
	sprintf(tmpcmd, "%s %s %s",
		appres.landscape ? "" : "-P",
		tmp_fig_file, outfile);
	strcat(prcmd, tmpcmd);

    /* PSTEX and PDFTEX */
    } else if (!strcmp(lang, "pstex") || !strcmp(lang, "pdftex")) {
	/* do both PostScript (or PDF) part and text part */
	/* first the postscript/PDF part */
	sprintf(tmpcmd, "-b %d -n %s", border, name);
	strcat(prcmd, tmpcmd);
	if (appres.correct_font_size)
	    strcat(prcmd," -F ");

	if (backgrnd[0]) {
	    strcat(prcmd," -g \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,backgrnd);
	}
	strcat(prcmd," ");
	strcat(prcmd,tmp_fig_file);
	strcat(prcmd," ");
	strcat(prcmd,outfile);

	if (!strcmp(lang, "pstex"))
	    (void) exec_prcmd(prcmd, "EXPORT of PostScript part");
	else
	    (void) exec_prcmd(prcmd, "EXPORT of PDF part");

	/* now the text part */
	/* add "_t" to the output filename and put in tmp_name */
	strcpy(tmp_name,outfile);
	strcat(tmp_name,"_t");
	/* make it automatically input the postscript/pdf part (-p option) */
#ifdef I18N
	sprintf(prcmd, "%s %s -L %s -E %d -p %s -m %f ",
		fig2dev_cmd, appres.international ? appres.fig2dev_localize_option : "",
#else
	sprintf(prcmd, "%s -L %s -E %d -p %s -m %f ",
		fig2dev_cmd,
#endif  /* I18N */
		!strcmp(lang,"pstex")? "pstex_t": "pdftex_t",
		appres.encoding, outfile, mag/100.0);
	/* add the -D +list if user doesn't want all layers printed */
	if (!print_all_layers)
	    strcat(prcmd, layers);
	/* finally, append the filenames */
	strcat(prcmd, tmp_fig_file);
	strcat(prcmd, " ");
	strcat(prcmd, tmp_name);

    /* JPEG */
    } else if (!strcmp(lang, "jpeg")) {
	/* set the image quality for JPEG export */
	sprintf(tmpcmd, "-b %d -q %d -S %d", 
		border, appres.jpeg_quality, smooth);
	strcat(prcmd, tmpcmd);

	if (appres.correct_font_size)
	    strcat(prcmd," -F ");
	strcat(prcmd," ");
	strcat(prcmd,tmp_fig_file);
	strcat(prcmd," ");
	strcat(prcmd,outfile);
	if (backgrnd[0]) {
	    strcat(prcmd," -g \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,backgrnd);
	}

    /* GIF */
    } else if (!strcmp(lang, "gif")) {
	sprintf(tmpcmd, "-b %d -S %d",
		border, smooth);
	strcat(prcmd, tmpcmd);

	/* select the transparent color, if any */
	if (transparent) {
	    /* if user wants background transparent, set the background
	        to the transparrent color */
	    if (use_transp_backg)
		backgrnd = transparent;
	    strcat(prcmd," -t \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,transparent);
	}
	if (appres.correct_font_size)
	    strcat(prcmd," -F ");
	if (backgrnd[0]) {
	    strcat(prcmd," -g \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,backgrnd);
	}
	strcat(prcmd," ");
	strcat(prcmd,tmp_fig_file);
	strcat(prcmd," ");
	strcat(prcmd,outfile);

    /* MAP */
    } else if (!strcmp(lang, "map")) {
        /* HTML map needs border option */
	sprintf(tmpcmd, "-b %d %s %s",
		border, tmp_fig_file, outfile);
	strcat(prcmd, tmpcmd);

    /* PCX, PNG, TIFF, XBM, XPM, and PPM */
    } else if (!strcmp(lang, "pcx") || !strcmp(lang, "png") || !strcmp(lang, "tiff") ||
		!strcmp(lang, "xbm") || !strcmp(lang, "xpm") || !strcmp(lang, "ppm")) {
        /* bitmap formats need border option */
	sprintf(tmpcmd, "-b %d -S %d",
		border, smooth);
	strcat(prcmd, tmpcmd);
	if (appres.correct_font_size)
	    strcat(prcmd," -F ");

	if (backgrnd[0]) {
	    strcat(prcmd," -g \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,backgrnd);
	}
	strcat(prcmd," ");
	strcat(prcmd,tmp_fig_file);
	strcat(prcmd," ");
	strcat(prcmd,outfile);

    /* binary CGM? */
    } else if (!strcmp(lang, "bcgm")) {
	/* yes, append -b option */
	strcat(prcmd," -b dum ");
	strcat(prcmd,tmp_fig_file);
	strcat(prcmd," ");
	strcat(prcmd,outfile);

    /* epic, eepic, eepicemu, latex, pictex */
    } else if (!strcmp(lang, "epic") || !strcmp(lang, "eepic") || !strcmp(lang, "eepicemu") ||
		!strcmp(lang, "latex") || !strcmp(lang, "pictex")) {
	sprintf(tmpcmd, "-E %d %s %s",
		appres.encoding, tmp_fig_file, outfile);
	strcat(prcmd, tmpcmd);
    /* tk? */
    } else if (!strcmp(lang, "tk")) {
	/* yes, append background option */
	if (backgrnd[0]) {
	    strcat(prcmd," -g \\");	/* must escape the #rrggbb color spec */
	    strcat(prcmd,backgrnd);
	}
	strcat(prcmd," ");
	sprintf(tmpcmd, "%s %s",
		tmp_fig_file, outfile);
	strcat(prcmd, tmpcmd);
    /* Everything else */
    } else {
	sprintf(tmpcmd, "%s %s",
		tmp_fig_file, outfile);
	strcat(prcmd, tmpcmd);
    }

    /* make a busy cursor */
    set_temp_cursor(wait_cursor);

    /* now execute fig2dev */
    if (exec_prcmd(prcmd, "EXPORT") == 0)
	put_msg("Export to \"%s\" done", file);

    /* and reset the cursor */
    reset_cursor();

    /* free tempnames */
    free(name);
    free(outfile);

    unlink(tmp_fig_file);
    return (0);
}

gen_print_cmd(cmd,file,printer,pr_params)
    char	   *cmd;
    char	   *file;
    char	   *printer;
    char	   *pr_params;
{
    if (emptyname(printer)) {	/* send to default printer */
#if (defined(SYSV) || defined(SVR4)) && !defined(BSDLPR)
	sprintf(cmd, "lp %s %s", 
		pr_params,
		shell_protect_string(file));
#else
	sprintf(cmd, "lpr %s %s",
		pr_params,
		shell_protect_string(file));
#endif /* (defined(SYSV) || defined(SVR4)) && !defined(BSDLPR) */
	put_msg("Printing on default printer with %s paper size in %s mode ...     ",
		paper_sizes[appres.papersize].sname,
		appres.landscape ? "LANDSCAPE" : "PORTRAIT");
    } else {
#if (defined(SYSV) || defined(SVR4)) && !defined(BSDLPR)
	sprintf(cmd, "lp %s -d%s %s",
		pr_params,
		printer, 
		shell_protect_string(file));
#else
	sprintf(cmd, "lpr %s -P%s %s", 
		pr_params,
		printer,
		shell_protect_string(file));
#endif /* (defined(SYSV) || defined(SVR4)) && !defined(BSDLPR) */
	put_msg("Printing on \"%s\" with %s paper size in %s mode ...     ",
		printer, paper_sizes[appres.papersize].sname,
		appres.landscape ? "LANDSCAPE" : "PORTRAIT");
    }
    app_flush();		/* make sure message gets displayed */
}

int
exec_prcmd(command, msg)
    char  *command, *msg;
{
    char   errfname[PATH_MAX];
    FILE  *errfile;
    char   str[400];
    int	   status;

    /* make temp filename for any errors */
    sprintf(errfname, "%s/xfig-export%06d.err", TMPDIR, getpid());
    /* direct any output from fig2dev to this file */
    strcat(command, " 2> "); 
    strcat(command, errfname); 
    if (appres.DEBUG)
	fprintf(stderr,"Execing: %s\n",command);
    status=system(command);
    /* check if error file has anything in it */
    if ((errfile = fopen(errfname, "r")) == NULL) {
	if (status != 0)
	    file_msg("Error during %s. No messages available.",msg);
    } else {
	if (fgets(str,sizeof(str)-1,errfile) != NULL) {
	    rewind(errfile);
	    file_msg("Error during %s.  Messages:",msg);
	    while (fgets(str,sizeof(str)-1,errfile) != NULL) {
		/* remove trailing newlines */
		str[strlen(str)-1] = '\0';
		file_msg(" %s",str);
	    }
	}
	fclose(errfile);
    }
    unlink(errfname);
    return status;
}

/* 
   make an rgb string from color (e.g. #31ab12)
   if the color is < 0, make empty string
*/

make_rgb_string(color, rgb_string)
    int	   color;
    char  *rgb_string;
{
	XColor xcolor;
	if (color >= 0) {
	    xcolor.pixel = x_color(color);
	    XQueryColor(tool_d, tool_cm, &xcolor);
	    sprintf(rgb_string,"#%02x%02x%02x",
				xcolor.red>>8,
				xcolor.green>>8,
				xcolor.blue>>8);
	} else {
	    rgb_string[0] = '\0';	/* no background wanted by user */
	}
}

/* make up the -D option to fig2dev if user wants to print only active layers */

build_layer_list(layers)
    char	*layers;
{
    char	 list[PATH_MAX], notlist[PATH_MAX], num[10];
    int		 layer, len, notlen;
    int		 firstyes, lastyes, firstno, lastno;

    layers[0] = '\0';

    if (print_all_layers)
	return;

    list[0] = notlist[0] = '\0';
    len = notlen = 0;

    /* build up two lists - layers TO print and layers to NOT print */
    /* use the smaller of the two in the final command */

    firstyes = firstno = -1;
    for (layer=min_depth; layer<=max_depth; layer++) {
	if (active_layers[layer] && object_depths[layer]) {
	    if (firstyes == -1)
		firstyes = lastyes = layer;
	    /* see if there is a contiguous set */
	    if (layer-lastyes <= 1) {
		lastyes = layer;	/* so far, yes */
		continue;
	    }
	    append_group(list, num, firstyes, lastyes);
	    firstyes = lastyes = layer;
	    if (len+strlen(list) >= PATH_MAX-5)
		continue;		/* list is too long, don't append */
	    strcat(list,num);
	    len += strlen(list)+1;
	} else if (object_depths[layer]) {
	    if (firstno == -1)
		firstno = lastno = layer;
	    /* see if there is a contiguous set */
	    if (layer-lastno <= 1) {
		lastno = layer;		/* so far, yes */
		continue;
	    }
	    if (firstno == -1)
		firstno = layer;
	    append_group(notlist, num, firstno, lastno);
	    firstno = lastno = layer;
	    if (notlen+strlen(notlist) >= PATH_MAX-5)
		continue;		/* list is too long, don't append */
	    strcat(notlist,num);
	    notlen += strlen(notlist)+1;
	}
    }
    if (firstyes != -1) {
	append_group(list, num, firstyes, lastyes);
	if (len+strlen(list) < PATH_MAX-5) {
	    strcat(list,num);
	    len += strlen(list)+1;
	}
    }
    if (firstno != -1) {
	append_group(notlist, num, firstno, lastno);
	if (notlen+strlen(notlist) < PATH_MAX-5) {
	    strcat(notlist,num);
	    notlen += strlen(notlist)+1;
	}
    }
    if (len < notlen && firstyes != -1) {
	/* use list of layers TO print */
	sprintf(layers," -D +%s ",list);
    } else if (firstno != -1){
	/* use list of layers to NOT print */
	sprintf(layers," -D -%s ",notlist);
    }
}

append_group(list, num, first, last)
    char    *list, *num;
    int	     first, last;
{
    if (list[0])
	strcat(list,",");
    if (first==last)
	sprintf(num,"%0d",first);
    else
	sprintf(num,"%0d:%d",first,last);
}
