package exercisesinlogic;

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

@SuppressWarnings("serial")

// Things to do:
	// Add good layout code for angles etc, relating to children bubbles
	// Add nesting logic

public class ExercisesInLogic extends PApplet {
	private RiText title;
	private RiText instructions1;
	private RiText instructions2;
	private PFont title_font;
	
	private BubbleAttractor if_attr;
	private BubbleAttractor then_attr;
	
	public void setup() {
		size(1000, 700);
		smooth();
		
		RiText.disableAutoDraw();
		title = new RiText(this, "Exercises in Logic");
		title_font = title.loadFont("title_font.vlw");
		instructions1 = new RiText(this, "CLICK the bubbles to explore logical relations. Click THEN to explode the implication.");
		instructions1.loadFont("bubble_font.vlw");
		instructions2 = new RiText(this, "Press ENTER to reset.");
		instructions2.loadFont("bubble_font.vlw");
		if_attr = new BubbleAttractor(this, "If", "ifthen_font.vlw", 0, 0);
		then_attr = new BubbleAttractor(this, "Then", "ifthen_font.vlw", 0, 0);
		
		create_propositions();
	}

	public void draw() {
		check_logic();
		background(240);
		title.setLocation((width/2)-(title.textWidth()/2), title.textHeight()+5);
		title.draw();
		instructions1.setLocation((width/2)-(instructions1.textWidth()/2), title.textHeight()+instructions1.textHeight()+25);
		instructions1.draw();
		instructions2.setLocation((width/2)-(instructions2.textWidth()/2), title.textHeight()+instructions1.textHeight()+instructions2.textHeight()+30);
		instructions2.draw();
		
		if_attr.setX(width/4);
		if_attr.setY(height/2);
		if_attr.draw(this);
		
		then_attr.setX((int)(width-(width/4)-(then_attr.text.textWidth()/2))); // this is ugly
		then_attr.setY(height/2);
		then_attr.draw(this);	
	}
	
	public void mouseClicked() {
		for (Bubble bubble : Bubble.bubbles) {
			if(bubble.pointInside(mouseX, mouseY)) {
				if(!bubble.activated) {
					bubble.activate();
				} else {
					bubble.deactivate();
				}
			}
		}
		if(then_attr.text.contains(mouseX, mouseY)) {
			ArrayList<Bubble> to_remove = new ArrayList<Bubble>();
			for(Bubble bubble : then_attr.bubbles) {
				if(bubble.activated) {
					to_remove.add(bubble);
				}
			}
			for(Bubble bubble : to_remove) {
				then_attr.drawing = false;
				then_attr.text.fadeColor(new float[] {255,255,230,240}, 0, 1);
				then_attr.text.fadeColor(new float[] {0,0,0,255}, 1, 1);
				for(Bubble friend : bubble.friends) {
					if_attr.removeBubbleWithText(friend.text);
				}
				then_attr.removeBubbleWithText(bubble.text);
				then_attr.drawing = true;
			}
		}
		System.out.println(title.isSelected());
	}
	
	public void keyPressed() {
		if((int)key==10) {
			create_propositions();
		}
	}
	
	public int[] unique_randoms(int num, int up_to) {
		int[] numbers = new int[num];
		for(int i = 0; i < num; ++i) {
			int number = (int) random(up_to);
			while (isIn(number, numbers)) {
				number = (int) random(up_to);
			}
			numbers[i] = number;
		}
		return  numbers;
	}
	
	public boolean isIn(int number, int[] array) {
		for (int j = 0; j < array.length; ++j) {
			if (array[j] == number) {
				return true;
			}
		}
		return false;
	}
	
	// Here's all our data. It's all sort of hard coded in. Alas. 
	public void create_propositions() {
		// Reset first
		if_attr.bubbles.clear();
		then_attr.bubbles.clear();
		
		// Get our props #s.
		int[] props = unique_randoms(4, 10);

		// IF they widen the turnpike AND eliminate tolls OR expand the airport, THEN they will stimulate tourism AND increase state tax revenues.
		if(isIn(1, props)) {
			Bubble one_a = new Bubble(this, "they widen the turnpike", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble one_b = new Bubble(this, "they eliminate tolls", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			one_a.addChildBubble("AND", true, "bubble_font.vlw", one_b);
			Bubble one_c = new Bubble(this, "they expand the airport", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			one_a.addChildBubble("OR", true, "bubble_font.vlw", one_c);
			Bubble one_d = new Bubble(this, "they will stimulate tourism", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble one_e = new Bubble(this, "they will increase state tax revenues.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			one_d.addChildBubble("AND", true, "bubble_font.vlw", one_e);
			one_a.addFriend(one_d);
			if_attr.addBubble(one_a);
			then_attr.addBubble(one_d);
		}
		// IF his new novel does not sell well AND get him a position in a writing program, THEN Malone will take a real job OR sell his home AND his car.
		if(isIn(2, props)) {
			Bubble two_a = new Bubble(this, "his new novel does not sell well", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble two_b = new Bubble(this, "his novel does not get him a position in a writing program", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			two_a.addChildBubble("AND", true, "bubble_font.vlw", two_b);
			Bubble two_c = new Bubble(this, "Malone will take a real job", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble two_d = new Bubble(this, "Malone will sell his home", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble two_e = new Bubble(this, "Malone will sell his car.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			two_d.addChildBubble("AND", true, "bubble_font.vlw", two_e);
			two_c.addChildBubble("AND", true, "bubble_font.vlw", two_d);
			two_a.addFriend(two_c);
			if_attr.addBubble(two_a);
			then_attr.addBubble(two_c);
		}
		// IF I think of a being that is first and supreme AND I must of necessity ascribe all perfections to him AND existence is a perfection, THEN a first and supreme being exists.
		if(isIn(3, props)) {
			Bubble three_a = new Bubble(this, "I think of a being that is first and supreme", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble three_b = new Bubble(this, "I must of necessity ascribe all perfections to him", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			three_a.addChildBubble("AND", true, "bubble_font.vlw", three_b);
			Bubble three_c = new Bubble(this, "existence is a perfection", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			three_a.addChildBubble("AND", true, "bubble_font.vlw", three_c);
			Bubble three_d = new Bubble(this, "a first and supreme being exists.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			three_a.addFriend(three_d);
			if_attr.addBubble(three_a);
			then_attr.addBubble(three_d);
		}
		// IF Fricka relents OR Brunnhilde has her way, THEN Wotan will intervene AND cause Siegmund's death.
		if(isIn(4, props)) {
			Bubble four_a = new Bubble(this, "Fricka relents", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble four_b = new Bubble(this, "Brunnhilde has her way", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			four_a.addChildBubble("OR", true, "bubble_font.vlw", four_b);
			Bubble four_c = new Bubble(this, "Wotan will intervene", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble four_d = new Bubble(this, "Wotan will cause Siegmund's death.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			four_c.addChildBubble("AND", true, "bubble_font.vlw", four_d);
			four_a.addFriend(four_c);
			if_attr.addBubble(four_a);
			then_attr.addBubble(four_c);
		}
		// IF the curse is not effective, THEN Fasolt will not retain the Ring AND Fafner will not retain the Ring.
		if(isIn(5, props)) {
			Bubble five_a = new Bubble(this, "the curse is not effective", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble five_b = new Bubble(this, "Fasolt will not retain the Ring", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble five_c = new Bubble(this, "Fafner will not retain the Ring.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			five_b.addChildBubble("AND", true, "bubble_font.vlw", five_c);
			five_a.addFriend(five_b);
			if_attr.addBubble(five_a);
			then_attr.addBubble(five_b);
		}
		// IF Wotan triumphs AND Valhalla is saved THEN Alberic will not have the final word.
		if(isIn(6, props)) {
			Bubble six_a = new Bubble(this, "Wotan triumphs", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble six_b = new Bubble(this, "Valhalla is saved", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble six_c = new Bubble(this, "Alberic will not have the final word.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			six_a.addChildBubble("AND", true, "bubble_font.vlw", six_b);
			six_a.addFriend(six_c);
			if_attr.addBubble(six_a);
			then_attr.addBubble(six_c);
		}
		// IF Wotan is satisfied, THEN Albreic will not be satisfied.
		if(isIn(7, props)) {
			Bubble seven_a = new Bubble(this, "Wotan is satisfied", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble seven_b = new Bubble(this, "Alberic will not be satisfied.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			seven_a.addFriend(seven_b);
			if_attr.addBubble(seven_a);
			then_attr.addBubble(seven_b);
		}
		// IF Sieglinde survives AND her son gains the Ring AND Wotan's plan is fulfilled, THEN Valhalla will be saved.
		if(isIn(8, props)) {
			Bubble eight_a = new Bubble(this, "Sieglinde survives", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble eight_b = new Bubble(this, "Sieglinde's son gains the Ring", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble eight_c = new Bubble(this, "Wotan's plan is fulfilled", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble eight_d = new Bubble(this, "Valhalla will be saved.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			eight_a.addChildBubble("AND", true, "bubble_font.vlw", eight_b);
			eight_a.addChildBubble("AND", true, "bubble_font.vlw", eight_c);
			eight_a.addFriend(eight_d);
			if_attr.addBubble(eight_a);
			then_attr.addBubble(eight_d);
		}
		// IF Siegmund finds the sword OR Siegmund eludes Hunding, THEN Siegmund will be safe.
		if(isIn(9, props)) {
			Bubble nine_a = new Bubble(this, "Siegmund finds the sword", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble nine_b = new Bubble(this, "Siegmund eludes Hunding", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble nine_c = new Bubble(this, "Siegmund will be safe.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			nine_a.addChildBubble("OR", true, "bubble_font.vlw", nine_b);
			nine_a.addFriend(nine_c);
			if_attr.addBubble(nine_a);
			then_attr.addBubble(nine_c);
		}
		// IF Fricka relents OR Brunnhilde has her way, THEN Wotan will not intervene AND Wotan will not cause Siegmund's death.
		if(isIn(10, props)) {
			Bubble ten_a = new Bubble(this, "Fricka relents", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble ten_b = new Bubble(this, "Brunnhilde has her way", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble ten_c = new Bubble(this, "Wotan will not intervene", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			Bubble ten_d = new Bubble(this, "Wotan will not cause Siegmund's death.", "bubble_font.vlw", 0, 0, 2, 255, 255, 255, 255);
			ten_a.addChildBubble("OR", true, "bubble_font.vlw", ten_b);
			ten_c.addChildBubble("AND", true, "bubble_font.vlw", ten_d);
			ten_a.addFriend(ten_c);
			if_attr.addBubble(ten_a);
			then_attr.addBubble(ten_c);
		}
	}

	public void check_logic() {
		for(Bubble bubble : if_attr.bubbles) {
			if(proposition_fulfilled(bubble)) {
				for(Bubble friend : bubble.friends) {
					friend.activate(); // Spazzes, good?
					activate_children(friend);
				}
			} else {
				for(Bubble friend : bubble.friends) {
					friend.deactivate();
					deactivate_children(friend);
				}
			}
		}
	}
	
	public void activate_children(Bubble bubble) {
		for(Object[] child_info : bubble.children) {
			Bubble child = (Bubble)child_info[1];
			child.activate(); // Spazzes, good?
			activate_children(child);
		}
	}
	
	public void deactivate_children(Bubble bubble) {
		for(Object[] child_info : bubble.children) {
			Bubble child = (Bubble)child_info[1];
			child.deactivate();
			deactivate_children(child);
		}
	}
	
	public boolean proposition_fulfilled(Bubble bubble) {
		if(bubble.children.isEmpty()) {
			if(bubble.activated) {
				return true;
			} else {
				return false;
			}
		} else {
			int ands = 0;
			int ors = 0;
			int true_ands = 0;
			int true_ors = 0;
			boolean and_success = false;
			boolean or_success = false;
			for(int i = 0; i < bubble.children.size(); ++i) {
				Object[] child_info = bubble.children.get(i);
				// recurse over the children first
				boolean truth = proposition_fulfilled((Bubble)child_info[1]);
				// reverse truth value if it's a negative statement
				if( ((Boolean)child_info[2]).booleanValue() == false) {
					if(truth == true) {
						truth = false;
					} else {
						truth = true;
					}
				}				
				if( ((RiText)child_info[0]).getText().equals("AND") ) {
					if(truth == true) {
						true_ands++;
					}
					ands++;
				} else if( ((RiText)child_info[0]).getText().equals("OR") ) {
					if(truth == true) {
						true_ors++;
					}
					ors++;
				}
			}

			if(bubble.activated && ands == true_ands) {
				and_success = true;
			}
			if(bubble.activated || true_ors > 0) {
				or_success = true;
			}
			if(ands>0 && ors>0) {
				if(and_success || (true_ors>0)) {
					return true;
				} else {
					return false;
				}
			}
			if(and_success) {
				return true;
			} else if (or_success && ors>0) {
				return true;
			} else {
				return false;
			}
		}
	}
}