/* todo:
 - implement all sox effects
 - don't rerender on change of blend-mode
 - add blending option everywhere
 - add blend-effect to blend a selected layer
 - add png corruption
 - add png, jpg, gif and fractal compression artifact effects
 */

import drop.*;
import controlP5.*;
import processing.sound.*;

import java.util.*;
//import processing.net.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import processing.video.*;
import com.hamoid.*;
import java.io.*;
import java.util.Arrays;

Class<?> sketchClass;
VideoExport videoExport;

AudioIn audioIn;
Amplitude loudness;
float volume;
float volumeRoof = 1.0;

int maxFx = 15; //possible amount of effect layers
SDrop drop;
PImage source;
PGraphics renderer;
PImage viewport;
SourceManager sourceManager;
String frameName; //to save frame as image
int uptime; //logs how many frames this software has rendered before (inaccurate, it's actually way, way more)
boolean recording; //save every frame?
int renderSize = 500; //px
float renderFrameRate;
String[] saveData;
String OS;
int w, h;

boolean spawnPlaying = false;
boolean autoPlay = false;
boolean videoRecord = false;
//boolean webcamMode = false;

int micChannel = 0; //which microphone?


//Capture[] cams;
//ArrayList<Capture> cams = new ArrayList<Capture>();

Capture cam;
Capture cam2;

String[] cameras;
int currentCam;

String[] params;



PImage droppedImage;
void dropEvent(DropEvent theDropEvent) {

  sourceManager.importURI(theDropEvent.filePath());
}


SecondApplet gui;
PApplet mainApplet;
void setup() {
  mainApplet = this;
  sketchClass = getClass();
  println(sketchClass);
  size(800, 600);
  w = width;
  h = height;
  frameRate(60);
  surface.setResizable(true);
  surface.setLocation(570, 240);
  noSmooth(); //saves resources but makes sum look shiddy
  imageMode(CENTER);
  drop = new SDrop(this);
  saveData = loadStrings(dataPath("saves.sav"));
  println("Loading Savefile...");
  for (int i = 0; i < saveData.length; i ++) {
    String[] temp;
    if (saveData[i].contains("uptime")) {
      temp = split(saveData[i], " = ");
      uptime = int(temp[1]);
      println("Uptime: " + uptime);
    }
  }
  fallbackImage = loadImage(dataPath("0.png"));
  bin = loadImage(dataPath("bin.png"));

  audioIn = new AudioIn(this, micChannel);
  audioIn.start();
  loudness = new Amplitude(this);
  loudness.input(audioIn);

  cameras = Capture.list();
  /*
  for (int i = 0; i < cameras.length-1; i++) {
   try {
   cams.add(new Capture(this, 1920, 1080, cameras[i]));
   }
   catch(Exception e) {
   println(e);
   }
   }
   */
  //cam =  new Capture(this, 1920,1080, "pipeline:autovideosrc");
  //cam = new Capture(this, 1920,1080, "Video Assist 5\" 3G");
  cam = new Capture(this, 1920, 1080, "OBS Virtual Camera", 60);
  cam2 = new Capture(this, 1920, 1080, "Kamera von „Victors iPhone“", 60);


  OS = getOS();

  String[] args = {"SecondFrame"};
  //gui = new SecondApplet(this);
  gui = new SecondApplet();
  PApplet.runSketch(args, gui);


  renderer = createGraphics(width, height);
  renderer.noSmooth();
  viewport = createImage(renderer.width, renderer.height, ARGB);
  sourceManager = new SourceManager();
  //sourceManager.importURI("/home/giers/.local/bin/fast-style-transfer/data/train2014");
}


PImage webcamImg;
PImage iPhoneImg;
void captureEvent(Capture c) {
  c.read();
  //webcamImg = cam.get();


  if (c == cam) {
    webcamImg = cam.get();
  }
  if (c == cam2) {
    iPhoneImg = cam2.get();
  }
}



void draw() {
  uptime+=1;
  renderFrameRate = frameRate;


  volume = map(loudness.analyze(),0,1,0,volumeRoof); 
  if(volume > 1) volumeRoof -= 0.008;
  //if(webcamRunning){
  //webcamImg =
  // }

  background(255);


  sourceManager.update(); //will write some image to the renderer
  sourceManager.setSource();
  if (autoPlay) gui.robot();
  gui.shaderManager.applyShader(); //boolean animate (iterative calcs), boolean apply (draw)

  background(color(0));
  viewport = renderer.get();

  int imgw, imgh;
  if (renderer.width < renderer.height) {
    imgh = height;
    imgw = int((float(renderer.width)/float(renderer.height))*height);
  } else {
    imgw = width;
    imgh = int(width/(float(renderer.width)/float(renderer.height)));
    if (imgh > height) {
      imgh = height;
      imgw = int((float(renderer.width)/float(renderer.height))*height);
    }
  }
  image(viewport, width/2, height/2, imgw, imgh);

  if (videoRecord) {
    videoExport.saveFrame();
    fill(#ff0000);
    ellipse(width-100, height-100, 30, 30);
  }



  if (recording) {
    snapshot();
    fill(#ff0000);
    ellipse(width-100, height-100, 30, 30);
  }
}


void snapshot() {
  frameName = str(uptime);
  renderer.save(dataPath("")+"/snapshots/" + frameName + ".png");
  saveData[1] = "uptime = " + frameName;
  println("Rendered " + frameName + ".png at " + dataPath("")+"/snapshots/ with a resolution of " + renderer.width + " x " + renderer.height);
  saveStrings(dataPath("saves.sav"), saveData);
}

void mousePressed()
{
  if (mouseButton == LEFT) {
    if (sourceManager.dir != null) {
      sourceManager.importURI(sourceManager.dir + "/" + sourceManager.selection[(int)random(sourceManager.selection.length)]);
    }
  }
  if (mouseButton == RIGHT) {
    snapshot();
  }
}
void mouseWheel(MouseEvent event) {

  if (event.getCount() < 0) renderSize += 8;
  else renderSize -= 8;
  renderSize = constrain(renderSize, 8, 15000);
}

String getOS() {
  String os = System.getProperty("os.name");
  if (os.contains("Windows")) {
    return "windows";
  } else if (os.contains("Mac")) {
    return "mac";
  } else if (os.contains("Linux")) {
    return "linux";
  } else {
    return "other";
  }
}
/*
boolean runCommand(String[] command) {
 //String returnedValues;
 try {
 Process p = new ProcessBuilder(command).start();
 int ii = p.waitFor();
 if (ii == 0) { //success signal
 //BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
 //while ( (returnedValues = stdInput.readLine ()) != null) {
 //println(returnedValues);
 //}
 return(true);
 } else {
 //BufferedReader stdErr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
 //println("Error:");
 //while ( (returnedValues = stdErr.readLine ()) != null) {
 //println(returnedValues);
 //}
 return(false);
 }
 }
 catch (Exception e) {
 //println("Error running command");
 //println(e);
 return(false);
 }
 }*/
int runCommand(String[] command) {
  String returnedValues;
  try {
    println(command);
    Process p = new ProcessBuilder(command).start();
    int ii = p.waitFor();
    BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
    BufferedReader stdErr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
    while ( (returnedValues = stdInput.readLine ()) != null) {
      println(returnedValues);
    }
    while ( (returnedValues = stdErr.readLine ()) != null) {
      println(returnedValues);
    }

    println(ii);
    return(ii);
  }
  catch (Exception e) {
    println("Error running command");
    println(command);
    println(e);
    return(3); //error signal
  }
}
