package SimplePostscript;

// SimplePostscript v.0092
// Simple Java library for outputting Postscript graphics.
// See http://process.unlekker.net/SimplePostscript/
//
// Marius Watz - www.unlekker.net


import java.io.*;
import processing.core.PApplet;

/**
 * <p>Title: SimplePostscript</p>
 *
 * <p>Description: Library to write PostScript files from Java or
 * <a href="http://www.processing.org/" target="_blank">Processing</a>.
 * Use by calling the open() function with a filename and coordinates for
 * the bounding box. open() returns a SimplePostscript instance which can be
 * used to draw to the opened file.</p>
 *
 * <p>Copyright: Copyright (c) 2005, Marius Watz</p>
 *
 * @author not attributable
 * @version 0092
 */
public class SimplePostscript implements processing.core.PConstants {
  public boolean isOpen;
  FileWriter out;
  PApplet p;

  public SimplePostscript(PApplet _parent) {
    p=_parent;
  }


  /**
   * Opens a new Postscript file. (x1,y1) - (x2,y2) are the coordinates that
   * define the bounding box. PostScript interpreters might choose to ignore
   * drawing outside this area.
   *
   * @param filename String - name of file to be opened.
   * @param x1 float
   * @param y1 float
   * @param x2 float
   * @param y2 float
   * @return success - True if successful, false otherwise.
   */
  public boolean open(String filename,
     float x1,float y1,
     float x2,float y2) {

  filename=p.savePath(filename);
   System.out.println("SimplePostscript.open("+filename+")");

   try {
     out=new FileWriter(filename);
     isOpen=true;
     println("%!PS-Adobe-3.0 EPSF-3.0");
     println("%%Creator: SimplePostscript");
     println("%%BoundingBox: "+fmt(x1)+" "+fmt(y1)+" "+fmt(x2)+" "+fmt(y2));
     println("%%HiResBoundingBox: "+fmt(x1)+" "+fmt(y1)+" "+fmt(x2)+" "+fmt(y2));
   }
   catch (Exception e) {
     isOpen=false;

     System.out.println("Exception opening file: "+filename);
     return false;
   }

   return true;
 }

 public boolean open(String filename) {
   return open(filename, 0,0,p.width,p.height);
 }


 public void setlinewidth(float w) {
   println(fmt(w) + " setlinewidth");
 }

 public void setlinejoin(int c) {
   println(fmt(c) + " setlinejoin");
 }

 public void setlinecap(int c) {
   println(fmt(c) + " setlinecap");
 }

 public void setdash(String str) {
   println(str + " setdash");
 }

 public void setgray(float g) {
   println(fmt(g) + " setgray");
 }

 public void setcmyk(float c,float m,float y,float k) {
   println(fmt(c) + " " +
       fmt(m) + " " +
       fmt(y) + " " +
       fmt(k) + " setcmykcolor");
 }

 public void setrgb(int r,int g,int b) {
   println(fmt((float)r/255) + " " +
       fmt((float)g/255) + " " +
       fmt((float)b/255) + " setrgbcolor");
 }

 public void setrgb(float r,float g,float b) {
   println(fmt(r/255) + " " +
       fmt(g/255) + " " +
       fmt(b/255) + " setrgbcolor");
 }

 public void setfont(String fontname) {
  println("/"+fontname+" findfont setfont");
 }

 public void setfont(String fontname,float pt) {
  println("/"+fontname+" findfont "+fmt(pt)+" scalefont setfont");
 }

 public void moveto(float x,float y) {
  println(fmt(x)+" "+fmt(p.height-y)+" moveto");
 }

 public void lineto(float x,float y) {
  println(fmt(x)+" "+fmt(p.height-y)+" lineto");
 }

 public void rect(float x1,float y1,float x2,float y2) {
   float hradius, vradius;
   switch (p.g.rectMode) {
   case CORNERS:
     break;
   case CORNER:
     x2 += x1; y2 += y1;
     break;
   case CENTER_RADIUS:
     hradius = x2;
     vradius = y2;
     x2 = x1 + hradius;
     y2 = y1 + vradius;
     x1 -= hradius;
     y1 -= vradius;
     break;
   case CENTER:
     hradius = x2 / 2.0f;
     vradius = y2 / 2.0f;
     x2 = x1 + hradius;
     y2 = y1 + vradius;
     x1 -= hradius;
     y1 -= vradius;
   }

   if (x1 > x2) {
     float temp = x1; x1 = x2; x2 = temp;
   }

   if (y1 > y2) {
     float temp = y1; y1 = y2; y2 = temp;
   }

  moveto(x1,y1);
  lineto(x2,y1);
  lineto(x2,y2);
  lineto(x1,y2);
  lineto(x1,y1);
 }

 public void arc(float x,float y,float rad,float deg1,float deg2) {
  println(fmt(x)+" "+" "+fmt(p.height-y)+" "+
   fmt(rad)+" "+fmt(deg1)+" "+
   fmt(deg2)+" arc");
 }

 public void arcNegative(float x,float y,float rad,float deg1,float deg2) {
   println(fmt(x)+" "+" "+fmt(p.height-y)+" "+
    fmt(rad)+" "+fmt(deg1)+" "+
    fmt(deg2)+" arcn");
 }

 public void circle(float x,float y,float rad) {
  moveto(x+rad,y);
  arc(x,y,rad,0,360);
 }


 public void ellipse(float a,float b,float c,float d) {
   float x=a,y=b,w=c,h=d;
   float kappa = 0.5522847498f;

   if (p.g.ellipseMode == CORNERS) {
     w = (c - a)/2;
     h = (d - b)/2;
     x=a+w;
     y=b+h;
   } else if (p.g.ellipseMode == CENTER_RADIUS) {
     x = a - c;
     y = b - d;
     w = c * 2;
     h = d * 2;

   } else if (p.g.ellipseMode == CORNER) {
     w/=2;
     h/=2;
     x= a + w;
     y = b + h;
   }

   if (w < 0) {  // undo negative width
     x += w;
     w = -w;
   }

   if (h < 0) {  // undo negative height
     y += h;
     h = -h;
   }

   y=p.height-y;

   moveto(w+x,0+y);
   curveto(w+x,kappa*h+y, kappa*w+x,h+y, 0+x,h+y);
   curveto(-kappa*w+x,h+y, -w+x,kappa*h+y, -w+x,0+y);
   curveto(-w+x,-kappa*h+y, -kappa*w+x,-h+y, 0+x,-h+y);
   curveto(kappa*w+x,-h+y, w+x,-kappa*h+y, w+x,0+y);
 }

 public void curveto(
     float x1,float y1,
     float x2,float y2,
     float x3,float y3) {
  println(""+fmt(x1)+" "+fmt(p.height-y1)+" "+
      fmt(x2)+" "+fmt(p.height-y2)+" "+
      fmt(x3)+" "+fmt(p.height-y3)+" curveto");
 }

 public void fill() {
  println("fill");
 }

 public void fillclosepath() {
  println("closepath fill");
 }

 public void stroke() {
  println("stroke");
 }

 public void strokeclosepath() {
  println("closepath stroke");
 }

 public void fillstroke() {
  gsave();
  stroke();
  grestore();
  fill();
 }

 public void fillstrokeclosepath() {
  gsave();
  strokeclosepath();
  grestore();
  fillclosepath();
 }

 public void rotate(float deg) {
  println(fmt(deg)+" rotate");
 }

 public void scale(float x,float y) {
  println(fmt(x)+" "+fmt(y)+" scale");
 }

 public void translate(float x,float y) {
  println(fmt(x)+" "+fmt(-y)+" translate");
 }

 public void gsave() {
  println("gsave");
 }

  public void grestore() {
  println("grestore");
 }

 public void text(float x,float y,String s) {
  if(emptyString(s)) return;
  moveto(x,y);
  println("("+formatString(s)+") show");
 }

 public void println(String s) {
   if(!isOpen) {
     System.err.println("SimplePostscript.println("+s+"): File not open.");
     return;
   }

  try {out.write(s+"\n");}
  catch(IOException e) {System.out.println("IOException!");}
 }

 public void print(String s) {
   if(!isOpen) {
     System.err.println("SimplePostscript.print("+s+"): File not open.");
     return;
   }
  try {out.write(s);}
  catch(IOException e) {System.out.println("IOException!");}
 }

 private static String fmt(float f) {
    double m=Math.pow(10,3);
    f=Math.round(f*m);
    f/=m;

    return ""+f;
 }

 private String formatString(String str) {
  String s,dummy;
  char c;
  int i;

  s="";
  for(i=0; i<str.length(); i++) {
   c=str.charAt(i);
   if(c=='(') s=s+"\\(";
   else if(c==')') s=s+"\\)";
   else if(c=='\\') s=s+"\\\\";
   else if(c=='\n');
   else {s=s+""+c;}
  }
  return s;
 }

 private boolean emptyString(String str) {
  java.lang.Character c;

  for(int i=0; i<str.length(); i++)
   if(Character.isSpaceChar(str.charAt(i))==false) return false;

  return true;
 }

 public void close() {
  System.out.println("SimplePostscript.close()");
  try {
   println("%%EOF\n");
   out.flush();
   out.close();
  } catch(Exception e) {System.out.println("SimplePostscript.close() failed - "+e);}
  isOpen=false;
 }
}

