/* File: Node.java
 * Author: Jason Gookins
 * Description: This class creates a Node in the network.
 */

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.lang.Math;
import java.util.ArrayList;
import javax.swing.JComponent;

public class Node extends JComponent
{
	/************************
	 ** Instance Variables **
	 ************************/

	private int index;
	private int xPos;
	private int yPos;
	private String name;
	private String operation;
	private int priority;
	private int minimumBound;
	private int maximumBound;
	private String givenDistMutability;
	private int hasGiven;
	private int hasGoal;
	private ArrayList<Integer> givenDistribution;
	private ArrayList<Integer> originalGivenDistribution;
	private ArrayList<Integer> goalDistribution;
	private ArrayList<Float> normalizedGoalDistribution;
	private ArrayList<Node> children;
	private ArrayList<Node> parents;
	private String description;
	private Color color;
	private boolean isHighlighted;
	private int change;
	private ArrayList<Integer> resultDistribution;
	private ArrayList<Float> normalizedResultDistribution;



	/**********************
	 ** Main Constructor **
	 **********************/

	public Node()
	{
		super();

		this.index = 0;
		this.xPos = 0;
		this.yPos = 0;
		this.name = "";
		this.operation = "null";
		this.priority = 0;
		this.minimumBound = 0;
		this.maximumBound = 1;
		this.givenDistMutability = "opt";
		this.hasGiven = 0;
		this.hasGoal = 0;
		this.givenDistribution = new ArrayList<Integer>();
		this.originalGivenDistribution = new ArrayList<Integer>();
		this.goalDistribution = new ArrayList<Integer>();
		this.normalizedGoalDistribution = new ArrayList<Float>();
		this.children = new ArrayList<Node>();
		this.parents = new ArrayList<Node>();
		this.description = "";
		this.color = Color.lightGray;
		this.isHighlighted = false;
		this.change = 0;
		this.resultDistribution = new ArrayList<Integer>();
		this.normalizedResultDistribution = new ArrayList<Float>();
	}



	/***************
	 ** Accessors **
	 ***************/

	public int getIndex()
	{
		return this.index;
	}

	public int getXPos()
	{
		return this.xPos;
	}

	public int getYPos()
	{
		return this.yPos;
	}

	public String getName()
	{
		return this.name;
	}

	public String getOperation()
	{
		return this.operation;
	}

	public int getPriority()
	{
		return this.priority;
	}

	public int getMinimumBound()
	{
		return this.minimumBound;
	}

	public int getMaximumBound()
	{
		return this.maximumBound;
	}

	public String getGivenDistMutability()
	{
		return this.givenDistMutability;
	}

	public int getHasGiven()
	{
		return this.hasGiven;
	}

	public int getHasGoal()
	{
		return this.hasGoal;
	}

	public ArrayList<Integer> getGivenDistribution()
	{
		return this.givenDistribution;
	}

	public ArrayList<Integer> getOriginalGivenDistribution()
	{
		return this.originalGivenDistribution;
	}

	public ArrayList<Integer> getGoalDistribution()
	{
		return this.goalDistribution;
	}

	public ArrayList<Float> getNormalizedGoalDistribution()
	{
		return this.normalizedGoalDistribution;
	}

	public ArrayList<Node> getChildren()
	{
		return this.children;
	}

	public ArrayList<Node> getParents()
	{
		return this.parents;
	}

	public String getDescription()
	{
		return this.description;
	}

	public Color getColor()
	{
		return this.color;
	}

	public boolean getIsHighlighted()
	{
		return this.isHighlighted;
	}

	public int getChange()
	{
		return this.change;
	}

	public ArrayList<Integer> getResultDistribution()
	{
		return this.resultDistribution;
	}

	public ArrayList<Float> getNormalizedResultDistribution()
	{
		return this.normalizedResultDistribution;
	}



	/**************
	 ** Mutators **
	 **************/

	public void setIndex(int newIndex)
	{
		this.index = newIndex;
	}

	public void setXPos(int newXPos)
	{
		this.xPos = newXPos;
	}

	public void setYPos(int newYPos)
	{
		this.yPos = newYPos;
	}

	public void setName(String newName)
	{
		this.name = newName;
	}

	public void setOperation(String newOperation)
	{
		this.operation = newOperation;
	}

	public void setPriority(int newPriority)
	{
		this.priority = newPriority;
	}

	public void setMinimumBound(int newMinimumBound)
	{
		this.minimumBound = newMinimumBound;
	}

	public void setMaximumBound(int newMaximumBound)
	{
		this.maximumBound = newMaximumBound;
	}

	public void setGivenDistMutability(String newGivenDistMutability)
	{
		this.givenDistMutability = newGivenDistMutability;
	}

	public void setHasGiven(int newHasGiven)
	{
		this.hasGiven = newHasGiven;
	}

	public void setHasGoal(int newHasGoal)
	{
		this.hasGoal = newHasGoal;
	}

	public void setGivenDistribution(ArrayList<Integer> newGivenDistribution)
	{
		this.givenDistribution = newGivenDistribution;
	}

	public void setOriginalGivenDistribution(ArrayList<Integer> newOriginalGivenDistribution)
	{
		this.originalGivenDistribution = newOriginalGivenDistribution;
	}

	public void setGoalDistribution(ArrayList<Integer> newGoalDistribution)
	{
		this.goalDistribution = newGoalDistribution;
	}

	public void setNormalizedGoalDistribution(ArrayList<Float> newNormalizedGoalDistribution)
	{
		this.normalizedGoalDistribution = newNormalizedGoalDistribution;
	}

	public void setChildren(ArrayList<Node> newChildren)
	{
		this.children = newChildren;
	}

	public void setParents(ArrayList<Node> newParents)
	{
		this.parents = newParents;
	}

	public void setDescription(String newDescription)
	{
		this.description = newDescription;
	}

	public void setColor(Color newColor)
	{
		this.color = newColor;
	}

	public void setIsHighlighted(boolean newIsHighlighted)
	{
		this.isHighlighted = newIsHighlighted;
	}

	public void setChange(int newChange)
	{
		this.change = newChange;
	}

	public void setResultDistribution(ArrayList<Integer> newResultDistribution)
	{
		this.resultDistribution = newResultDistribution;
	}

	public void setNormalizedResultDistribution(ArrayList<Float> newNormalizedResultDistribution)
	{
		this.normalizedResultDistribution = newNormalizedResultDistribution;
	}


	/**************************
	 ** Node Painting Method **
	 **************************/

	public void paintComponent(Graphics g, boolean isNameDisplayed)
	{
		super.paintComponent(g);

		Graphics2D g2 = (Graphics2D)g;

		RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		RenderingHints hintsNew = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		hints.add(hintsNew);
		g2.setRenderingHints(hints);

		Area clip = new Area(g2.getClipBounds());

		if (operation.equals("null"))
		{
			g2.setPaint(Color.BLACK);
			g2.fill(new Ellipse2D.Double(xPos, yPos, 50, 50));
			g2.setPaint(color);
			g2.fill(new Ellipse2D.Double(xPos + 2, yPos + 2, 46, 46));
		}
		else if (operation.equals("not"))
		{
			g2.setPaint(color);
			g2.fill(new Ellipse2D.Double(xPos, yPos, 50, 50));
			g2.setPaint(Color.BLACK);
			g2.fill(new Ellipse2D.Double(xPos + 4, yPos + 4, 42, 42));
		}
		else if (operation.equals("and"))
		{
			Area ellipse = new Area(new Ellipse2D.Double(xPos, yPos, 50, 50));
			int stripeWidth = 2;

			g2.setPaint(Color.BLACK);
			g2.fill(ellipse);

			ellipse.intersect(clip);
			g2.setClip(ellipse);
			g2.setPaint(color);
			for (int i = xPos; i < xPos + 50; i += 2 * stripeWidth)
			{
				g2.fillRect(i, yPos, stripeWidth, 50);
			}
			g2.setClip(clip);
		}
		else if (operation.equals("or"))
		{
			g2.setPaint(Color.BLACK);
			g2.fill(new Ellipse2D.Double(xPos, yPos, 50, 50));
			g2.setPaint(color);
			g2.fill(new Arc2D.Double(xPos, yPos, 50, 50, 270, 180, Arc2D.PIE));
		}

		if (isHighlighted == true)
		{
			g2.setPaint(new Color(255, 255, 0, 100));
			g2.fill(new Ellipse2D.Double(xPos, yPos, 50, 50));
		}

		if (isNameDisplayed)
		{
			FontMetrics metrics = g2.getFontMetrics();
			String text = this.name;

			int textWidth = metrics.stringWidth(text);
			int textHeight = metrics.getHeight();

			int centerX = (xPos + 25) - (textWidth / 2);
			int centerY = (yPos + 37) - (textHeight / 2);

			g2.setPaint(new Color(255, 255, 225));
			g2.fill3DRect(centerX - 3, centerY - 15, textWidth + 6, textHeight + 6, true);
			g2.setPaint(Color.BLACK);
			g2.drawString(text, centerX, centerY);
		}
	}



	/**********************
	 ** Instance Methods **
	 **********************/

	public boolean contains(int x, int y)
	{
		boolean containsPoint = false;

		double rx = 25.0;
		double ry = 25.0;
		double cx = xPos + rx;
		double cy = yPos + ry;

		if((ry * (x - cx)) * (ry * (x - cx)) + (rx * (y - cy)) * (rx * (y - cy)) <= (rx * rx * ry *ry))
		{
			containsPoint = true;
		}

		return containsPoint;
	}

	public void moveBy(int x, int y, int width, int height)
	{
		xPos = Math.max((xPos += x), 0);
		xPos = Math.min(xPos, (width - 50));
		yPos = Math.max((yPos += y), 0);
		yPos = Math.min(yPos, (height - 50));
	}

	public Point center()
	{
		return new Point(xPos + 25, yPos + 25);
	}
}