
import java.awt.*;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

/**
 * DXFOut - DESCRIPTION
 * <p/>
 * An extension to the Processing project - http://Proce55ing.net
 * <p/>
 * Copyright (c) 2004 Simon Greenwold
 * Created: Feb 11, 2004
 * <p/>
 * 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.
 * <p/>
 * 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.
 * <p/>
 * You should have received a copy of the GNU Lesser General
 * Public License along with the Processing project; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA  02111-1307  USA
 */

public class DXFOut implements Plugin {

  private char triggerKey;
  private String fileName;
  private boolean registered;
  private boolean shouldWrite;

  public BApplet getBApplet() {
    return bApplet;
  }

  private BApplet bApplet;

  public String getVersion() {
    return "0.1a";
  }

  public int getMinCompatibleProcessingVersion() {
    return 68;
  }

  public String getDescription() {
    return "Will write DXF files for use with 3D programs. Only 3D geometry is exported.";
  }

  public void initialize(BApplet bApplet) {
    this.bApplet = bApplet;
    DXFinit();
    if (!bApplet.online()) {
      Frame frame = new Frame();
      frame.setVisible(true);
      frame.setVisible(false);
    }
    bApplet.registerCall(PRE_LOOP_HOOK, new Runnable() {
      public void run() {
        DXFloop();
      }
    });
  }

  public void setTriggerKey(char key, String fileName) {
    triggerKey = key;
    this.fileName = fileName;

    if (!registered) {
      bApplet.registerCall(KEY_PRESSED_HOOK, new Runnable() {
        public void run() {
          keyPressed();
        }
      });
      bApplet.registerCall(POST_LOOP_HOOK, new Runnable() {
        public void run() {
          processKey();
        }
      });
      registered = true;
    }
  }

  private void keyPressed() {
    if (bApplet.key == triggerKey) {
      shouldWrite = true;
    }
    else {
      shouldWrite = false;
    }
  }

  private void processKey() {
    if (shouldWrite) {
      DXFwrite(fileName);
    }
    shouldWrite = false;
  }


//--------- DXFwrite --------------------
// Writes all current triangle-based graphics
// (polygons, boxes, spheres, etc.) to a DXF file.
// Call this at the end of your loop (after everything has drawn).
// But be sure to put a condition like a keypress on it!
// You don't want it running over and over in a loop.
// File will appear in the same folder as the
// Processing executable.

  void DXFwrite(String fileName) {
    try {
      PrintWriter fileWriter = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
      DXFheader(fileWriter);
      DXFgraphics(fileWriter);
      DXFfooter(fileWriter);
      fileWriter.close();
    }
    catch (IOException e) {
      e.printStackTrace();  //To change body of catch statement use Options | File Templates.
      return;
    }
    //saveStrings(fileName, (String[])text.toArray(new String[0]));
    bApplet. println("DXF file \"" + fileName + "\" written with " + bApplet.g.triangles_count + " triangles.");
  }

  final int MAX_TRI_LAYERS = 500000;
  final int DXF_NO_LAYER = -1;
  int currentDXFLayer = 0;
  int[] DXFLayerList = new int[MAX_TRI_LAYERS];

//--------- DXFinit --------------------
// Should be called as the first line of setup()
// Makes sure that graphics are drawn in a way that
// the writer can use.
  void DXFinit() {
    bApplet.hint(BConstants.NEW_GRAPHICS);
    bApplet.lights();
  }

//--------- DXFloop --------------------
// Should be called as the first line of loop()
// It makes sure that all triangles are done in 3D
  void DXFloop() {
    bApplet.rotateX(BConstants.PI/8);
    bApplet.rotateX(-BConstants.PI/8);
    for (int i = 0; i < MAX_TRI_LAYERS; i++) {
      DXFLayerList[i] = DXF_NO_LAYER;
    }
    DXFlayer(0);
  }

// DXFwrite utility functions below. Do not use.
  private void DXFheader(PrintWriter writer) {
    writer.println("0");
    writer.println("SECTION");
    writer.println("2");
    writer.println("ENTITIES");
  }

  private void DXFfooter(PrintWriter writer) {
    writer.println("0");
    writer.println("ENDSEC");
    writer.println("0");
    writer.println("EOF");
  }

  void DXFlayer(int layer) {
    currentDXFLayer = layer;

    if (bApplet.g.triangles_count >= MAX_TRI_LAYERS) {
      return;
    }
    DXFLayerList[bApplet.g.triangles_count] = currentDXFLayer;

  }

  private void DXFgraphics(PrintWriter writer) {
    float a[];
    float b[];
    float c[];

    currentDXFLayer = 0;

    for (int i = 0; i < bApplet.g.triangles_count; i++) {
      a = bApplet.g.vertices[bApplet.g.triangles[i][0]];
      b = bApplet.g.vertices[bApplet.g.triangles[i][1]];
      c = bApplet.g.vertices[bApplet.g.triangles[i][2]];

      if (a[BConstants.VW] != 0.0 && b[BConstants.VW] != 0.0 && c[BConstants.VW] != 0.0) {
        writer.println("0");
        writer.println("3DFACE");
        writer.println("8");

        if (i < MAX_TRI_LAYERS) {
          if (DXFLayerList[i] >= 0) {
            currentDXFLayer = DXFLayerList[i];
          }
        }
        writer.println(Integer.toString(currentDXFLayer));

        writer.println("10");
        writer.println(Float.toString(a[BConstants.VX]/a[BConstants.VW]));
        writer.println("20");
        writer.println(Float.toString(a[BConstants.VY]/a[BConstants.VW]));
        writer.println("30");
        writer.println(Float.toString(a[BConstants.VZ]/a[BConstants.VW]));
        writer.println("11");
        writer.println(Float.toString(b[BConstants.VX]/b[BConstants.VW]));
        writer.println("21");
        writer.println(Float.toString(b[BConstants.VY]/b[BConstants.VW]));
        writer.println("31");
        writer.println(Float.toString(b[BConstants.VZ]/b[BConstants.VW]));
        writer.println("12");
        writer.println(Float.toString(c[BConstants.VX]/c[BConstants.VW]));
        writer.println("22");
        writer.println(Float.toString(c[BConstants.VY]/c[BConstants.VW]));
        writer.println("32");
        writer.println(Float.toString(c[BConstants.VZ]/c[BConstants.VW]));
        writer.println("13");
        writer.println(Float.toString(c[BConstants.VX]/c[BConstants.VW]));
        writer.println("23");
        writer.println(Float.toString(c[BConstants.VY]/c[BConstants.VW]));
        writer.println("33");
        writer.println(Float.toString(c[BConstants.VZ]/c[BConstants.VW]));
      }
    }
  }

}
