package net.paulhertz.pixelaudio.example;

import processing.core.PApplet;
import processing.core.PImage;
import net.paulhertz.pixelaudio.*;

/**
 * This is the Starter example with animation added. In the LookupTables example we showed how to 
 * rotate an array along the signal path and then write it to the display. When we work with 
 * large arrays, shifting numbers for every animation step is not an efficient procedure. Instead,
 * we just shift an index into an array and then copy the pixels to the display using the shifted
 * index. We'll use this technique in all our examples. 
 * 
 * Press 'a' to toggle animation.
 * Press 'h' to print help to the console.
 * 
 */
public class SimpleAnimation extends PApplet {
	PixelAudio pixelaudio;        // the library that we need to load in setup()
	HilbertGen hGen;              // a PixelMapGen child class for making Hilbert curves
	PixelAudioMapper mapper;      // a class that uses a PixelMapGen ("gen", for short) to map audio samples to RGB pixels
	PImage mapImage;              // a bitmap image for display
	PImage baseImage;             // a reference image, unchanging, used as source for animation
	int[] spectrum;               // an array of colors that will be written along the "signal path" in mapImage
	int shift = 64;               // amount we shift for each animation step
	int totalShift = 0;           // total amount we have shifted the image
	boolean isAnimating = false;  // toggle for animation
	boolean isTrackMouse = true;  // track mouse position to set shift value


	public static void main(String[] args) {
		PApplet.main(new String[] { SimpleAnimation.class.getName() });
	}

	public void settings() {
		  size(512, 512);                          // Hilbert curves require dimensions that are powers of 2. 		
	}

	// PixelAudio sketches typically begin like this.
	public void setup() {
		// 1. initialize PixelAudio library
		pixelaudio = new PixelAudio(this);
		// 2. create a PixelMapGen: here it's the Hilbert curve generator           
		hGen = new HilbertGen(width, height);        
		// 3. initialize a PixelAudioMapper object with the gen
		mapper = new PixelAudioMapper(hGen);         
		// 4. create an image for display
		mapImage = createImage(width, height, RGB);  
		// At this point, we might load audio, but we'll leave that for later examples.
		// Right now, let's use a color spectrum to look at the pattern the Hilbert curve makes
		// in the display image. We'll do this frequently in example code, since it shows how
		// an audio signal maps to the image.
		// 5. create rainbow color array "spectrum" and plant it in mapImage
		// The PixelAudioMapper variable "mapper" can access the geometry
		// of the signal path generated by hGen. PlantPixels(...) copies 
		// an array of RGB colors to the signal path mapped to an image.
		mapImage.loadPixels();
		spectrum = getColors(mapper.getSize());
		mapper.plantPixels(spectrum, mapImage.pixels, 0, mapper.getSize());
		mapImage.updatePixels();
		// 6. initialize baseImage, the reference image for pixel-shifting animation
		baseImage = mapImage.copy(); 
		// 7. show the help message
		showHelp();
	}

	/**
	 * Creates an array of colors in rainbow (spectrum) order.
	 * @param size    size of the desired array
	 * @return an array of colors in rainbow (spectrum) order
	 */
	public int[] getColors(int size) {
		int[] colorWheel = new int[size];
		pushStyle();
		colorMode(HSB, colorWheel.length, 100, 100);
		int h = 0;
		for (int i = 0; i < colorWheel.length; i++) {
			colorWheel[i] = color(h, 66, 66);
			h++;
		}
		popStyle();
		return colorWheel;
	}

	public void draw() {
		image(mapImage, 0, 0);
		if (isAnimating) animate();
	}
	
	public void animate() {
		totalShift += shift;
		mapImage.loadPixels();
		// PixelAudioMapper has the method we need, copying baseImage to mapImage 
		// along the signal path, using the accumulated pixel-shifing value totalShift
		mapper.copyPixelsAlongPathShifted(baseImage.pixels, mapImage.pixels, totalShift);
		mapImage.updatePixels();
	}

	public void mouseDragged() {
	    if (isTrackMouse) {
	      shift = abs(width/2 - mouseX) * 16;
	      if (mouseY < height/2) shift = -shift;
	    }
	}

	public void keyPressed() {
	  switch(key) {
	  case ' ': // toggle animation
		  isAnimating = !isAnimating;
		  println(isAnimating ? "-- animation is running" : "-- animation is paused");
		  break;
	  case 'm': // toggle isTrackMouse
		    isTrackMouse = !isTrackMouse;
		    println("-- mouse tracking is "+ isTrackMouse);
		    break;
	  case 'h': // print help to the console
	    showHelp();
	    break;
	  default:
	    break;
	  }
	}
	
	public void showHelp() {
		println(" * Press ' ' to toggle animation.");
		println(" * Drag the mouse to change pixel-shifting speed and direction.");
		println(" * Press 'm' to turn mouse tracking on and off.");
		println(" * Press 'h' to print help to the console.");
	}
	
}
