package exercisesinlogic;

import processing.core.PApplet;
import processing.core.PFont;
import rita.RiText;
import java.util.ArrayList;

public class Bubble {
	public int x = 0;
	public int y = 0;
	public RiText[] lines;
	public PFont font;
	public static int BUFFER = 7; // buffer around the text in pixels
	public static int MAX_CHARS = 20; // max width in chars for a text line
	public static int LEADING = 4; // pixels between lines of text
	public int jitter = 0;
	public int r = 0;
	public int g = 0;
	public int b = 0;
	public int a = 0;
	public PApplet applet;
	public String text;
	public ArrayList<Object[]> children; // [RiText (connector), Bubble (end bubble), boolean (true/false logic)]
	public boolean activated = false;
	public ArrayList<Bubble> friends;
	
	public static ArrayList<Bubble> bubbles = new ArrayList<Bubble>();
	
	public Bubble(PApplet applet, String text, String fontfile, int x, int y, int jitter, int r, int g, int b, int a) {
		font = new RiText(applet).loadFont(fontfile);
		lines = RiText.createLines(applet, text, x, y, MAX_CHARS, LEADING);
		for(RiText line : lines) {
			line.textFont(font);
			line.align(RiText.CENTER);
		}
		children = new ArrayList<Object[]>();
		this.jitter = jitter;
		this.r = r;
		this.g = g;
		this.b = b;
		this.a = a;
		this.applet = applet;
		this.text = text;
		setX(x);
		setY(y);
		bubbles.add(this);
		friends = new ArrayList<Bubble>();
	}
	
	public void activate() {
		activated = true;
		setColor((int)applet.random(255), (int)applet.random(255), (int)applet.random(255), (int)applet.random(255));
	}
	
	public void deactivate() {
		activated = false;
		setColor(255, 255, 255, 255);
	}
	
	public void addChildBubble(String conn, boolean truth_value, String font_file, Bubble child) {
		RiText t = new RiText(applet, conn);
		t.loadFont(font_file);
		children.add(new Object[] { t, child, truth_value });
	}
	
	public void removeBubbleWithText(String text) {
		for (Object[] child : children) {
			String t = ((Bubble)child[1]).text;
			if( t.equals(text) ) {
				children.remove(child);
			}
		}
	}
	
	public void setX(int new_x) {
		for(RiText line : lines) {
			line.setX(new_x);
		}
		x = new_x;
	}
	
	public void setY(int new_y) {
		int new_text_y = (int)(new_y-totalTextHeight()/2);
		int acc = 0;
		for(int i = 0; i < lines.length; ++i) {
			lines[i].setY(new_text_y+acc);
			acc += lines[i].textHeight()+LEADING;
		}
		y = new_y;
	}
	
	public void setColor(int r, int g, int b, int a) {
		this.r = r;
		this.g = g;
		this.b = b;
		this.a = a;
	}
	
	public void draw(PApplet applet) {
		draw(applet, 0, PApplet.TWO_PI);
	}
	
	public void draw(PApplet applet, float min_angle, float max_angle) {
		// Jitter
		setX(x+(int)applet.random(-1*jitter, jitter));
		setY(y+(int)applet.random(-1*jitter, jitter));
		
		// Draw the bubble		
		float ellipse_diameter = radius()*2;
		applet.fill(r, g, b, a);
		applet.strokeWeight(5);
		applet.ellipse(x, y, ellipse_diameter, ellipse_diameter);
		// Draw the text
		for (RiText line : lines) {
			line.draw();
		}
		// Draw the children
		updateChildren(min_angle, max_angle);
		
		for(Object[] child : children) {
			((RiText)child[0]).draw();
			((Bubble)child[1]).draw(applet, min_angle, max_angle);
		}
	}
	
	public void updateChildren(float min_angle, float max_angle) {
		if(children.isEmpty()) {
			return;
		}
		float angle = min_angle;
		int current_x = (int)(x+radius());
		int current_y = (int)(y);
		float dist = PApplet.dist(x, y, current_x, current_y);
		RiText current_child_text;
		Bubble current_child;
		int text_x, text_y;
		for(int i = 0; i < children.size(); ++i) {
			current_child_text = (RiText)children.get(i)[0];
			current_child_text.align(RiText.CENTER);

			current_child = (Bubble)children.get(i)[1];
			current_child.jitter = 0;
			current_child_text.rotate(-1*angle+PApplet.PI/2);

			current_x = (int)(x + (dist+current_child.radius()+current_child_text.textHeight()+5)*PApplet.cos(angle));
			current_y = (int)(y - (dist+current_child.radius()+current_child_text.textHeight()+5)*PApplet.sin(angle));
			
			text_x = (int)(x + (radius()+4)*PApplet.cos(angle));
			text_y = (int)(y - (radius()+4)*PApplet.sin(angle));
			
			current_child_text.setX(text_x);
			current_child_text.setY(text_y);
			current_child.setX(current_x);
			current_child.setY(current_y);
			angle += max_angle/(children.size());
		}
	}
	
	public boolean pointInside(int x, int y) {
		if( (PApplet.sq(x-this.x) + PApplet.sq(y-this.y)) <= PApplet.sq(radius()) ) {
			return true;
		}
		return false;
	}
	
	private RiText widestRiText() {
		float current_largest_width = 0;
		RiText current_widest = null;
		for (RiText line : lines) {
			int width = (int)line.textWidth(); // help
			if(width > current_largest_width) {
				current_largest_width = width;
				current_widest = line;
			}
		}
		return current_widest;
	}
	
	private float totalTextHeight() {
		float running_total = 0;
		for(int i = 0; i < lines.length-1; ++i) {
			running_total += lines[i].textHeight()+LEADING;
		}
		return running_total;
	}
	
	public float radius() {
		float w = widestRiText().textWidth();
		float h = totalTextHeight();
		return PApplet.sqrt( PApplet.sq(w/2) + PApplet.sq(h/2) ) + BUFFER;
	}
	
	public void addFriend(Bubble f) {
		friends.add(f);
		f.friends.add(this);
	}
	
	public void removeFriend(Bubble f) {
		friends.remove(f);
		f.friends.remove(this);
	}
}
