/* output-p2e.c: utility routines for pstoedit intermediate output

   Copyright (C) 2000-2001 Wolfgang Glunz, Martin Weber 

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA. */

/* Initial author: Wolfgang Glunz - wglunz@pstoedit.net
   use the generated file to run "pstoedit -bo -f format input output"
   Adapted to pstoedit 3.30 by Wolfgang Glunz. */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* Def: HAVE_CONFIG_H */

#include "types.h"
#include "spline.h"
#include "color.h"
#include "output-p2e.h"


#define SIGN(x) ((x) > 0 ? 1 : (x) < 0 ? -1 : 0)
#define ROUND(x) ((int) ((int) (x) + .5 * SIGN (x)))

/* Output macros.  */

/* This should be used for outputting a string S on a line by itself.  */
#define OUT_LINE(l)							\
  fprintf (ps_file, "%s\n", l)

/* These output their arguments, preceded by the indentation.  */
#define OUT1(s, e)							\
  fprintf (ps_file, s, e)

#ifdef withrgbcolor
#define OUT3(s, e1, e2, e3)	  fprintf (ps_file, s, e1, e2, e3)
#else
#define OUT5(s, e1, e2, e3, e4, e5)		  fprintf (ps_file, s, e1, e2, e3, e4, e5)
#endif

#define OUT4(s, e1, e2, e3, e4)						\
  fprintf (ps_file, s, e1, e2, e3, e4)

/* These macros just output their arguments.  */
#define OUT_STRING(st)	fprintf (ps_file, "%s", st)
#define OUT_REAL(r)	fprintf (ps_file,				\
                                 r == ROUND (r) ? "%.0f " : "%.3f ", r)

/* For a PostScript command with two real arguments, e.g., lineto.  OP
   should be a constant string.  */
#define OUT_COMMAND2(first, second, op)					\
  do									\
	{								\
      OUT_STRING (" ");							\
      OUT_REAL (first);							\
      OUT_REAL (second);						\
      OUT_STRING (op "\n");						\
    }									\
  while (0)

/* For a PostScript command with six real arguments, e.g., curveto.
   Again, OP should be a constant string.  */
#define OUT_COMMAND6(first, second, third, fourth, fifth, sixth, op)	\
  do									\
    {									\
      OUT_STRING (" ");							\
      OUT_REAL (first);							\
      OUT_REAL (second);						\
      OUT_STRING (" ");							\
      OUT_REAL (third);							\
      OUT_REAL (fourth);						\
      OUT_STRING (" ");							\
      OUT_REAL (fifth);							\
      OUT_REAL (sixth);							\
      OUT_STRING (" " op "\n");						\
    }									\
   while (0)

/* This should be called before the others in this file.  It opens the
   output file `OUTPUT_NAME.ps', and writes some preliminary boilerplate. */

static int output_p2e_header(FILE* ps_file, at_string name,
			     int  llx, int  lly, int  urx, int  ury, spline_list_array_type shape)
{
  unsigned this_list, with_curves = 1;

  for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
       this_list++)
    {
      unsigned this_spline;

      spline_list_type list = SPLINE_LIST_ARRAY_ELT (shape, this_list);

      for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
           this_spline++)
        {
          spline_type s = SPLINE_LIST_ELT (list, this_spline);

          if (SPLINE_DEGREE (s) != LINEARTYPE)
            {
              with_curves = 0;
              this_list = SPLINE_LIST_ARRAY_LENGTH (shape);
              break;
            }
        }

    }

  OUT_LINE ("%!PS-Adobe-3.0");
  OUT1     ("%%%%Title: flattened PostScript generated by autotrace: %s\n",name);
  OUT_LINE ("%%Creator: pstoedit");
  OUT_LINE ("%%BoundingBox: (atend)");
  OUT_LINE ("%%Pages: (atend)");
  OUT_LINE ("%%EndComments");
  OUT_LINE ("%%BeginProlog");
  OUT_LINE ("/setPageSize { pop pop } def");
  OUT_LINE ("/ntranslate { neg exch neg exch translate } def");
  OUT_LINE ("/setshowparams { pop pop pop} def");
  OUT_LINE ("/awidthshowhex { dup /ASCIIHexDecode filter exch length 2 div cvi string readstring pop awidthshow } def");
  OUT_LINE ("/backendconstraints { pop pop } def");
  OUT_LINE ("/pstoedit.newfont { 80 string cvs  findfont  dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall  /Encoding ISOLatin1Encoding def   dup 80 string cvs /FontName exch def  currentdict end  definefont pop } def");
  OUT_LINE ("/imagestring 1 string def");
  OUT_LINE ("%%EndProlog");
  OUT_LINE ("%%BeginSetup");
  OUT_LINE ("% textastext doflatten backendconstraints  "); 
  OUT1     ("%d 0 backendconstraints\n", with_curves);
  OUT_LINE ("%%EndSetup");

  return 0;
}

/* This outputs the PostScript code which produces the shape in
   SHAPE.  */

static void
out_splines (FILE * ps_file, spline_list_array_type shape)
{
  unsigned this_list;
  unsigned int pathnr = 1;
  spline_list_type list;
  color_type last_color = {0,0,0};

  OUT_LINE (" 612 792 setPageSize");
  OUT_LINE (" 0 setlinecap");
  OUT_LINE (" 10.0 setmiterlimit");
  OUT_LINE (" 0 setlinejoin");
  OUT_LINE (" [ ] 0.0 setdash");
  OUT_LINE (" 1.0 setlinewidth");

  for (this_list = 0; this_list < SPLINE_LIST_ARRAY_LENGTH (shape);
       this_list++)
    {
      unsigned this_spline;
	  spline_type first;

      list = SPLINE_LIST_ARRAY_ELT (shape, this_list);
      first = SPLINE_LIST_ELT (list, 0);


      if (this_list == 0 || !COLOR_EQUAL(list.color, last_color))
        {
          int c, m, y, k;

          OUT_LINE ((shape.centerline || list.open) ? "stroke" : "fill");
          OUT1("\n\n%% %d pathnumber\n",pathnr); 
          OUT_LINE ((shape.centerline || list.open) ? "% strokedpath" : "% filledpath");
          pathnr++;
#ifdef withrgbcolor
          // in the long term this can be removed.
          OUT3 ("%.3f %.3f %.3f setrgbcolor\n",	(real)list.color.r/255.0,
            (real)list.color.g/255.0,
            (real)list.color.b/255.0);
#else
          c = k = 255 - list.color.r;
          m = 255 - list.color.g;
          if (m < k)
            k = m;
          y = 255 - list.color.b;
          if (y < k)
            k = y;
          c -= k;
          m -= k;
          y -= k;
          OUT5("%.3f %.3f %.3f %.3f %s\n", (double) c/255.0, (double) m/255.0,(double) y/255.0, (double) k/255.0, "setcmykcolor");
#endif
          last_color = list.color;
        }

      OUT_LINE ("newpath");
      OUT_COMMAND2 (START_POINT (first).x, START_POINT (first).y, "moveto");

      for (this_spline = 0; this_spline < SPLINE_LIST_LENGTH (list);
        this_spline++)
        {
          spline_type s = SPLINE_LIST_ELT (list, this_spline);

          if (SPLINE_DEGREE (s) == LINEARTYPE)
            OUT_COMMAND2 (END_POINT (s).x, END_POINT (s).y, "lineto");
          else
            OUT_COMMAND6 (CONTROL1 (s).x, CONTROL1 (s).y,
              CONTROL2 (s).x, CONTROL2 (s).y,
              END_POINT (s).x, END_POINT (s).y,
              "curveto");
        }
      if (!list.open) OUT_LINE ("closepath");
    }
  if (SPLINE_LIST_ARRAY_LENGTH(shape) > 0)
    OUT_LINE ((shape.centerline || list.open) ? "stroke" : "fill");
}


int output_p2e_writer(FILE* ps_file, at_string name,
		      int llx, int lly, int urx, int ury, 
		      at_output_opts_type * opts,
		      spline_list_array_type shape,
		      at_msg_func msg_func, 
		      at_address msg_data)
{
  int result;

  result = output_p2e_header(ps_file, name, llx, lly, urx, ury, shape);
  if (result != 0)  return result;

  out_splines(ps_file, shape);

  OUT_LINE ("showpage");
  OUT4 ("%%%%BoundingBox: %d %d %d %d\n", llx, lly, urx, ury);
  OUT_LINE ("%%Page: 1 1");
  OUT_LINE ("% normal end reached by pstoedit.pro");
  OUT_LINE ("%%Trailer");
  OUT_LINE ("%%Pages: 1");
  OUT_LINE ("%%EOF");

  return 0;
}
