package Ragedemo01;
import processing.core.PApplet;

/**
 * Draws a constantly morphing flower made with lines on the parent programs screen.
 *     
 * 
 * @version 005
 * @author RageManifesto
 *
 *
 * TODO for next versions
 * ----------------------
 *   - nothing right now
 *
 *
 */
public class RageFlowers {
	
	private PApplet parent;
	private float strokeWeight;
	private float baseLineLength1;
	private float angle1 = 0.0f;
	private float angle2 = 0.0f;
	private float angleModificationInput = 0.0f;
	private float strokeAlpha;
	private int baseLocation_x;
	private int baseLocation_y;
	private int numberOfArms;
	private int numberOfPiecesPerArm;
	private float morphingSpeed;
	private float sizeChangeAmount;
	private float rotation;
	private float rotator;
	private float rot = 0;
	private int[] baseColor;
	private int[][] colors;
	private float baseDistance;
	private int movement_x;
	private int movement_y;
	private int loc_x;
	private int loc_y;
	private float initialMorphState;
	private int maxSize;
	private float baseLineLengthModifier;

	private final float pi = 3.14159f;
	private final float pi2 = 6.2832f;	
	private final int colorShiftAmount = 20;
	
	
	
    /**
     * Initializes a RageFlower. Some parameters do nothing currently.
     * The signature is a nightmare. If you have troubles with it, just start with some of these examples:
     * 
     *       this.flowers1 = new RageFlowers(this, 200, -280, 0, 1, -50f, -0.08f, 16, 16, 1f, 27f, 0.3f, 255, 5, 50);
     *       this.flowers2 = new RageFlowers(this, 400, -90, 1, 1, -15f, -0.03f, 8, 8, 1.5f, 30f, 0.5f, 255, 10, 25); 
     *       this.flowers3 = new RageFlowers(this, 600, -50, 0, 1, -10f, 0f, 12, 6, 0.7f, 30f, 0.3f, 255, 10, 32);
     *       this.flowers4 = new RageFlowers(this, 800, -60, -1, 1, -11f, -0.06f, 12, 6, 12f, 1f, 0.5f, 255, 5, 25);
     *       this.flowers5 = new RageFlowers(this, 0, -70, 0, 1, -12f, 0.2f, 16, 9, 1f, 12f, 0.4f, 255, 15, 15);
     *       this.flowers6 = new RageFlowers(this, 1000, -170, 2, 1, -15f, 0f, 18, 10, 1f, 15f, 0.3f, 255, 10, 38);
     *       this.flowers7 = new RageFlowers(this, 350, -70, -2, 1, -16f, 0.1f, 20, 15, 1.2f, 25f, 0.2f, 255, 12, 30);
     *       this.flowers8 = new RageFlowers(this, 400, -120, 1, 1, -17f, -0.3f, 16, 3, 1f, 30f, 0.7f, 255, 4, 60);
     *       this.flowers9 = new RageFlowers(this, 0, -400, 1, 1, -18f, 0f, 18, 9, 1f, 25f, 0.6f, 255, 8, 25);
     *       this.flowers10 = new RageFlowers(this, 200, -550, 0, 2, -19f, 0f, 12, 8, 1f, 20f, 0.5f, 255, 10, 45);
     * 
     * 
     * 
     * @param p
     * @param x
     * @param y
     * @param x_speed
     * @param y_speed
     * @param distance
     * @param rotation
     * @param numberOfArms
     * @param numberOfPiecesPerArm
     * @param morphingSpeed
     * @param sizeModifier
     * @param sizeChangeModifier
     * @param alpha
     * @param strokeWeight
     * @param maxSize
     */
	public RageFlowers(
			PApplet p,
			int x,
			int y,
			int x_speed,
			int y_speed,
			float distance,
			float rotation,
			int numberOfArms,
			int numberOfPiecesPerArm,
			float morphingSpeed,
			float sizeModifier,
			float sizeChangeModifier,
			int alpha,
			int strokeWeight,
			int maxSize
			){
		this.parent = p;
	    this.rotation = rotation;
		this.strokeWeight = strokeWeight;
		this.baseLineLength1 = sizeModifier;
		this.baseLocation_x = x/2;
		this.baseLocation_y = y/2;
		this.loc_x = x/2;
		this.loc_y = y/2;
		this.movement_x = x_speed;
		this.movement_y = y_speed;
		this.numberOfArms = numberOfArms;
		this.numberOfPiecesPerArm = numberOfPiecesPerArm;
		//this.morphingSpeed = morphingSpeed;
		this.morphingSpeed = 1f;
		this.strokeAlpha = alpha;
		this.sizeChangeAmount = sizeChangeModifier;
		this.baseDistance = distance;
		this.maxSize = maxSize;
		
		
		this.baseColor = new int[]{ (int)parent.random(0,255), (int)parent.random(0,255), (int)parent.random(0,255) };
		
		this.colors = new int[numberOfPiecesPerArm+1][3];
		this.colors[0] = this.baseColor;
		
		for (int i = 1; i < numberOfPiecesPerArm; i++) {
			
			this.colors[i] = giveNextColor(this.colors[i-1]);			
			
		}
		
		//this.initialMorphState = parent.random(0f, 3f);
		this.initialMorphState = 0f;
	}
	

	private int[] giveNextColor(int[] thisColor) {
		int[] newColor = new int[3];
		int a;
		for ( int k = 0; k < thisColor.length; k++ ) {
			
			a = thisColor[k];		
			a = a + (int) parent.random(0, this.colorShiftAmount);
			if ( a > 255 ) a = (int) parent.random(0, 255);
			newColor[k] = a;
		}
		return newColor;
	}
	
	
	/**
	 * A method for some debugging purpose.
	 */
	public void printColors(){
		
		for ( int i = 0; i < this.colors.length; i++ ) {
			
			for ( int j = 0; j < this.colors[i].length; j++ ) {
				
			}
		}
	}
	
	
	/**
	 * An empty update method that intentionally does nothing. It's enough to just call the draw() method.
	 * Implemented here to make sure the update method stays empty.
	 */
	public void update(){
		//This method intentionally left empty.
	}
	
	/**
	 * Draw method.
	 */
	public void draw(){
		
		//rotation
        rot = rot + rotation;
		rotator = (float) (Math.sin(rot));
		
		//location
		loc_x += movement_x;
		loc_y += movement_y;
		
		//respawning
		if ( loc_y > 1100 ) {
			loc_y = baseLocation_y-150;
			loc_x = baseLocation_x;		
		}
		if ( loc_x > 1600 ) {
			loc_y = baseLocation_y-150;
			loc_x = baseLocation_x;	
			this.movement_x = -(this.movement_x);
		}
		if ( loc_x < -550 ) {
			loc_y = baseLocation_y-150;
			loc_x = baseLocation_x;	
			this.movement_x = -(this.movement_x);
		}
		
		
		
		//some arm angle stuff
		angleModificationInput += 0.005f;
		angle1 = initialMorphState + angleModificationInput * 0.5f * pi;	  
		angle2 = initialMorphState + angleModificationInput * pi2;
		  
		this.baseLineLengthModifier = ((angle1%pi2) - pi) * -10f;
				
		if (  this.baseLineLengthModifier > 0.0f  ) {
			baseLineLength1 = baseLineLength1 + sizeChangeAmount * (baseLineLengthModifier * 0.1f);
			//System.out.println("kasvaa");
		}
		else {
			baseLineLength1 = baseLineLength1 - sizeChangeAmount* (baseLineLengthModifier * -0.1f);
			//System.out.println("pienenee");
		}
		
		for ( float j = 1f; j <= numberOfArms; j++ ){
			
		    parent.pushMatrix();

		    //adjust distance
		    parent.translate(baseLocation_x, baseLocation_y, baseDistance);
		    
		    //draw the arms first line
		    draw1stLine(loc_x, loc_y, ( angle2 + 2 * pi * ( j / numberOfArms) ) , (int)j-1 );  
		      
		    //draw the rest of the arm pieces
		    for (int i = 0; i < numberOfPiecesPerArm; i++){
		    	
		        //adjust distance
		    	parent.translate(0, 0, (baseDistance + (i * 10f) ) * 0.01f);
		        drawLine(baseLineLength1, 0, angle1 * morphingSpeed, i);
		    	  
		    }

		    parent.popMatrix();	  
		}
	}


	private void draw1stLine(float x, float y, float a, int index) {
	    parent.translate(x, y);
		parent.rotate(a + rotator);
		parent.stroke(this.colors[0][0],this.colors[0][1],this.colors[0][2],strokeAlpha);
		parent.strokeWeight(strokeWeight);
		parent.line(0, 0, baseLineLength1, 0);
	}
	
	private void drawLine(float x, float y, float a, int index) {
	    parent.translate(x, y);
		parent.rotate(a);
		parent.stroke(this.colors[index][0],this.colors[index][1],this.colors[index][2],strokeAlpha);
		parent.strokeWeight(strokeWeight);
		parent.line(0, 0, baseLineLength1, 0);
	}
}