/*
 * Open Source Physics software is free software as described near the bottom of this code file.
 *
 * For additional information and documentation on Open Source Physics please see:
 * <http://www.opensourcephysics.org/>
 */

package org.jibble.epsgraphics;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;

/**
 * This represents an EPS document. Several EpsGraphics2D objects may point
 * to the same EpsDocument.
 *  <p>
 * Copyright Paul Mutton,
 *           <a href="http://www.jibble.org/">http://www.jibble.org/</a>
 *
 */
public class EpsDocument {
  /**
   * Constructs an empty EpsDevice.
   * @param title
   */
  public EpsDocument(String title) {
    _title = title;
    minX = Float.POSITIVE_INFINITY;
    minY = Float.POSITIVE_INFINITY;
    maxX = Float.NEGATIVE_INFINITY;
    maxY = Float.NEGATIVE_INFINITY;
    _stringWriter = new StringWriter();
    _bufferedWriter = new BufferedWriter(_stringWriter);
  }

  /**
   * Constructs an empty EpsDevice that writes directly to a file.
   * Bounds must be set before use.
   * @param title
   * @param outputStream
   * @param minX
   * @param minY
   * @param maxX
   * @param maxY
   * @throws IOException
   */
  public EpsDocument(String title, OutputStream outputStream, int minX, int minY, int maxX, int maxY) throws IOException {
    _title = title;
    this.minX = minX;
    this.minY = minY;
    this.maxX = maxX;
    this.maxY = maxY;
    _bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
    write(_bufferedWriter);
  }

  /**
   * Returns the title of the EPS document.
   */
  public synchronized String getTitle() {
    return _title;
  }

  /**
   * Updates the bounds of the current EPS document.
   */
  public synchronized void updateBounds(double x, double y) {
    if(x>maxX) {
      maxX = (float) x;
    }
    if(x<minX) {
      minX = (float) x;
    }
    if(y>maxY) {
      maxY = (float) y;
    }
    if(y<minY) {
      minY = (float) y;
    }
  }

  /**
   * Appends a line to the EpsDocument.  A new line character is added
   * to the end of the line when it is added.
   */
  public synchronized void append(EpsGraphics2D g, String line) {
    if(_lastG==null) {
      _lastG = g;
    } else if(g!=_lastG) {
      EpsGraphics2D lastG = _lastG;
      _lastG = g;
      // We are being drawn on with a different EpsGraphics2D context.
      // We may need to update the clip, etc from this new context.
      if(g.getClip()!=lastG.getClip()) {
        g.setClip(g.getClip());
      }
      if(!g.getColor().equals(lastG.getColor())) {
        g.setColor(g.getColor());
      }
      if(!g.getBackground().equals(lastG.getBackground())) {
        g.setBackground(g.getBackground());
      }
      // We don't need this, as this only affects the stroke and font,
      // which are dealt with separately later on.
      // if (!g.getTransform().equals(lastG.getTransform())) {
      // g.setTransform(g.getTransform());
      // }
      if(!g.getPaint().equals(lastG.getPaint())) {
        g.setPaint(g.getPaint());
      }
      if(!g.getComposite().equals(lastG.getComposite())) {
        g.setComposite(g.getComposite());
      }
      if(!g.getComposite().equals(lastG.getComposite())) {
        g.setComposite(g.getComposite());
      }
      if(!g.getFont().equals(lastG.getFont())) {
        g.setFont(g.getFont());
      }
      if(!g.getStroke().equals(lastG.getStroke())) {
        g.setStroke(g.getStroke());
      }
    }
    _lastG = g;
    try {
      _bufferedWriter.write(line+"\n");                                 //$NON-NLS-1$
    } catch(IOException e) {
      throw new EpsException("Could not write to the output file: "+e); //$NON-NLS-1$
    }
  }

  /**
   * Outputs the contents of the EPS document to the specified
   * Writer, complete with headers and bounding box.
   */
  public synchronized void write(Writer writer) throws IOException {
    float offsetX = -minX;
    float offsetY = -minY;
    writer.write("%!PS-Adobe-3.0 EPSF-3.0\n");                                                                   //$NON-NLS-1$
    writer.write("%%Creator: EpsGraphics2D "+EpsGraphics2D.VERSION+" by Paul Mutton, http://www.jibble.org/\n"); //$NON-NLS-1$ //$NON-NLS-2$
    writer.write("%%Title: "+_title+"\n");                                                                        //$NON-NLS-1$ //$NON-NLS-2$
    writer.write("%%CreationDate: "+new Date()+"\n");                                                             //$NON-NLS-1$ //$NON-NLS-2$
    writer.write("%%BoundingBox: 0 0 "+((int) Math.ceil(maxX+offsetX))+" "+((int) Math.ceil(maxY+offsetY))+"\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    writer.write("%%DocumentData: Clean7Bit\n");      //$NON-NLS-1$
    writer.write("%%DocumentProcessColors: Black\n"); //$NON-NLS-1$
    writer.write("%%ColorUsage: Color\n");            //$NON-NLS-1$
    writer.write("%%Origin: 0 0\n");                  //$NON-NLS-1$
    writer.write("%%Pages: 1\n");                     //$NON-NLS-1$
    writer.write("%%Page: 1 1\n");                    //$NON-NLS-1$
    writer.write("%%EndComments\n\n");                //$NON-NLS-1$
    writer.write("gsave\n");                          //$NON-NLS-1$
    if(_stringWriter!=null) {
      writer.write(offsetX+" "+(offsetY)+" translate\n");             //$NON-NLS-1$ //$NON-NLS-2$
      _bufferedWriter.flush();
      StringBuffer buffer = _stringWriter.getBuffer();
      for(int i = 0; i<buffer.length(); i++) {
        writer.write(buffer.charAt(i));
      }
      writeFooter(writer);
    } else {
      writer.write(offsetX+" "+((maxY-minY)-offsetY)+" translate\n"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    writer.flush();
  }

  private void writeFooter(Writer writer) throws IOException {
    writer.write("grestore\n"); //$NON-NLS-1$
    if(isClipSet()) {
      writer.write("grestore\n"); //$NON-NLS-1$
    }
    writer.write("showpage\n"); //$NON-NLS-1$
    writer.write("\n");         //$NON-NLS-1$
    writer.write("%%EOF");      //$NON-NLS-1$
    writer.flush();
  }

  public synchronized void flush() throws IOException {
    _bufferedWriter.flush();
  }

  public synchronized void close() throws IOException {
    if(_stringWriter==null) {
      writeFooter(_bufferedWriter);
      _bufferedWriter.flush();
      _bufferedWriter.close();
    }
  }

  public boolean isClipSet() {
    return _isClipSet;
  }

  public void setClipSet(boolean isClipSet) {
    _isClipSet = isClipSet;
  }

  private float minX;
  private float minY;
  private float maxX;
  private float maxY;
  private boolean _isClipSet = false;
  private String _title;
  private StringWriter _stringWriter;
  private BufferedWriter _bufferedWriter = null;
  // We need to remember which was the last EpsGraphics2D object to use
  // us, as we need to replace the clipping region if another EpsGraphics2D
  // object tries to use us.
  private EpsGraphics2D _lastG = null;

}

/*
 * Open Source Physics software is free software; you can redistribute
 * it and/or modify it under the terms of the GNU General Public License (GPL) as
 * published by the Free Software Foundation; either version 2 of the License,
 * or(at your option) any later version.

 * Code that uses any portion of the code in the org.opensourcephysics package
 * or any subpackage (subdirectory) of this package must must also be be released
 * under the GNU GPL license.
 *
 * This software 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
 * or view the license online at http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2007  The Open Source Physics project
 *                     http://www.opensourcephysics.org
 */
