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

import moonlander.library.*; 
import ddf.minim.*; 
import ddf.minim.analysis.*; 
import ddf.minim.effects.*; 
import ddf.minim.signals.*; 
import ddf.minim.spi.*; 
import ddf.minim.ugens.*; 

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













PVector camera_target;
PVector camera_dir;
float angle_x;
float angle_y;
float angle_z;

ModArea pinkArea;
SweepArea sweepArea;

PImage star_field;

Moonlander moonLander;

//int width = 1024;
//int height = 720;


public void settings() {
  fullScreen(P3D);
  //size(width, height, P3D);
}

public void setup()
{
  
  camera_target = new PVector(width/2, height/2, 0.0f);
  camera_dir = new PVector(0.0f, 0.0f, 0.0f);
  angle_x = 0.0f;
  angle_y = 0.0f;
  angle_z = 0.0f;

  star_field = loadImage("star_field.png");

  pinkArea = new ModArea(new PVector(0, 0, 0), 10.0f, 3.0f);
  sweepArea = new SweepArea();
  moonLander = Moonlander.initWithSoundtrack(this, "space_song.mp3", 190, 4);
  moonLander.start();

  // noStroke();
}

public void draw() {
  moonLander.update();

  // Star background

  background(0);
  ortho();
  hint(DISABLE_DEPTH_MASK);
  image(star_field, 0, 0);
  hint(ENABLE_DEPTH_MASK);

  float fovOffset = (float)moonLander.getValue("fov_offset");
  float fov = PI / 3.0f + radians(fovOffset);
  float aspect = (float)width / (float)height;
  float near_clip = 0.1f;
  float far_clip = 400;
  perspective(fov, aspect, near_clip, far_clip);

  // background(100);
  // Position x, y, z. Center of scene x y z, up vector
  //camera_dir.add(0.1, 0.0, 0.0);
  float camera_depth = (float)moonLander.getValue("Camera_offset");
  camera_target.add(camera_dir);
  camera(width/2, height/2, 150 + camera_depth,
         camera_target.x, camera_target.y, camera_target.z,
         0.0f, 1.0f, 0.0f);

  angle_x = (float)moonLander.getValue("angle_x") / 100.0f;
  angle_y = (float)moonLander.getValue("angle_y") / 100.0f;
  angle_z = (float)moonLander.getValue("angle_z") / 100.0f;

  pinkArea.Sync(moonLander);
  sweepArea.Sync(moonLander);
  // Rendering

  pushMatrix();
  translate(width/2, height/2, 0); // set new center for all cubes

  int minCoord = -100;
  int maxCoord = 100;
  int stepCoord = (int)moonLander.getValue("grid_step");
  if (stepCoord < 12)
    {
      stepCoord = 12;
    }

  float black_size = 1.0f + (float)moonLander.getValue("black_size");

  for (int z = minCoord; z < maxCoord; z += stepCoord) {
    for (int x = minCoord; x < maxCoord; x += stepCoord) {
      for (int y = minCoord; y < maxCoord; y += stepCoord) {
        // Translate individual box
        pushMatrix();
        // Rotate box around center
        rotateX(angle_x);
        rotateY(angle_y);
        rotateZ(angle_z);
        translate(x, y, z);

        PVector cube_pos = new PVector(x, y, z);
        if (pinkArea.InRange(cube_pos)) {
          fill(pinkArea.GetCubeColor());
          stroke(pinkArea.GetBorderColor());
          box(pinkArea.GetSize());
        }
        else
          {
            float sweepIntensity = sweepArea.InRange(cube_pos);

            noStroke();
            fill(sweepIntensity * sweepArea.sweep_color);
            box(black_size);
          }

        popMatrix();
      }
    }
  }
  popMatrix();
}

class SweepArea {
  float row;
  float size;
  float tail;
  int sweep_color;
  SweepArea()
    {
    }
  public float InRange(PVector cubePosition) {
    float x = cubePosition.x;
    if (cubePosition.x > row - size
            && cubePosition.x < row + size)
      {
        return 1.0f;
      }
    else if (cubePosition.x > row - size - tail)
      {
        return (float)abs((x - (row - size))) / (float)tail;
      }
      else if (cubePosition.x < row + size + tail)
      {
        return (float)(row + size - x) / (float)tail;
      }
    else
      {
        return 0.0f;
      }
  }
  public void Sync(Moonlander syncer) {
    row = (float)syncer.getValue("sweep_x");
    size = (float)syncer.getValue("sweep_size");
    tail = (float)syncer.getValue("sweep_tail");
    sweep_color = (int)syncer.getValue("sweep_color");
  }

}

class ModArea {

  PVector center;
  float area_size;
  float cube_size;
  int pink_color_r;
  int pink_color_g;
  int pink_color_b;
  float border_multiplier;

  ModArea(PVector pos, float sz, float cubeSizeP){
    center = pos;
    area_size = sz;
    cube_size = cubeSizeP;

  }

  public int GetCubeColor()
  {
    return color(pink_color_r, pink_color_g, pink_color_b);
  }
  public int GetBorderColor() {
    return color(pink_color_r * border_multiplier, pink_color_g * border_multiplier, pink_color_b * border_multiplier);
  }
  public float GetSize() {
      return cube_size;
  }
  public boolean InRange(PVector cubePosition) {
    return (center.dist(cubePosition) < area_size);
  }

  public void Sync(Moonlander syncer)
  {
    area_size = (float) syncer.getValue("pink_area_size");
    cube_size = (float) syncer.getValue("pink_cube_size");

    pink_color_r = (int) syncer.getValue("pink_red");
    pink_color_g = (int) syncer.getValue("pink_green");
    pink_color_b = (int) syncer.getValue("pink_blue");
    border_multiplier = (float) syncer.getValue("pink_border_mult");
  }
}
  static public void main(String[] passedArgs) {
    String[] appletArgs = new String[] { "pink_in_space" };
    if (passedArgs != null) {
      PApplet.main(concat(appletArgs, passedArgs));
    } else {
      PApplet.main(appletArgs);
    }
  }
}
