"strict"

let myShader;
let screen;

let canvas_width;
let canvas_height; 

let noiseVal; 
let noiseScale = 0.005;
let flow_field_noise_Scale = 0.007;

let flow_particles;
let circle_measurements;  
const flow_particle_counts = {on_circle : 600, on_radius : 10};
const flow_particle_speed = 2;
let particle_settings = {moving_angle : 0, angle_oscilation_strength : 0, angle_oscillation_time : 1, 
                         noiseStrength : 0.0, noise_time : 1, flow_field : true, noiseSeed : 404, noiseSeedSet : true}

let movement_settings = {rotation : 0, scaling : 1.00}//{rotation : Math.PI/60, scaling : 1.00}

let shader_settings = {shader_type : 0, noise_cutoff : 0.5, noiseScale : 0.0005, startMillis : 0.0}

let background_color; 
let eye_scale = 1.005; 

let initial_stroke = 2;
let stroke_scale = 0.998;
 
let soundTrack;
let renderedImg;

let frame_1;
let frame_2;
let frame_3;
let frame_4;
let frame_5;
let background;
let BIG_background;

let credits;

let i_image;
let logo;

let rendering_flag = false;
let particle_ready = false; //flag to control particle animat
let fade_ready = false; //flag to control fading animation
let far_away = true; // flag to control Big background rendering
let movement_flag = true; // flag to control movement animation
let reverse = false; // flag to control movement animation
let i_title = true; // flag to control i_image rendering
let logo_flag = false; // flag to control logo rendering

let initiate_button;


function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

function preload(){ 
  soundTrack = loadSound('FuriousFreak.mp3');
  frame_5 = loadImage('eye_frames/Graffathon_v2_0_1.png');
  frame_4 = loadImage('eye_frames/Graffathon_v2_1_1.png');
  frame_3 = loadImage('eye_frames/Graffathon_v2_2.png');
  frame_2 = loadImage('eye_frames/Graffathon_v2_3.png');
  frame_1 = loadImage('eye_frames/Graffathon_v2_4.png');

  background = loadImage('eye_frames/Graffathon_background_1.png');
  BIG_background = loadImage('eye_frames/Background_Big.png');
  i_image = loadImage('eye_frames/Graffathon_i_1.png');
  logo = loadImage('eye_frames/Graffathon_logo-BIG.png');

  myShader = loadShader('shader.vert', 'shader.frag'); 


}

function setup() {


  canvas_width = windowWidth;
  canvas_height = windowHeight;
  circle_measurements = {x: canvas_width/2, y : canvas_height/2, inner_radius : 50, outer_radius : 175}

  createCanvas(canvas_width, canvas_height, WEBGL);
  screen = createGraphics(canvas_width, canvas_height);
  screen.background(0, 0, 0, 0);
  frameRate(24);

  background_color = color(0, 0, 0, 15);
  initialize_spot_coords();

  
  // noiseDetail of the pixels octave count and falloff value
  noiseDetail(4, 0.5);

  renderedImg = frame_1;

  // Set stroke weight for the first scene
  screen.strokeWeight(initial_stroke);

  screen.translate(-(canvas_width/2)*(-0.75), -(canvas_height/2)*(-0.75)); 
  screen.scale(0.25, 0.25);  

  noLoop();
  credits = createImg('eye_frames/Graffathon_credits.png').position(800,400);
  initiate_button = createButton('start demo')
    .mousePressed((self) => {
        
        fullscreen(true);
        loop();
        initiate_button.hide();
        initialize_animation();
        credits.hide();

    })
    .position(windowWidth/2-30,windowHeight/2 -125);
  
    
}

/*!!!!!!!!!!!!!!!DRAW!!!!!!!!!!!!!!!!!!!!!!*/
function draw() {

  //noiseStrength = 0.1; //(sin(millis() / 1000) + 1)/6;
  //moving_angle = max(0, (sin(TWO_PI*millis()/100) - 0.5) * 6)
  screen.background(background_color);
  if(movement_flag){
    movement();
  }
  if (!fade_ready){
    screen.background(0);
  }
  if(particle_ready){
    draw_flow_particles();
  }
  if(i_title){
    screen.image(i_image, canvas_width/2 - i_image.width/2 + 30, canvas_height/2 - i_image.height/2 + 105);
  }
  if(rendering_flag){
    animate();
  }
  if(logo_flag){
    screen.image(logo, 0, 0, windowWidth, windowHeight);
  }
  shader(myShader);
  drawScreen();
  //draw_white_part(); 
}

function initialize_animation() {
  //setTimeout(() => {renderedImg = frame_2}, 500);
  //setTimeout(() => {renderedImg = frame_3}, 1000);
  //setTimeout(() => {renderedImg = frame_4; particle_ready = true}, 5000);
  //setTimeout(() => {renderedImg = frame_5}, 5800);
  //setTimeout(() => {movement_settings.rotation = 0; movement_settings.scaling = 1.005}, 5803) 
  //setTimeout(() => {fade_ready = true}, 5806);
  soundTrack.play();

  soundTrack.jump(30);

  soundTrack.addCue(5.806,() => {fade_ready = true})
  soundTrack.addCue(5.83, () => {movement_settings.rotation = 0; movement_settings.scaling = 1.005}) 
  soundTrack.addCue(30, () => {i_title = false});
  soundTrack.addCue(31, () => {rendering_flag = true});
  soundTrack.addCue(35, () => {renderedImg = frame_2; animate()});
  soundTrack.addCue(37.5, () => {renderedImg = frame_3; animate()});
  soundTrack.addCue(41.5,() => {renderedImg = frame_4; particle_ready = true; animate()});
  soundTrack.addCue(44.0, () => {shader_settings.shader_type = 2})
  soundTrack.addCue(44.85, () => {renderedImg = frame_5; far_away = false; animate(); shader_settings.shader_type = 6, shader_settings.cutOff = 0.7, shader_settings.noiseScale = 0.001}, );                      //Eye opened 
  soundTrack.addCue(44.85, () => {particle_settings.moving_angle = 1, particle_settings.angle_oscilation_strength = 0.1, particle_settings.angle_oscillation_time = 60/80})
  soundTrack.addCue(59, () => {movement_flag = false; particle_settings.noiseSeed = 403, flow_field_noise_Scale = 0.014}) // eye stops moving
  soundTrack.addCue(63, () => {particle_settings.noiseSeed = 402, flow_field_noise_Scale = 0.025});
  soundTrack.addCue(67, () => {particle_settings.noiseSeed = 401, flow_field_noise_Scale = 0.007});
  soundTrack.addCue(71, () => {particle_settings.noiseSeed = 400, flow_field_noise_Scale = 0.005});
  soundTrack.addCue(75.0, () => {particle_settings.moving_angle = 1, particle_settings.angle_oscilation_strength = 0.1, particle_settings.angle_oscillation_time = 60/80, particle_settings.flow_field = false})
  soundTrack.addCue(91, () => {particle_settings.moving_angle = -5, particle_settings.angle_oscilation_strength = -0.5, particle_settings.angle_oscillation_time = 30/80, particle_settings.flow_field = false, shader_settings.shader_type = 4, shader_settings.startMillis = millis()}); // beat change stuff
  soundTrack.addCue(105, () => {movement_flag = true; circle_measurements.outer_radius -= 15; movement_settings.scaling = 0.98; far_away = true, shader_settings.shader_type = 3, shader_settings.startMillis = millis()}) //eye moves away
  soundTrack.addCue(109, () => {logo_flag = true}) 
  soundTrack.addCue(120, () => {noLoop(); soundTrack.stop(); rendering_flag = false;})
}

function drawScreen() {
  myShader.setUniform('texture', screen);
  myShader.setUniform('noise', getNoiseValue());
  myShader.setUniform('shader_type', shader_settings.shader_type);
  myShader.setUniform('time', millis());
  myShader.setUniform('startMillis', shader_settings.startMillis);
  
  rect(-canvas_width/2, -canvas_height/2, canvas_width, canvas_height);
}

function getNoiseValue() { 
  let v = noise(millis()/100);
  const cutOff = shader_settings.noise_cutoff;
  
  if(v < cutOff) {
    return 0;
  }
  
  v = pow((v-cutOff) * 1/(1-cutOff), 2); 
  
  return v;
}

function animate() {

  screen.image(renderedImg, canvas_width/2 - renderedImg.width/2 + 30, canvas_height/2 - renderedImg.height/2 + 105);
  
  screen.image(background, canvas_width/2 - background.width/2 + 30, canvas_height/2 - background.height/2 + 105);
  if(far_away){
    screen.image(BIG_background, canvas_width/2 - BIG_background.width/2 + 30, canvas_height/2 - BIG_background.height/2 + 105);
  }




}


function movement() {

  
  screen.translate(-(canvas_width/2)*(movement_settings.scaling-1), -(canvas_height/2)*(movement_settings.scaling-1)); 
  screen.scale(movement_settings.scaling, movement_settings.scaling);  
  


  if (!(movement_settings.rotation == 0.0)) {
    let r = Math.sqrt(Math.pow(canvas_width/2) + Math.pow(canvas_width/2))
    screen.rotate(movement_settings.rotation);
    screen.translate(Math.sin(movement_settings.rotation) * r, Math.cos(movement_settings.rotation) * r)
  }

  initial_stroke *= stroke_scale;
  screen.strokeWeight(initial_stroke);

  
}

function initialize_spot_coords() {
  flow_particles = []; 
  
  for (let i = 0; i < flow_particle_counts.on_circle; i++) {
    for (let j = 0; j < flow_particle_counts.on_radius; j++) {

      let location_from_center = count_initial_location(i, j);
      let r_with_noise = location_from_center.r + random(0, 12);

      flow_particles.push({x : circle_measurements.x + r_with_noise * Math.sin(location_from_center.angle), 
                           y : circle_measurements.y + r_with_noise * Math.cos(location_from_center.angle), 
                           angle : location_from_center.angle});

    }
  } 
}

function count_initial_location(i, j) {
  let r = circle_measurements.inner_radius + (j / flow_particle_counts.on_radius) * (circle_measurements.outer_radius - circle_measurements.inner_radius);
  let angle = (i / flow_particle_counts.on_circle) * TWO_PI; 

  return {r : r, angle : angle};
}

function draw_flow_particles() {
  
  //fill(background_color);
  //noStroke();
  //circle(circle_measurements.x, circle_measurements.y, circle_measurements.outer_radius*2);
  // transform the eye trajectory


  // Draw flow particles
  for (let i = 0; i < flow_particle_counts.on_circle * flow_particle_counts.on_radius; i++) {

      const flow_particle_x = flow_particles[i].x;
      const flow_particle_y = flow_particles[i].y;
      const angle = flow_particles[i].angle;
      //const previous_angle = flow_particles[i].previous_angle;
    
      var paint = color( 160 + Math.sin(flow_particle_x/100)*50, 
                         140 + Math.sin(flow_particle_y/100)*50,  
                         180 + Math.sin(flow_particle_x/100)*20 + Math.sin(flow_particle_y/100)*30, 
                         255); 
      screen.stroke(paint);

      screen.point(flow_particle_x, flow_particles[i].y);

      let new_x;
      let new_y;

      if (particle_settings.flow_field) {
        if (particle_settings.noiseSeedSet) {
          noiseSeed(particle_settings.noiseSeed);
          particle_settings.noiseSeedSet = false;
        }
        let r = dist(flow_particle_x, flow_particle_y, circle_measurements.x, circle_measurements.y);
        let coming_angle = Math.atan((flow_particle_y-circle_measurements.y)/(flow_particle_x-circle_measurements.x));
        
        let noiseVal = noise(4 * coming_angle * flow_field_noise_Scale, 2 * r * flow_field_noise_Scale);

        let new_r = r + Math.cos(noiseVal) * flow_particle_speed;
        let new_angle = angle + Math.sin(noiseVal) * flow_particle_speed;

        new_x = circle_measurements.x + Math.sin(new_angle) * new_r;
        new_y = circle_measurements.y + Math.cos(new_angle) * new_r;    
      }  

      else {
        let noiseVal = noise(flow_particle_x * noiseScale, flow_particle_y * noiseScale) + Math.random(-0.1, 0.1);
        let local_angle = angle + (noiseVal - 0.5)*TWO_PI*particle_settings.noiseStrength 
                      + particle_settings.moving_angle * sin(millis()/(1000*particle_settings.angle_oscillation_time))*TWO_PI * particle_settings.angle_oscilation_strength;
                      
        new_x = flow_particle_x + Math.sin(local_angle) * flow_particle_speed;
        new_y = flow_particle_y + Math.cos(local_angle) * flow_particle_speed;  
      }
        
    
      if ((dist(new_x, new_y, circle_measurements.x, circle_measurements.y) >= circle_measurements.inner_radius) && 
           dist(new_x, new_y, circle_measurements.x, circle_measurements.y) <= circle_measurements.outer_radius) {
        flow_particles[i] = {x: new_x, y: new_y, angle: angle};
      } 
      else {
        let location_from_center = count_initial_location(floor(i/flow_particle_counts.on_radius), 0);

        flow_particles[i] = {x : circle_measurements.x + location_from_center.r * Math.sin(angle),
                             y : circle_measurements.y + location_from_center.r * Math.cos(angle),  
                             angle : angle}; 
      }
  }

}


