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

import moonlander.library.*; 
import java.io.DataOutputStream; 
import java.io.DataInputStream; 
import java.io.IOException; 
import ddf.minim.*; 

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 graffathon extends PApplet {





// Minim must be imported when using Moonlander with soundtrack.


Moonlander moonlander;
PFont t, g;


float d = 1;
int size;
float tStart;

float xDef, yDef, zDef, sizeDef, distanceDef;

String kela, drunch, greet, uki, deka, lors, semilors, title, presents, graffathon, tommila, kala, eeli, music, code;
float xorig, yorig, vx, xpos, ypos, hue, custart, cupos, cpos;
int titleSize, greetSize, cur, bpm;
Letter[] dGreet, tit;
Letter cu;
float[] lin, noises;
boolean setup;
ArrayList<ArrayList<Integer>> values;
ArrayList<Float> nois;
public void setup() {
    
    //size(200, 200, P3D);
    size = width * height;
    noCursor();
    noises = new float[72];
    values = new ArrayList<ArrayList<Integer>>();
    nois = new ArrayList<Float>();
    noiseSeed(0);
    frameRate(60);
    bpm = 82;    
    moonlander = Moonlander.initWithSoundtrack(this, "./data/Helium.mp3", bpm, 8);
    xDef = 1000;
    yDef = 2000;
    zDef = 0;
    sizeDef = 1;
    distanceDef = 500;
    greet = "Greetings to:";
    deka = "dekadenssi boys";
    lors = "FK-Lörs";
    semilors = "FK-Semilörs";
    uki = "ukimies";
    title = "Pelkkää pöhinää";
    presents = "fkbois @ Graffathon 2018 presents:";
    graffathon = "Graffathon 2018";
    tommila = "tommila";
    kala = "kalamies";
    eeli = "eeli";
    music = "Music";
    code = "Code";
    drunch = "Drunch pizza";
    kela = "Kela";
    greetSize = height/deka.length();
    titleSize = ceil((width/(title.length())));
    t = createFont("./data/fonts/Black_Ops_One/BlackOpsOne-Regular.ttf", titleSize);
    g = createFont("./data/fonts/Righteous-Regular.ttf", greetSize);
    textFont(t);
    textAlign(CENTER,CENTER);
    background(0);
    fill(240,100,100);
    text("Loading",width/2, height/2);
    colorMode(HSB, 360, 100, 100);
    dGreet = letterList(deka,width, titleSize/2, g, greetSize);
    setup=true;
}



public String[][] grid() {
  String[][] g = new String[10][100];
  for (int x=0;x<g.length;x++) {
    for (int z=0;z<g[0].length;z++) {
      g[x][z] = Integer.toString((int) random(10));
    }
  }
  return g;
}

String[][] l = grid();

int m = 0;
float[][][] coords = { { {0,2}, {1,3}, {2,1}, {2,2}, {2,3} } , { {1,1}, {1,3}, {2,2}, {2,3}, {3,2} } , { {1,3}, {2,1}, {2,3}, {3,2}, {3,3} } , { {1,3}, {2,3}, {2,4}, {3,2}, {3,3} } };


public float[] drawGlider(int j, float time) {
    int step = 15;
    color(255);
    noStroke();
    lights();
    float[][] data = gliderCoords(step, time, coords[j]);
    for (int i=0; i<data.length; i++) {
      pushMatrix();
      translate(data[i][0], data[i][1]);
      fill(255);
      box(step);
      popMatrix();
    }
    return data[0];
}

public float[][] gliderCoords(int step, float time, float[][] coords) {
    float[][] out = new float[coords.length][coords[0].length];
    for (int i=0; i<coords.length; i++) {
      float[] a = {step*coords[i][0]+time, step*coords[i][1]+time};
      out[i] = a;
    }
    return out;
}



public void drawNumberGrid(int xPos, int yPos, int zPos, float t1, float t2, float t3) {
  int size = 15;
  pushMatrix();
  translate(xPos, yPos, zPos);
  rotateZ(radians(60));
  for (int x=0;x<10;x++) {
    for (int z=0;z<100;z++) {
      pushMatrix();
      fill(0, 255, 0);
      textSize(2*size);
      translate(x*size, 0, 2*size*z-50*size);
      if (x==0 || x==4 || x==8) translate(0, 0, t1);
      if (x==1 || x==3 || x==5 || x==7 || x==9) translate(0, 0, t2);
      if (x==2 || x==6) translate(0, 0, t3);
      rotateX(radians(-90));      
      text(l[x][z], 0, 0, 0);
      popMatrix();
    }
  }
  fill(0);
  noStroke();
  rotateX(radians(-90));
  rotateZ(radians(180));
  rectMode(CORNERS);
  translate(0, 0, 1);
  rect(size, 20*size, -size*11, 1000);
  rect(size, 0, -size*11, -1000);
  popMatrix();
  
}

//void drawTerrain(int xPos, int yPos, int zPos) {
  



public void draw() {
    if(setup){
      lin = linspace(1.0f,-10.0f,72);
      noises = linspace(0.0f, 4.672f, 72);
      for(int j = 0; j < 72; j++){
        values.add(new ArrayList<Integer>());
        float x0 = 0.001643721971153f;
        float y0 = -0.822467633298876f;
        float scale = exp(lin[j]);
        for (int i = 0; i < size; i++) {
         
          int xIndex = i % width;
          int yIndex = i / width;
         
          float xNormalized = map((xIndex - width/2), -height/2, height/2, -1, 1);
          float yNormalized = map((yIndex - height/2), -height/2, height/2, -1, 1);
         
          float xInc = x0 + scale * xNormalized;
          float yInc = y0 + scale * yNormalized;
          
          float x = 0.0f;
          float y = 0.0f;
          int max_iteration = 100;
          int iteration = 0;
          while (x * x + y * y < 4 && iteration < max_iteration) {
            float xTemp = x * x - y * y + xInc;
            y = 2 * x * y + yInc;
            x = xTemp;
            iteration += 1;
          }
          values.get(j).add(iteration);
      }
      nois.add(noise(noises[j]));
    }
      moonlander.start("localhost", 1338, "./data/syncdata.rocket");
      setup = !setup;
    }else{
    moonlander.update();
    float time = (float) moonlander.getCurrentTime();
    //println(time);
    
    int flag = (int) moonlander.getValue("flag");

    if (flag == 2) draw1(tStart); else if (flag == 1) draw2(); else draw3(time);
    
    int exit = (int) moonlander.getValue("exit");
    
    if (exit == 1) exit();
    }
}

public void draw1(float tStart) {
  
    colorMode(RGB, 255);  
  
    float t1 = (float) moonlander.getValue("xEye");
    float t2 = (float) moonlander.getValue("yEye");
    float t3 = (float) moonlander.getValue("zEye");
    
    float t4 = (float) moonlander.getValue("xCenter");
    float t5 = (float) moonlander.getValue("yCenter");
    float t6 = (float) moonlander.getValue("zCenter");
    
    float t7 = (float) moonlander.getValue("Grid1Pos");
    float t8 = (float) moonlander.getValue("Grid2Pos");
    float t9 = (float) moonlander.getValue("Grid3Pos");
    
    float fade = (float) moonlander.getValue("fade");
    
    background(0);
    
    float time = (float) moonlander.getCurrentTime() - tStart;
    
    float[] center = drawGlider(m/10%4, 100*time);
    m += 1;
    if (m/10%4 == 0) { d+=0.01f; }
    
    /*stroke(255);
    line(0, 0, 0, 0, 0, 1000);
    stroke(255);
    line(0, 0, 0, 0, 1000, 0);
    stroke(255);
    line(0, 0, 0, 1000, 0, 0);*/
    
    float eyeX, eyeY, eyeZ;
    float centerX, centerY, centerZ;
    float upX, upY, upZ;
    
    eyeX = t1;
    eyeY = t2;
    eyeZ = t3;
    
    centerX = t4;
    centerY = t5;
    centerZ = t6;
    
    upX = 0;
    upY = 0;
    upZ = -1;
    
    camera(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
    
    fill(255);
    pushMatrix();
    translate(1300, 900, 200);
    rotateX(radians(-90));
    rotateY(radians(-60));
    textSize(60);
    text("sample text", 1800-150*time, 0, 0);
    popMatrix();
    
    drawNumberGrid(1000, 200, -200, t7, t8, t9);
    
    float x = xDef;
  float y = yDef;
  float z = zDef;
  float size = sizeDef;
  float distance = distanceDef;
 
  pushMatrix();
  //rotateZ(radians(45));
  fill(128);
  stroke(0);
  strokeWeight(1);
  pushMatrix();
  translate(x, y, z);
  //rotateZ(radians(45));
  box(10 * size, 200 * size, 120 * size);
  popMatrix();
 
  pushMatrix();
  translate((x + distance) * size, y * size, z * size);
  //rotateZ(radians(45));
  box(10 * size, 200 * size, 120*size);
  popMatrix();
 
  //blackbox
  pushMatrix();
  translate((x-100), y-50, z);
  rotateZ(radians(90));
  fill(0);
  stroke(0);
  box(30 * size, 200 * size, 120 * size);
  popMatrix();
 
  pushMatrix();
  translate((x + distance+ 100) * size, y * size - 100, z *size);
  rotateZ(radians(90));
  fill(0);
  stroke(0);
  box(30 * size, 200 * size, 120 * size);
  popMatrix();
 
  //ball
  float xPosDef = (float) moonlander.getValue("zPos");
  float xPos = map(xPosDef, -1, 1, x - 40 , x + distance + 40);
  pushMatrix();
  translate(xPos, y*size, z);
  //rotateZ(radians(45));
  colorMode(HSB, 100);
  stroke(30 + xPosDef * 50, 80, 80);
  fill(30 + xPosDef * 50, 80, 80);
  sphere(40*size);
  popMatrix();
 
  colorMode(RGB, 255);
 
 
  pushMatrix();
  translate(x+6, y, z);
  rotateY(radians(90));
  fill(0);
  stroke(253,102,0);
  strokeWeight(4);
  ellipse(0, 0, 96*size, 180*size);
  popMatrix();
 
  pushMatrix();
  translate((x + distance) * size -6, y * size, z * size);
  rotateY(radians(90));
  fill(0);
  stroke(0,120,255);
  strokeWeight(4);
  ellipse(0, 0, 96, 180);
  popMatrix();
  
  popMatrix();
  
}

public void draw2() {
    colorMode(HSB, 100);
    loadPixels();
    int frame = (int) moonlander.getValue("scale");
    for (int i = 0; i < size; i++) {
      float noiseVal = nois.get(frame);
      int iteration = values.get(frame).get(i);
      //float fade = (float) moonlander.getValue("fade");
      float col2 = 100-(iteration * (1+noiseVal))%100;
      int c = color(iteration, col2, col2);
      pixels[i] = c;
    }
    updatePixels();
    tStart = (float) moonlander.getCurrentTime();
  }
  
public void draw3(float time){
  pushMatrix();
  background(0);
  //float time = (float) moonlander.getCurrentTime();
  int b = floor(((time) * (bpm / 60.0f))/2-0.5f)+1;
  //println(time);
  //println(b);
  textFont(g,greetSize);
  for (int i = 0; i < dGreet.length; i++){
    Letter l = dGreet[i];
    xorig = l.xhome;
    hue = map(noise(time,i),0,1,0,360);
    int col = color(hue, 100,100);
    l.setColor(col);
    xpos = xorig + vx * time;
    ypos = yorig + (yorig/2) * sin(xpos/30);
    l.move(xpos,ypos);
    l.draw();
  }
  if(b<16){
  textFont(t);
  textSize(titleSize);
  textAlign(CENTER, CENTER);
  if(b >= 1){
    textFont(t);
    textSize(0.6f*titleSize);
    text(presents, width/2, textAscent());
  }
  textSize(titleSize);
  if(b>=2 && b<3){
    textFont(t);
    textAlign(CENTER,TOP);
    text(title, width/2, height/4);
    fill(0);
    rect(width/2, height/4, width/2, height/2);
  }
  if (b >= 3){
    textFont(t);
    textAlign(CENTER, TOP);
    text(title, width/2, height/4);
  }
  textFont(g);
  if (b >= 4 && b < 10) text(music, width/2, height/(2.5f));
  if (b >= 5 && b < 10) text(uki, width/2, height/(2.5f)+0.1f*height);
  if (b >= 6 && b < 10) text(code, width/2, height/(2.5f)+0.2f*height);
  if (b >= 7 && b < 10) text(tommila, width*0.25f, height/(2.5f)+0.3f*height);
  if (b >= 8 && b < 10) text(kala, width/2, height/(2.5f)+0.3f*height);
  if (b >= 9 && b < 10) text(eeli, width*0.75f, height/(2.5f)+0.3f*height);
  if (b >= 10 && b < 11) text(greet, width/2, height/2);
  if (b >= 11 && b < 13){
    textAlign(CENTER, CENTER);
    text(deka, width/2, height/2);
  }
  if (b >= 12 && b < 13){
    textAlign(CENTER, CENTER);
    text(semilors, width/2, height*0.75f);
  }
  if (b >= 13){
    textAlign(CENTER, CENTER);
    text(lors, width/2, height/2.2f);
  }
  if (b >= 14){
    textAlign(CENTER, CENTER);
    text(drunch, width/2, height/2.2f + 0.1f*height);
  }
  if (b >= 15){
    textAlign(CENTER, CENTER);
    text(kela, width/2, height/2.2f + 0.2f*height);
  }
  }
  /*if(b < 17){
    for(int i = 1; i < b; i++){
     tit[i-1].draw();
    }
  }*/
  popMatrix();
}
  
class Letter {
  char letter;
  float x, y, xhome, yhome;
  int col;
  Letter(float x_, float y_, char c, int col_) {
    x = x_;
    xhome = x_;
    y = y_;
    yhome = y_;
    letter = c;
    col = col_;
  }
  public void draw(){
    fill(col);
    textAlign(LEFT,CENTER);
    text(letter, x, y);
  }
  public void move(float dx, float dy){
    x = dx;
    y = dy;
  }
  public void setColor(int col_){
    col = col_;
  }
}
public Letter[] letterList(String s, float x, float y, PFont font, int textSize){
  textFont(font);
  textSize(textSize);
  Letter[] ls = new Letter[s.length()];
  for (int i = 0; i < ls.length; i++) {
    ls[i] = new Letter(x,y,s.charAt(i), color(120,50,50)); 
    x += textWidth(s.charAt(i));
  }
  return ls;
}
public float[] linspace(float min, float max, int points) {  
    float[] f = new float[points];  
    for (int i = 0; i < points; i++){  
        f[i] = min + i * (max - min) / (points - 1);  
    }  
    return f;  
}  
  public void settings() {  fullScreen(P3D); }
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "graffathon" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
