/* $Id: impress.c,v 1.4 2010/10/06 16:02:49 rice Exp $

	PLplot ImPress device driver.
*/
#include "plDevs.h"

#ifdef PLD_imp

#include "plplotP.h"
#include "drivers.h"

/* Device info */
const char* plD_DEVICE_INFO_impress = "imp:Impress File:0:impress:37:imp";

/* Function prototypes */

/* pmr: defined in drivers.h */
/*void plD_dispatch_init_imp	( PLDispatchTable *pdt );*/

void plD_init_imp		(PLStream *);
void plD_line_imp		(PLStream *, short, short, short, short);
void plD_polyline_imp		(PLStream *, short *, short *, PLINT);
void plD_eop_imp		(PLStream *);
void plD_bop_imp		(PLStream *);
void plD_tidy_imp		(PLStream *);
void plD_state_imp		(PLStream *, PLINT);
void plD_esc_imp		(PLStream *, PLINT, void *);

static void flushline(PLStream *);

/* top level declarations */

#define IMPX		2999
#define IMPY		2249

#define BUFFPTS		50
#define BUFFLENG	2*BUFFPTS

/* Graphics control characters. */

#define SET_HV_SYSTEM	0315
#define OPBYTE1		031
#define OPBYTE2		0140
#define SET_ABS_H	0207
#define SET_ABS_V	0211
#define OPWORDH1	0
#define OPWORDH2	150
#define OPWORDV1	0
#define OPWORDV2	150
#define ENDPAGE		0333

#define SET_PEN		0350
#define CREATE_PATH	0346
#define DRAW_PATH	0352
#define OPTYPE		017

static short *LineBuff;
static short FirstLine;
static int penchange = 0, penwidth = 1;
static short count;

void plD_dispatch_init_imp( PLDispatchTable *pdt )
{
#ifndef ENABLE_DYNDRIVERS
    pdt->pl_MenuStr  = "Impress File";
    pdt->pl_DevName  = "imp";
#endif
    pdt->pl_type     = plDevType_FileOriented;
    pdt->pl_seq      = 37;
    pdt->pl_init     = (plD_init_fp)     plD_init_imp;
    pdt->pl_line     = (plD_line_fp)     plD_line_imp;
    pdt->pl_polyline = (plD_polyline_fp) plD_polyline_imp;
    pdt->pl_eop      = (plD_eop_fp)      plD_eop_imp;
    pdt->pl_bop      = (plD_bop_fp)      plD_bop_imp;
    pdt->pl_tidy     = (plD_tidy_fp)     plD_tidy_imp;
    pdt->pl_state    = (plD_state_fp)    plD_state_imp;
    pdt->pl_esc      = (plD_esc_fp)      plD_esc_imp;
}

/*--------------------------------------------------------------------------*\
 * plD_init_imp()
 *
 * Initialize device (terminal).
\*--------------------------------------------------------------------------*/

void
plD_init_imp(PLStream *pls)
{
    PLDev *dev;

/* Initialize family file info */

    plFamInit(pls);

/* Prompt for a file name if not already set */

    plOpenFile(pls);

/* Allocate and initialize device-specific data */

    dev = plAllocDev(pls);

    dev->xold = PL_UNDEFINED;
    dev->yold = PL_UNDEFINED;
    dev->xmin = 0;
    dev->ymin = 0;
    dev->xmax = IMPX;
    dev->ymax = IMPY;
    dev->xlen = dev->xmax - dev->xmin;
    dev->ylen = dev->ymax - dev->ymin;

    plP_setpxl((PLFLT) 11.81, (PLFLT) 11.81);
    plP_setphy(dev->xmin, dev->xmax, dev->ymin, dev->ymax);

    LineBuff = (short *) malloc(BUFFLENG * sizeof(short));
    if (LineBuff == NULL) {
	plexit("Error in memory alloc in plD_init_imp().");
    }
    fprintf(pls->OutFile, "@Document(Language ImPress, jobheader off)");
    fprintf(pls->OutFile, "%c%c", SET_HV_SYSTEM, OPBYTE1);
    fprintf(pls->OutFile, "%c%c%c", SET_ABS_H, OPWORDH1, OPWORDH2);
    fprintf(pls->OutFile, "%c%c%c", SET_ABS_V, OPWORDV1, OPWORDV2);
    fprintf(pls->OutFile, "%c%c", SET_HV_SYSTEM, OPBYTE2);
}

/*--------------------------------------------------------------------------*\
 * plD_line_imp()
 *
 * Draw a line in the current color from (x1,y1) to (x2,y2).
\*--------------------------------------------------------------------------*/

void
plD_line_imp(PLStream *pls, short x1a, short y1a, short x2a, short y2a)
{
    PLDev *dev = (PLDev *) pls->dev;
    int xx1 = x1a, yy1 = y1a, xx2 = x2a, yy2 = y2a;
    int iw;

    if (FirstLine) {
	if (penchange) {
	    fprintf(pls->OutFile, "%c%c", SET_PEN, (char) penwidth);
	    penchange = 0;
	}

    /* Add both points to path */

	count = 0;
	FirstLine = 0;
	*(LineBuff + count++) = (short) xx1;
	*(LineBuff + count++) = (short) yy1;
	*(LineBuff + count++) = (short) xx2;
	*(LineBuff + count++) = (short) yy2;
    }
    else if ((count + 2) < BUFFLENG && xx1 == dev->xold && yy1 == dev->yold) {

    /* Add new point to path */

	*(LineBuff + count++) = (short) xx2;
	*(LineBuff + count++) = (short) yy2;
    }
    else {

    /* Write out old path */

	count /= 2;
	fprintf(pls->OutFile, "%c%c%c", CREATE_PATH, (char) count / 256, (char) count % 256);
	iw = fwrite((char *) LineBuff, sizeof(short), 2 * count, pls->OutFile);
	fprintf(pls->OutFile, "%c%c", DRAW_PATH, OPTYPE);

    /* And start a new path */

	if (penchange) {
	    fprintf(pls->OutFile, "%c%c", SET_PEN, (char) penwidth);
	    penchange = 0;
	}
	count = 0;
	*(LineBuff + count++) = (short) xx1;
	*(LineBuff + count++) = (short) yy1;
	*(LineBuff + count++) = (short) xx2;
	*(LineBuff + count++) = (short) yy2;
    }
    dev->xold = xx2;
    dev->yold = yy2;
}

/*--------------------------------------------------------------------------*\
 * plD_polyline_imp()
 *
 * Draw a polyline in the current color.
\*--------------------------------------------------------------------------*/

void
plD_polyline_imp(PLStream *pls, short *xa, short *ya, PLINT npts)
{
    PLINT i;

    for (i = 0; i < npts - 1; i++)
	plD_line_imp(pls, xa[i], ya[i], xa[i + 1], ya[i + 1]);
}

/*--------------------------------------------------------------------------*\
 * plD_eop_imp()
 *
 * End of page.
\*--------------------------------------------------------------------------*/

void
plD_eop_imp(PLStream *pls)
{
    flushline(pls);
    fprintf(pls->OutFile, "%c", ENDPAGE);
}

/*--------------------------------------------------------------------------*\
 * plD_bop_imp()
 *
 * Set up for the next page.
\*--------------------------------------------------------------------------*/

void
plD_bop_imp(PLStream *pls)
{
    PLDev *dev = (PLDev *) pls->dev;

    FirstLine = 1;
    dev->xold = PL_UNDEFINED;
    dev->yold = PL_UNDEFINED;

    if (!pls->termin)
	plGetFam(pls);

    pls->page++;
}

/*--------------------------------------------------------------------------*\
 * plD_tidy_imp()
 *
 * Close graphics file or otherwise clean up.
\*--------------------------------------------------------------------------*/

void
plD_tidy_imp(PLStream *pls)
{
    free((void *) LineBuff);
    fclose(pls->OutFile);
}

/*--------------------------------------------------------------------------*\
 * plD_state_imp()
 *
 * Handle change in PLStream state (color, pen width, fill attribute, etc).
\*--------------------------------------------------------------------------*/

void 
plD_state_imp(PLStream *pls, PLINT op)
{
    switch (op) {

    case PLSTATE_WIDTH:
	if (pls->width > 0 && pls->width <= 20) {
	    penwidth = pls->width;
	    penchange = 1;
	}
	break;

    case PLSTATE_COLOR0:
	break;

    case PLSTATE_COLOR1:
	break;
    }
}

/*--------------------------------------------------------------------------*\
 * plD_esc_imp()
 *
 * Escape function.
\*--------------------------------------------------------------------------*/

void
plD_esc_imp(PLStream *pls, PLINT op, void *ptr)
{
    (void) pls;				/* pmr: make these used */
    (void) op;
    (void) ptr;
}

/*--------------------------------------------------------------------------*\
 * flushline()
 *
 * Spits out the line buffer.
\*--------------------------------------------------------------------------*/

static void
flushline(PLStream *pls)
{
    int iw;

    count /= 2;
    fprintf(pls->OutFile, "%c%c%c", CREATE_PATH, (char) count / 256, (char) count % 256);
    iw = fwrite((char *) LineBuff, sizeof(short), 2 * count, pls->OutFile);
    fprintf(pls->OutFile, "%c%c", DRAW_PATH, OPTYPE);
    FirstLine = 1;
}

#else
int 
pldummy_impress(void)
{
    return 0;
}

#endif				/* PLD_imp */
