/* p_gstate.c
 * Copyright (C) 1997-98 Thomas Merz. All rights reserved.
 *
 * PDFlib routines dealing with the graphics states
 */

#include <stdio.h>
#include <math.h>

#include "p_intern.h"

/* Section 8.3 Special Graphics State */

void
PDF_save(PDF *p)
{
    pdf_end_text(p);
    (void) fputs("q\n", p->fp);
}

void
PDF_restore(PDF *p)
{
    pdf_end_text(p);
    (void) fputs("Q\n", p->fp);
}

void
pdf_concat(PDF *p, PDF_matrix m)
{
    pdf_end_text(p);
    (void) fprintf(p->fp,"%s %s %s %s %s %s cm\n",
		  pdf_float(m.a), pdf_float(m.b), pdf_float(m.c),
		  pdf_float(m.d), pdf_float(m.e), pdf_float(m.f));
}

/* Convenience routines */

void
PDF_translate(PDF *p, float tx, float ty)
{
    (void) fprintf(p->fp,"1 0 0 1 %s %s cm\n", pdf_float(tx), pdf_float(ty));

}

void
PDF_scale(PDF *p, float sx, float sy)
{
    (void) fprintf(p->fp,"%s 0 0 %s 0 0 cm\n", pdf_float(sx), pdf_float(sy));
}

void
PDF_rotate(PDF *p, float phi)
{
    double c, s;

    if (phi == 0)
	return;

    phi = phi * M_PI / 180;	/* convert to radians */

    c = cos(phi);
    s = sin(phi);

    (void) fprintf(p->fp,"%s %s %s %s 0 0 cm\n",
		pdf_float(c), pdf_float(s), pdf_float(-s), pdf_float(c));
}

/* Section 8.4 General Graphics State */

void
PDF_setdash(PDF *p, float d1, float d2)
{
    if (d1 < 0.0 || d2 < 0.0) {
	pdf_error(p, PDF_WARN, "Negative dash values");
	return;
    }

    pdf_end_text(p);
    if (d1 == 0.0 && d2 == 0.0)		/* both zero means solid line */
	(void) fputs("[] 0 d\n", p->fp);
    else
	(void) fprintf(p->fp,"[%s %s] 0 d\n", pdf_float(d1), pdf_float(d2));
}

void
PDF_setpolydash(PDF *p, float *darray, int length)
{
    int i;

    if (length == 0 || length == 1) {	/* length == 0 or 1 means solid line */
	(void) fputs("[] 0 d\n", p->fp);
	return;
    }

    /* sanity checks */
    if (length < 0) {
	pdf_error(p, PDF_WARN, "Negative dash array length");
	return;
    }

    for (i = 0; i < length; i++) {
	if (darray[i] < 0.0) {
	    pdf_error(p, PDF_WARN, "Negative dash value");
	    return;
	}
    }

    pdf_end_text(p);
    (void) fputs("[", p->fp);

    for (i = 0; i < length; i++) {
	(void) fprintf(p->fp,"%s ", pdf_float(darray[i]));
    }
    (void) fputs("] 0 d\n", p->fp);
}

void
PDF_setflat(PDF *p, float flat)
{
    if (flat < 0.0 || flat > 100.0) {
	pdf_error(p, PDF_WARN, "Illegal flat value");
	return;
    }

    pdf_end_text(p);
    (void) fprintf(p->fp,"%s i\n", pdf_float(flat));
}

void
PDF_setlinejoin(PDF *p, byte join)
{
#define LAST_JOIN	2
	if (join > LAST_JOIN) {
		pdf_error(p, PDF_WARN, "Bogus line join value");
		return;
	}

    pdf_end_text(p);
    (void) fprintf(p->fp,"%d j\n", join);
#undef LAST_JOIN
}

void
PDF_setlinecap(PDF *p, byte cap)
{
#define LAST_CAP	2
	if (cap > LAST_CAP) {
		pdf_error(p, PDF_WARN, "Bogus line cap value");
		return;
	}

    pdf_end_text(p);
    (void) fprintf(p->fp,"%d J\n", cap);
#undef LAST_CAP
}

void
PDF_setmiterlimit(PDF *p, float miter)
{
	if (miter < 1.0) {
		pdf_error(p, PDF_WARN, "Bogus miter limit");
		return;
	}

    pdf_end_text(p);
    (void) fprintf(p->fp,"%s M\n", pdf_float(miter));
}

void
PDF_setlinewidth(PDF *p, float width)
{
    pdf_end_text(p);
    (void) fprintf(p->fp,"%s w\n", pdf_float(width));
}
