package io.measures.passage;

import com.google.common.base.Joiner;
import io.measures.passage.geometry.Model3D;
import io.measures.passage.geometry.Projectable3D;
import io.measures.passage.geometry.SphericalPoint;
import io.measures.passage.geometry.Triangle3D;
import processing.core.PApplet;

import processing.event.KeyEvent;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Sketch
 * @author Dietrich Featherston
 */
public class Sketch extends PApplet {

    protected final long startedAt = System.currentTimeMillis()/1000L;

    protected final String homeDir;
    protected final String baseDataDir;

    protected static final Joiner pathJoiner = Joiner.on(File.separatorChar);

    public Sketch() {

        String homeDir = getParameter("PASSAGE_HOME");
        String userDir = System.getProperty("user.dir");
        if(homeDir == null) {
            homeDir = userDir;
        }
        this.homeDir = homeDir;

        baseDataDir = getParameter("PASSAGE_DATA") == null ? homeDir : getParameter("PASSAGE_DATA");

        // ensure the snapshot directory exists
        new File(getSnapshotDir()).mkdirs();
        // ensure the data dir exists
        new File(getDataDir()).mkdirs();
    }

    public void initSize(String type) {
        size(getTargetWidth(), getTargetHeight(), type);
    }

    public int getTargetWidth() {
        return 1280;
    }

    public int getTargetHeight() {
        return 720;
    }

    public float getAspectRatio() {
        return (float)getTargetWidth() / (float)getTargetHeight();
    }

     @Override
    public final void draw() {
        beforeFrame();
        renderFrame();
        afterFrame();
    }

    protected void beforeFrame() {}
    protected void renderFrame() {}
    protected void afterFrame() {}

    public int darker(int c) {
       return color(round(red(c)*0.6f), round(green(c)*0.6f), round(blue(c)*0.6f));
    }

    public void vertex(Projectable3D p) {
        vertex(p.x(), p.y(), p.z());
    }

    public void line(Projectable3D a, Projectable3D b) {
        line(a.x(), b.y(), b.z(), b.x(), b.y(), b.z());
    }

    void triangles(Projectable3D a, Projectable3D b, Projectable3D c, Projectable3D d) {
        beginShape(TRIANGLES);
        vertex(a);
        vertex(b);
        vertex(c);
        vertex(d);
        vertex(c);
        vertex(b);
        endShape();
    }

    public void renderModel(Model3D model) {
        beginShape(TRIANGLES);
        for(Triangle3D t : model.getTriangles()) {
            vertex(t.a());
            vertex(t.b());
            vertex(t.c());
        }
        endShape();
    }

    public void translate(Projectable3D p) {
        translate(p.x(), p.y(), p.z());
    }

    public void translateNormal(SphericalPoint p) {
        rotateZ(p.phi());
        rotateY(p.theta());
        translate(0, 0, p.r());
    }

    public float noiseZ(float noiseScale, float x, float y, float z) {
        return noise(noiseScale*(x+10000), noiseScale*(y+10000), noiseScale*(z+10000));
    }

    @Override
    public void keyPressed(KeyEvent e) {
        super.keyPressed();
        println("key pressed");
        if (key == ' ') {
            snapshot();
        }
    }

    public void snapshot() {
        System.out.println("saving code and raster");
        long now = System.currentTimeMillis()/1000L;
        copyFile(getSketchSourceFile(), getSnapshotPath("code-" + now + ".java"));
        saveFrame(getSnapshotPath("raster-" + now + ".png"));
    }

    // todo - compatibility
    void copyFile(String from, String to) {
        try {
            String command = "cp " + from + " " + to;
            println("running command \"" + command + "\"");
            Process p = Runtime.getRuntime().exec(command);
            copy(p.getInputStream(), System.out);
            copy(p.getErrorStream(), System.err);
            int exitValue = p.waitFor();
            println("command exited with code " + exitValue);
        }
        catch(Exception ignored) {
            println(ignored.getMessage());
            ignored.printStackTrace();
        }
    }

    void copy(InputStream in, OutputStream out) throws IOException {
        while (true) {
            int c = in.read();
            if (c == -1) break;
            out.write((char)c);
        }
    }

    public String getSketchSourceFile() {
        return pathJoiner.join(getSketchSourcePath(), getSketchPathComponent() + ".java");
    }

    private String getSketchSourcePath() {
        return pathJoiner.join(homeDir, "src/main/java");
    }

    public String getSketchPathComponent() {
        return this.getClass().getName().replace('.', File.separatorChar);
    }

    /**
     * @return the directory to which progress artifacts should be saved
     */
    public String getSnapshotDir() {
        return pathJoiner.join(baseDataDir, getSketchPathComponent(), "snapshots");
    }

    public String getSnapshotPath(String name) {
        return pathJoiner.join(getSnapshotDir(), name);
    }

    public String getDataDir() {
        return pathJoiner.join(baseDataDir, getSketchPathComponent(), "data");
    }

    public String getDataPath(String name) {
        return pathJoiner.join(getDataDir(), name);
    }

    @Override
    public File dataFile(String where) {
        File why = new File(where);
        if (why.isAbsolute()) return why;
        return new File(getDataPath(where));
    }

    @Override
    public String getParameter(String name) {
        return System.getenv(name);
    }

    public void printenv() {
        System.out.println("sketch name: " + this.getClass().getName());
        System.out.println("PASSAGE_HOME=" + homeDir);
        System.out.println("PASSAGE_DATA=" + baseDataDir);
        System.out.println("sketch-specific path = " + getSketchPathComponent());
        System.out.println("sketch source = " + getSketchSourcePath());
        System.out.println("sketch source file = " + getSketchSourceFile());
        System.out.println("snapshot dir = " + getSnapshotDir());
    }
}

@@ -1729,32 +1729,29 @@
     %7D%0A%0A    p
-rotected
+ublic
  void before
@@ -1762,32 +1762,29 @@
 e() %7B%7D%0A    p
-rotected
+ublic
  void render
@@ -1799,24 +1799,21 @@
 %7B%7D%0A    p
-rotected
+ublic
  void af
@@ -2159,269 +2159,8 @@
  %7D%0A%0A
-    void triangles(Projectable3D a, Projectable3D b, Projectable3D c, Projectable3D d) %7B%0A        beginShape(TRIANGLES);%0A        vertex(a);%0A        vertex(b);%0A        vertex(c);%0A        vertex(d);%0A        vertex(c);%0A        vertex(b);%0A        endShape();%0A    %7D%0A%0A
     
@@ -3301,24 +3301,31 @@
 ibility%0A    
+public 
 void copyFil
@@ -3891,16 +3891,23 @@
  %7D%0A%0A    
+public 
 void cop
@@ -5166,22 +5166,41 @@
         
-return
+File sketchSpecificFile =
  new Fil
@@ -5218,24 +5218,164 @@
 th(where));%0A
+        if(sketchSpecificFile.exists()) %7B%0A            return sketchSpecificFile;%0A        %7D%0A        else %7B%0A            return why;%0A        %7D%0A
     %7D%0A%0A    @

load files from user.dir if they aren't in the sketch-specific data dir also mark some methods as public