import processing.core.*; 
import processing.data.*; 
import processing.event.*; 
import processing.opengl.*; 

import ddf.minim.*; 
import ddf.minim.analysis.*; 
import ddf.minim.effects.*; 
import ddf.minim.signals.*; 
import ddf.minim.spi.*; 
import ddf.minim.ugens.*; 
import moonlander.library.*; 
import ch.bildspur.postfx.builder.*; 
import ch.bildspur.postfx.pass.*; 
import ch.bildspur.postfx.*; 

import java.util.HashMap; 
import java.util.ArrayList; 
import java.io.File; 
import java.io.BufferedReader; 
import java.io.PrintWriter; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.IOException; 

public class glitches_0_3_4 extends PApplet {

//IMPORTS FOR LIBRARIES











//shader asignments
PostFXSupervisor supervisor;
InvertPass sobelPass;
Glitches glitches;


//Moonlander audiosync
Moonlander moonlander;

// we pass the canvas through postFX
PGraphics canvas;

//custom font
PFont font;
int fontsize = 0;

// Quote texts
// This is the textscene2 and 3 text
char[] msg1 = "As far as i know,".toCharArray();
char[] msg2 = "you really shouldn't exist.".toCharArray();

public void setup()
{
  //window
  //size(1920, 1080, P2D);
  
  
  //supervisor and new shaders for FX
  supervisor = new PostFXSupervisor(this);
  glitches = new Glitches();
  sobelPass = new InvertPass(this); 
  //graphics canvas
  canvas = createGraphics(width, height, P3D);
  //audio load
  moonlander = Moonlander.initWithSoundtrack(this,"audio.wav",82,4);
  //rasterize and apply font
  font = createFont("C64_Pro-STYLE.ttf",100);
  fontsize = height / 30;
  //init for audio sync
  moonlander.start("localhost", 1338, "data/syncdata.rocket");
}

boolean glitchflash= false;
public void draw()
{
    

  noCursor();
  //update audio and moonlander vars
  moonlander.update();
  float rot = (float) moonlander.getValue("rot");
  int scene = (int) moonlander.getValue("scene");
  float fadeIn = (int) moonlander.getValue("fadein");
  
  if (moonlander.getValue("glitchflash") == 1)
    glitchflash = true;
  else
    glitchflash = false;

  //begin canvas drawing
  canvas.beginDraw();
  canvas.textFont(font);
  
  switch(scene)
  {
    case 0:
      titlescene();
      break;
    case 10:
      thankscene();
      break;
    case 20:
      cubescene(rot);
      break;
    case 30:
      textscene2(fadeIn);
      break;
    case 40:
      cubescene(rot);
      break;
    case 50:
      textscene3(fadeIn);
      break;
    case 60:
      cubescene2(rot,fadeIn);
      break; 
    case 70:
      cubescene2 (rot,fadeIn);
      break;
    case 80:
      cubescene(rot);
      break;
    case 90:
      cubescene3();
      break;
    case 100:
      ballscene();
      break;
    case 110:
      cubetransform();
      break;
    case 420:
      endcredits(fadeIn);
      break;
    case 999:
      exit();
    default:
      cubescene(rot);
  }
  canvas.endDraw();
  //canvas has been drawn
  
  // apply post FX
  blendMode(BLEND);
  supervisor.render(canvas);

  if (glitchflash)
  {
    glitches.shader.set("colorshift",true);
    supervisor.pass(sobelPass);
  }
  else
  {
     glitches.shader.set("colorshift",false);
       
  }
  //scene based selection
  switch(scene)
  {
    case 40:
      supervisor.pass(glitches);
      break;
    case 60:
      supervisor.pass(glitches);
      glitches.shader.set("wiggle",false);
      glitches.shader.set("scan",false);
      glitches.shader.set("colorshift",false);
      
      break;
    case 70:
      glitches.shader.set("wiggle",true);
      glitches.shader.set("scan",false);
      glitches.shader.set("colorshift",true);
      supervisor.pass(glitches);
      break;
    case 100:
      supervisor.pass(glitches);
      break;
    case 110:
      glitches.shader.set("wiggle",true);
      glitches.shader.set("scan",false);
      glitches.shader.set("colorshift",true);
      supervisor.pass(glitches);
      break;
    default:
      supervisor.pass(glitches);
      
      glitches.shader.set("wiggle",false);
      glitches.shader.set("scan",false);
      glitches.shader.set("colorshift",false);
      //do nothing
  }
  supervisor.compose();
  
}
class Glitches implements Pass
{
  PShader shader;

  public Glitches()
  {
    shader = loadShader("glitches.glsl");
    shader.set("iResolution", PApplet.parseFloat(width), PApplet.parseFloat(height));
    shader.set("vignet",true);
  }

  @Override
    public void prepare(Supervisor supervisor) {
    // set parameters of the shader if needed
  }

  @Override
    public void apply(Supervisor supervisor) {
    PGraphics pass = supervisor.getNextPass();
    supervisor.clearPass(pass);

    pass.beginDraw();
    shader.set("iTime", millis()/1.f);
    pass.shader(shader);
    pass.image(supervisor.getCurrentPass(), 0, 0);
    pass.endDraw();
  }
}
class NegatePass implements Pass
{
  PShader shader;

  public NegatePass()
  {
    shader = loadShader("negateFrag.glsl");
    shader.set("iResolution", PApplet.parseFloat(width), PApplet.parseFloat(height));
    
  }

  @Override
    public void prepare(Supervisor supervisor) {
    // set parameters of the shader if needed
  }

  @Override
    public void apply(Supervisor supervisor) {
    PGraphics pass = supervisor.getNextPass();
    supervisor.clearPass(pass);

    pass.beginDraw();
    shader.set("iTime", millis()/1.f);
    pass.shader(shader);
    pass.image(supervisor.getCurrentPass(), 0, 0);
    pass.endDraw();
  }
}
public void ballscene()
{
  float shrink = (float) moonlander.getValue("shrink");
  canvas.background(255);
  canvas.lights();
  //cube
  canvas.pushMatrix();
  canvas.translate(width / 2, height / 2);
  canvas.noStroke();
  canvas.fill((200-shrink*200), 30, 30);
  canvas.sphere(3*75*shrink*shrink);
  
  canvas.popMatrix(); 
  
  

}
public void cubescene(float rot)
{
  float floora = PI/2;
  canvas.background(255);
  canvas.lights();
  //cube
  canvas.pushMatrix();
  canvas.translate(width / 2, height / 3);
  
  canvas.rotateX(radians(rot % 360));
  canvas.rotateZ(radians(rot % 360));
  
  canvas.noStroke();
  canvas.fill(30, 30, 30);
  canvas.box(200);
  canvas.popMatrix(); 
  
  
  //floor
  canvas.pushMatrix();
  canvas.noStroke();
  canvas.fill(250, 250, 250);
  canvas.translate(width / 2, 2*height / 3);
  canvas.rectMode(CENTER);
  canvas.rotateX(floora);
  canvas.rect(0,0,10000,10000);
  canvas.popMatrix(); 
 
  
  canvas.ellipseMode(CENTER);
  for(int i = 100;i>1;i--)
  {
    canvas.pushMatrix();
    canvas.translate(width / 2, (2-(100-i)*0.0002f)*height / 3);
    canvas.rotateX(floora);
    canvas.fill(2.5f*i, 2.5f*i, 2.5f*i);
    canvas.ellipse(0,0,3*i,3*i);
    canvas.popMatrix(); 
  }

}
public void cubescene2(float rot,float fadeIn)
{
  float zoom = (float) moonlander.getValue("zoom");
  float floora = PI/2;
  canvas.background(255);
  canvas.lights();
  //cube
  canvas.pushMatrix();
  canvas.translate(width / 2, height / 3,zoom);
  
  canvas.rotateX(radians(rot % 360));
  canvas.rotateZ(radians(rot % 360));
  
  canvas.noStroke();
 
  float time = (float) moonlander.getCurrentTime();
  
  int bsize = 8;
  float offset = bsize-8*sin((time-3.25f));
  int res = 14;
  canvas.translate(-(offset+bsize)*res/2, -(offset+bsize)*res/2,-(offset+bsize)*res/2);
  for(int x=0;x<res;x++)
  {
    canvas.pushMatrix();
    for(int y=0;y<res;y++)
    {
      
      canvas.translate(0,(bsize+offset));
      
      canvas.pushMatrix();
      for(int z=0;z<res;z++)
      {
        canvas.translate((bsize+offset),0);
        
        float colr =  100*(x+y+z)/(res*2);
        canvas.fill(2.55f*(colr)*fadeIn/100, 30, 30);
        
        canvas.box(bsize);
      }
      canvas.popMatrix();
    }
    canvas.popMatrix();
    
    canvas.translate(0,0,(bsize+offset));
    
  }
  //canvas.box(100);
  canvas.popMatrix(); 
  
  
  //floor
  canvas.pushMatrix();
  canvas.noStroke();
  canvas.fill(250, 250, 250);
  canvas.translate(width / 2, 2.5f*height / 3);
  canvas.rectMode(CENTER);
  canvas.rotateX(floora);
  canvas.rect(0,0,10000,10000);
  canvas.popMatrix(); 
  
  //floorcircle
  canvas.pushMatrix();
  canvas.translate(width / 2, 2.5f*height / 3-1,zoom);
  canvas.fill(30, 30, 30);
  canvas.rotateX(floora);
  canvas.ellipseMode(CENTER);
  float shadowsize = 200-160*sin((time-3.25f));
  canvas.ellipse(0,0,shadowsize,shadowsize);
  canvas.popMatrix(); 
 

  

}
public void cubescene3()
{
  float zoom = (float) moonlander.getValue("zoom");
  float panx = (float) moonlander.getValue("panx");
  canvas.background(225-panx*200);
  canvas.lights();
  //cube
  canvas.pushMatrix();
  canvas.translate((1.35f+panx)*width/2, 1.32f*height / 2,-90+zoom);
  canvas.rotateZ(zoom*0.01f);
  canvas.fill(30, 30, 30);
  int bsize = 140;
  float offset = 200;
  int res = 15;
  canvas.translate(-(offset+bsize)*res/2, -(offset+bsize)*res/2,-(offset+bsize)*res/2);
  for(int x=0;x<res;x++)
  {
    canvas.pushMatrix();
    for(int y=0;y<res;y++)
    {
      
      canvas.translate(0,(bsize+offset));
      
      canvas.pushMatrix();
      for(int z=0;z<res;z++)
      {
        canvas.translate((bsize+offset),0);
        canvas.box(bsize);
      }
      canvas.popMatrix();
    }
    canvas.popMatrix();
    
    canvas.translate(0,0,(bsize+offset));
    
  }
  
  canvas.popMatrix(); 
}
public void cubetransform()
{
  float circletransformx = (float) moonlander.getValue("circletransformx");
  float circletransformy = (float) moonlander.getValue("circletransformy");
  float circletransformz = (float) moonlander.getValue("circletransformz");
  canvas.background(20);
  canvas.lights();
  //cube
  canvas.pushMatrix();
  canvas.translate(width / 2, height / 2);

  
  canvas.stroke(255,255,255);
  canvas.fill(30, 30, 30);
  
  for (int k=0;k<10;k++)
  {
    canvas.pushMatrix();
    canvas.rotateX(k/(2*PI)*circletransformz);
    for (int j=0;j<10;j++)
    {
      canvas.pushMatrix();
      canvas.rotateZ(j/(2*PI)*circletransformy);
      for (int i=0;i<10;i++)
      {
        canvas.pushMatrix();
        canvas.rotateY(i/(2*PI)*circletransformx);
        canvas.box(300);
        canvas.popMatrix();
      }
      canvas.popMatrix();
    }
    canvas.popMatrix();
  }
  
  canvas.popMatrix(); 
}
public void endcredits(float fade)
{
    canvas.background(20);
    canvas.fill(255, 255, 255, fade);
    canvas.textAlign(CENTER, CENTER);
    canvas.textSize(fontsize*2);
    canvas.text("GLITCH_", 5*width/10, 5*height/10);
    canvas.textSize(fontsize);
    canvas.text("made by", 5*width/10, 6*height/10);
    canvas.text("icecryptex & garhuweli", 5*width/10, 7*height/10);
    canvas.text("for Graffathon 2018", 5*width/10, 8*height/10);
}
public void textscene1()
{
  canvas.background(20);
  canvas.textSize(32);
  canvas.fill(255, 255, 255 ,255);
  canvas.textAlign(CENTER, CENTER);
  canvas.textFont(font, fontsize);
  canvas.text("Some text needs to be added", width/2, height/2); 
}
public void textscene2(float amplitude)
{
  canvas.background(20);
  canvas.textSize(fontsize);
  canvas.fill(255, 255, 255 ,255);
  canvas.textAlign(CENTER, CENTER);
  canvas.text(msg1, 0, msg1.length, width/2, 4*height/10);
  canvas.text(msg2, 0, msg2.length, width/2, 5*height/10);
  canvas.loadPixels();
  int[] newPixels = new int[canvas.pixels.length];
  for (int x = 0; x < width; x++) {
    int rowsToShift = (int) (amplitude * noise(x));
    for (int y = x; y < canvas.pixels.length - width; y += width) {
      newPixels[(y + width * rowsToShift) % canvas.pixels.length] = canvas.pixels[y];
    }
  }
  canvas.pixels = newPixels;
  canvas.updatePixels();
}
public void textscene3(float fadeIn)
{
    
  String s1 = "You are just a glitch";
  String s2 = "You are just an anomaly";
  String s3 = "You are just an error";
  String s4 = "You are just a glitch";
  canvas.background(20);
  canvas.textSize(fontsize);
  canvas.fill(255, 255, 255 ,fadeIn);
  canvas.textAlign(CENTER, CENTER);
  int randt = (int) moonlander.getValue("shrink");
  switch(randt)
  {
    case 1:
      canvas.text(s1, width/2, height/2);
      break;
    case 2:
      canvas.text(s2, width/2, height/2);
      break;
    case 3:
      canvas.text(s3, width/2, height/2);
      break;
    case 4:
      canvas.text(s4, width/2, height/2);
      break;
  }
  

}
public void thankscene()
{
  canvas.background(20);
  canvas.textSize(fontsize);
  canvas.fill(255, 255, 255 ,255);
  canvas.textAlign(CENTER, CENTER);
  canvas.text("Thanks to", width/2, height/6);
  canvas.textSize(fontsize/2);
  canvas.text("Song: Abandoned - Corrupt Indulgence", width/2, 3*height/10);
  canvas.text("Font: C64_Pro from style64.org", width/2, 4*height/10);
  canvas.text("Rocket + Moonlander", width/2, 5*height/10);
  canvas.text("Processing", width/2, 6*height/10);
}
public void titlescene()
{
  canvas.background(20);
  canvas.fill(255, 255, 255 ,255);
  canvas.textAlign(LEFT, CENTER);
  canvas.textSize(fontsize*2);
  int row = floor((float)moonlander.getCurrentRow());
  String title = "";
  switch(row) {
    case 0:
      title = "_";
      break;
    case 1:
      title = "G_";
      break;
    case 2:
      title = "GL_";
      break;
    case 3:
      title = "GLI_";
      break;
    case 4:
      title = "GLIT_";
      break;
    case 5:
      title = "GLITC_";
      break;
    case 7:
      title = "GLITCH";
      break;
    case 10:
      title = "GLITCH";
      break;
    case 13:
      title = "GLITCH";
      break;
    case 15:
      title = "GLITCH";
      break;
    default:
      title = "GLITCH_";
  }
  canvas.text(title, 7*width/10, 8*height/10);
}
  public void settings() {  fullScreen(P2D); }
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "glitches_0_3_4" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
