// Project: 		TrafficFlow
// File: 			ParticlesTest.java
// Created by: 		rcarlsen, Feb 24, 2009

// Imports
import java.util.ArrayList;

import javax.media.opengl.GL;

import processing.core.*;
import processing.opengl.*;

import javax.media.opengl.*;

public class ParticlesTest extends PApplet {

	// Demo of forces + particle system
	// Particles interact with a list of "Repeller" objects
	// Daniel Shiffman <http://www.shiffman.net>
    // Moved to Eclipse by Robert Carlsen | robertcarlsen.net

	ParticleSystem ps;
	ArrayList<ParticleSystem> emitters;
	ArrayList<Repeller> repellers;
	ArrayList<Attractor> attractors;
	ArrayList<ParticleSystem> cloudEmitters;
	ArrayList<Attractor> deviceAttractors;
	
	// some switches to control the program
	boolean displayRepellers = false;
	boolean driftRepellers = true;
	boolean displayAttractors = false;
	
    // to set up the openGL context:
    PGraphicsOpenGL pgl;
    GL gl;
    
	public void setup() {
	  size(600,600,OPENGL);
	  
	  // for the initial testing of the particles
	  //ps = new ParticleSystem(this, 1,new PVector(width/2,height/4));

	  // create a list of emitters. also set up the complementary attractors
	  // for the time being, let's arrange them in a concentric ring
	  emitters = new ArrayList<ParticleSystem>();
	  deviceAttractors = new ArrayList<Attractor>();
	  cloudEmitters = new ArrayList<ParticleSystem>();
	  int num = 7;
	  float radius = (this.width-40)/2.0f;
	  for(int i=0;i<num;i++){
	    float a = i*(TWO_PI/(float)num);
	    PVector loc = new PVector(radius*cos(a),radius*sin(a));
	    PVector center = new PVector(this.width/2.0f, this.height/2.0f);
	    loc.add(center);
	    emitters.add(new ParticleSystem(this,1,loc, color(150,20,20)));
	    deviceAttractors.add(new Attractor(this, loc,20.0f,10.0f));
	    cloudEmitters.add(new ParticleSystem(this,1,center,color(20,20,150)));
	  }
	  
	  // Create a list of Repeller objects
	  repellers = new ArrayList<Repeller>();
	  for (int i = 0; i < 20; i++) {
	    repellers.add(new Repeller(this, random(width),random(height)));
	  }
	  
	  // Create a list of Attractor objects
	  attractors = new ArrayList<Attractor>();
	  for (int i = 0; i < 1; i++) {
	    //attractors.add(new Attractor(this, new PVector(random(width),random(height)),10.0f,3.0f));
	    attractors.add(new Attractor(this, new PVector(width/2.0f,height/2.0f),20.0f,10.0f));
	  }
	  
	  smooth();
	}

	public void draw() {
	  //***//
      // OPENGL Additive blending stuff:
      pgl = (PGraphicsOpenGL) g;
      gl = pgl.gl;
      
      pgl.beginGL();
      // This fixes the overlap issue
       gl.glDisable(GL.GL_DEPTH_TEST);
      // Turn on the blend mode
      gl.glEnable(GL.GL_BLEND);
      // Define the blend mode
       gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE);
      //gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
       
       //gl.glFrustum(0, this.width, this.height, 0, 0, 20000);
      pgl.endGL();  
      //***//
      
	  background(10);
//	  fill(0xff000000);
//	  rect(0,0,this.width,this.height);

	  /*
	  // Apply gravity force to all Particles
	  PVector gravity = new PVector(0,0.1f);
	  //ps.applyForce(gravity);
	  // Apply repeller objects to all Particles
	  ps.applyRepellers(repellers);
	  // Apply the attractor objects to all Particles
	  ps.applyAttractors(attractors);
	  // Run the Particle System
	  ps.run();
	  // Add more particles
	  ps.addParticle();
*/
	  
	  // go through all of the emitters:
	  for(int i=0;i< emitters.size();i++){
	    ParticleSystem e = emitters.get(i);
	    
	    // Apply gravity force to all Particles
	    //PVector gravity = new PVector(0,0.1f);
	    //ps.applyForce(gravity);
	    // Apply repeller objects to all Particles
	    e.applyRepellers(repellers);
	    cloudEmitters.get(i).applyRepellers(repellers);
	    
	    // Apply the attractor objects to all Particles
	    e.applyAttractors(attractors);
	    cloudEmitters.get(i).applyAttractor(deviceAttractors.get(i));
	    
	    // Run the Particle System
	    e.run();
	    cloudEmitters.get(i).run();
	    
	    // Add more particles
	    // throttling a bit:
	    if(this.frameCount%2 == 0)
	      e.addParticle();
	    
	    if(this.frameCount%5 == 0)
	          cloudEmitters.get(i).addParticle();
	    
	    // TODO: set the loc of the cloudEmitters to follow the (big, red) attractor
	  }
	  

	  // Display all repellers
	  for (int i = 0; i < repellers.size(); i++) {
	    Repeller r = (Repeller) repellers.get(i); 

	    // move the repellers around a bit
	    if(driftRepellers){
	      int range = 1;
	      float n1 = random(-range,range);
	      float n2 = random(-range,range);
	      PVector shiftV = new PVector(n1, n2);
	      r.addLoc(shiftV);
	    }
	    
	    if(displayRepellers){
	      r.display();
	      r.drag();
	    }
	  }


	  if(displayAttractors){
	    // Display all attractors
	    for (int i = 0; i < attractors.size(); i++) {
	      Attractor a = (Attractor) attractors.get(i); 
	      a.display();
	      a.drag();
	    }
	  }
	}

	public void mousePressed() {
	  for (int i = 0; i < repellers.size(); i++) {
	    Repeller r = (Repeller) repellers.get(i); 
	    r.clicked(mouseX,mouseY);
	  }
	  
	  for(int i=0;i<attractors.size();i++){
		  Attractor a = (Attractor) attractors.get(i);
		  a.clicked(mouseX,mouseY);
	  }
	}

	public void mouseReleased() {
	  for (int i = 0; i < repellers.size(); i++) {
	    Repeller r = (Repeller) repellers.get(i); 
	    r.stopDragging();
	  }
	  for(int i=0;i<attractors.size();i++){
	    Attractor a = (Attractor) attractors.get(i);
	    a.stopDragging();
	  }
	}

	public void keyPressed(){
	  switch(key)  {
	  case 'r':
	    displayRepellers = !displayRepellers;
	    break;
	  case 'R':
	     driftRepellers = !driftRepellers;
	     break;
	  case 'a':
	    displayAttractors = !displayAttractors;
	    break;
	  }
	}

}
