/* File: Node.java
 * Author: Jason Gookins
 * Description: This is the class which creates the individual
 * Nodes within the network.
 */

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
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 Color nodeColor;
	private boolean isHighlighted;
	private String name;
	private String operation;
	private int priority;
	private int minimumRange;
	private int maximumRange;
	private String givenFlag;
	private int hasGiven;
	private int hasGoal;
	private int numberOfChildren;
	private ArrayList<String> children;
	private ArrayList<Integer> givenDistribution;
	private ArrayList<Integer> goalDistribution;
	private ArrayList<Float> resultData;
	private ArrayList<Float> goalData;



	/******************
	 ** Constructors **
	 ******************/

	/* Constructor for creating a new Node by hand */
	public Node(int index, int xPos, int yPos, String name)
	{
		this.index = index;
		this.xPos = xPos;
		this.yPos = yPos;
		this.nodeColor = Color.lightGray;
		this.isHighlighted = false;
		this.name = name;
		this.operation = "NULL";
		this.priority = 0;
		this.minimumRange = 0;
		this.maximumRange = 0;
		this.givenFlag = "opt";
		this.hasGiven = 0;
		this.hasGoal = 0;
		this.numberOfChildren = 0;
		this.children = new ArrayList<String>();
		this.givenDistribution = new ArrayList<Integer>();
		this.goalDistribution = new ArrayList<Integer>();
		this.resultData = new ArrayList<Float>();
		this.goalData = new ArrayList<Float>();
	}

	/* Constructor for creating a new Node from a file */
	public Node (int index, String name)
	{
		this.index = index;
		this.xPos = 0;
		this.yPos = 0;
		this.nodeColor = Color.lightGray;
		this.isHighlighted = false;
		this.name = name;
		this.operation = "NULL";
		this.priority = 0;
		this.minimumRange = 0;
		this.maximumRange = 0;
		this.givenFlag = "opt";
		this.hasGiven = 0;
		this.hasGoal = 0;
		this.numberOfChildren = 0;
		this.children = new ArrayList<String>();
		this.givenDistribution = new ArrayList<Integer>();
		this.goalDistribution = new ArrayList<Integer>();
		this.resultData = new ArrayList<Float>();
		this.goalData = new ArrayList<Float>();
	}



	/***************
	 ** Accessors **
	 ***************/

	/* Get the ID number of this Node */
	public int getIndex()
	{
		return this.index;
	}

	/* Get the X position of the upper-left corner of this Node */
	public int getXPos()
	{
		return this.xPos;
	}

	/* Get the Y position of the upper-left corner of this Node */
	public int getYPos()
	{
		return this.yPos;
	}

	/* Get the color of this Node */
	public Color getNodeColor()
	{
		return this.nodeColor;
	}

	/* Get whether this Node is highlighted */
	public boolean getIsHighlighted()
	{
		return this.isHighlighted;
	}

	/* Get the name of this Node */
	public String getName()
	{
		return this.name;
	}

	/* Get the operation of this Node */
	public String getOperation()
	{
		return this.operation;
	}

	/* Get the priority of this Node */
	public int getPriority()
	{
		return this.priority;
	}

	/* Get the minimum range of this Node */
	public int getMinimumRange()
	{
		return this.minimumRange;
	}

	/* Get the maximum range of this Node */
	public int getMaximumRange()
	{
		return this.maximumRange;
	}

	/* Get whether this Node's given distribution is mandatory or optional */
	public String getGivenFlag()
	{
		return this.givenFlag;
	}

	/* Get whether this Node has a given distribution */
	public int getHasGiven()
	{
		return this.hasGiven;
	}

	/* Get whether this Node has a goal distribution */
	public int getHasGoal()
	{
		return this.hasGoal;
	}

	/* Get the number of children that this Node has */
	public int getNumberOfChildren()
	{
		return this.numberOfChildren;
	}

	/* Get the children of this Node */
	public ArrayList<String> getChildren()
	{
		return this.children;
	}

	/* Get the given distribution of this Node */
	public ArrayList<Integer> getGivenDistribution()
	{
		return this.givenDistribution;
	}

	/* Get the goal distribution of this Node */
	public ArrayList<Integer> getGoalDistribution()
	{
		return this.goalDistribution;
	}

	/* Get this Node's result data */
	public ArrayList<Float> getResultData()
	{
		return this.resultData;
	}

	/* Get this Node's goal data */
	public ArrayList<Float> getGoalData()
	{
		return this.goalData;
	}



	/**************
	 ** Mutators **
	 **************/


	/* Set the ID number of this Node */
	public void setIDNumber(int newIndex)
	{
		this.index = newIndex;
	}

	/* Set the X position of the upper-left corner of this Node */
	public void setXPos(int newXPos)
	{
		this.xPos = newXPos;
	}

	/* Set the Y position of the upper-left corner of this Node */
	public void setYPos(int newYPos)
	{
		this.yPos = newYPos;
	}

	/* Set the color of this Node */
	public void setNodeColor(Color newNodeColor)
	{
		this.nodeColor = newNodeColor;
	}

	/* Set whether this Node is highlighted */
	public void setIsHighlighted(boolean newIsHighlighted)
	{
		this.isHighlighted = newIsHighlighted;
	}

	/* Set the name of this Node */
	public void setName(String newName)
	{
		this.name = newName;
	}

	/* Set the operation of this Node */
	public void setOperation(String newOperation)
	{
		this.operation = newOperation;
	}

	/* Set the priority of this Node */
	public void setPriority(int newPriority)
	{
		this.priority = newPriority;
	}

	/* Set the minimum range of this Node */
	public void setMinimumRange(int newMinimumRange)
	{
		this.minimumRange = newMinimumRange;
	}

	/* Set the maximum range of this Node */
	public void setMaximumRange(int newMaximumRange)
	{
		this.maximumRange = newMaximumRange;
	}

	/* Set whether this Node's given distribution is mandatory or optional */
	public void setGivenFlag(String newGivenFlag)
	{
		this.givenFlag = newGivenFlag;
	}

	/* Set whether this Node has a given distribution */
	public void setHasGiven(int newHasGiven)
	{
		this.hasGiven = newHasGiven;
	}

	/* Set whether this Node has a goal distribution */
	public void setHasGoal(int newHasGoal)
	{
		this.hasGoal = newHasGoal;
	}

	/* Set the number of children that this Node has */
	public void setNumberOfChildren(int newNumberOfChildren)
	{
		this.numberOfChildren = newNumberOfChildren;
	}

	/* Set the children of this Node */
	public void setChildren(ArrayList<String> newChildren)
	{
		this.children = newChildren;
	}

	/* Set the given distribution of this Node */
	public void setGivenDistribution(ArrayList<Integer> newGivenDistribution)
	{
		this.givenDistribution = newGivenDistribution;
	}

	/* Set the goal distribution of this Node */
	public void setGoalDistribution(ArrayList<Integer> newGoalDistribution)
	{
		this.goalDistribution = newGoalDistribution;
	}

	/* Set this Node's result data */
	public void setResultData(ArrayList<Float> newResultData)
	{
		this.resultData = newResultData;
	}

	/* Set this Node's goal data */
	public void setGoalData(ArrayList<Float> newGoalData)
	{
		this.goalData = newGoalData;
	}


	/**************************
	 ** Node Painting Method **
	 **************************/

	public void paintComponent(Graphics g, boolean displayNames)
	{
		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);

		g2.setPaint(Color.black);
		g2.fill(new Ellipse2D.Double(xPos, yPos, 50, 50));
		g2.setPaint(nodeColor);
		g2.fill(new Ellipse2D.Double(xPos + 2, yPos + 2, 46, 46));
		if (this.isHighlighted == true)
		{
			g2.setPaint(new Color(255, 255, 0, 100));
			g2.fill(new Ellipse2D.Double(xPos, yPos, 50, 50));
		}
		if (displayNames == true)
		{
			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 + 35 - textHeight / 2;

			g2.setPaint(new Color(255, 255, 225));
			g2.fill3DRect(centerX - 3, centerY - 13, textWidth + 6, textHeight + 6, true);
			g2.setPaint(Color.black);
			g2.drawString(text, centerX, centerY);
		}
	}



	/**********************
	 ** Instance Methods **
	 **********************/

	/* Determine if a point lies within the Node */
	public boolean contains(int x, int y)
	{
		boolean containsPoint = false;

		double rx = 50/2.0;
		double ry = 50/2.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;
	}

	/* Determine how far to move a Node when dragging it */
	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));
	}

	/* Determine the coordinates of the center of a Node */
	public Point center()
	{
		return new Point(xPos + 25, yPos + 25);
	}
}