// State.java
// class for an individual state of an NFA

import java.awt.*;		// for graphics
import java.awt.geom.*;		// for Arc2D 
import javax.swing.*;		// for graphics 
import java.util.*;		// for HashSet
import java.awt.event.*;	// for Mouse events

/** State of an NFA, implemented as a JComponent.
 *  May be added to an NFA.
 *  May possess 0 or more transitions to other states.
 *  May be final or start state.
 *  Implements MouseListener so that States can be selected and dragged
 */
public class State extends JComponent
		   implements MouseListener
{
/** The NFA (i. e. JFrame) which contains this state
 */
NFA nfa;				// nfa containing this state
/** Radius of all states, when drawn as a circle
*/
public static int r = 20;			// radius when drawn as a circle
/** final state is an accepting state, 
 *  Accessed in the Attributes class.
 */
public boolean isFinal, isStart;

/** The index number of this state (used for the array states in NFA)
 */
public int index;

/** This state has a set of transitions to other states
*/
public HashSet transitions;
/** A state may be labelled.  Not yet implemented.
 */
public char label;

/** location of this state on the frame
 */
public int locX, locY;		// location on the frame, upper left corner

/** Create a state
 *  @param x x coordinate of this state on the frame
 *  @param y y coordinate of this state on the frame
 *  @param n The NFA which contains this state
 */
public State (int x, int y, NFA n)
{  locX = x;
   locY = y;
   setBounds (locX, locY-3*r, 2*r, 2*r);		// kludge on y coordinate
   nfa = n;
   transitions = new HashSet();
   isStart = false;
   isFinal = false;
   addMouseListener (this);
}

/** Allow the user to set the attributes of this State, using a panel with 
 *  checkboxes.
 */
public void setAttributes()
{  
   Attributes att = new Attributes(this);
   WindowUtilities.openInJFrame (att,200,175);
}

/** Save mouse click location, for dragging of states
 */
int downAtX, downAtY;

/** A selected state can be modified or given a transition
 */
public boolean isSelected;

/** Respond to a MouseClicked event, by selecting this state.  Also check to
 *  see if it was clicked to select a transition target.
 *  @param evt The location of the event.
 */
public void mouseClicked (MouseEvent evt)
{   
    Transition trans;
    selectThis();			// this state is selected
    if (nfa.addingTrans)			// adding a transition?
      {	
	trans = new Transition (this, nfa.fromState, nfa.transChar);
	nfa.fromState.transitions.add (trans);
	nfa.addingTrans = false;
	nfa.repaint();
      }
}

/** Respond to a MouseEntered event
 *  @param evt The location of the event.
 */
public void mouseEntered (MouseEvent evt)
{
}

/** Respond to a MouseExited event
 *  @param evt The location of the event.
 */
public void mouseExited (MouseEvent evt)
{
}

/** Respond to a MousePressed event
 *  @param evt The location of the event.
 */
public void mousePressed (MouseEvent evt)
{   downAtX = evt.getX();		// save location of click
    downAtY = evt.getY();
    selectThis();			// select this state
}

/** Respond to a MouseReleased event.
 *  This State has been dragged.
 *  @param evt The location of the event.
 */
public void mouseReleased (MouseEvent evt)
{  int x,y;
   int xDiff, yDiff;
   x = evt.getX();
   y = evt.getY();
   xDiff = x - downAtX;
   yDiff = y - downAtY;
   locX = locX + xDiff;		// new location of this State
   locY = locY + yDiff;
   setLocation (locX, locY-3*r);	// kludge on y coordinate
   moveLabels ();		// move the labels also
   nfa.repaint();
}

void moveLabels ()
{  Iterator it = transitions.iterator();
   Transition trans;
   while (it.hasNext())
     {	trans = (Transition) it.next();
	trans.lbl.setLocation ();
	trans.lbl.setOpaque (false);
     }
}

//  Deselect the selected state and select this state instead
void selectThis()
{  if (nfa.selectedState!=null) nfa.selectedState.isSelected = false;
   isSelected = true;
   nfa.selectedState = this;
}


/** Display this state on the given graphics object g.  Color it red if
 *  selected.  Draw an inner circle if it is a final state.  Draw an arrow
 *  coming in if it is a start state.  Draw all the transitions coming out
 *  of this state.
 * @param g The Graphics object on which it is being displayed.
 */
public void paint (Graphics g)
{ super.paint (g);
  Graphics2D graphics2D = (Graphics2D) g;
 
   if (isSelected) graphics2D.setColor (Color.red);
   graphics2D.draw (new Arc2D.Double (locX, locY, 2.0*r, 2.0*r, 0.0, 360.0,
		Arc2D.OPEN));
   // draw inner circle for final states
   if (isFinal)
	graphics2D.draw (new Arc2D.Double (locX+0.2*r, locY+0.2*r,
		1.6*r, 1.6*r, 0.0, 360.0, Arc2D.OPEN));
   // draw arrow to start state(s)
   Arrow startArrow;
   double diff;
   if (isStart)
     {	diff = r / 1.414;
	startArrow = new Arrow (locX, locY, locX+diff, locY+diff, Color.blue);
     }

   graphics2D.setColor (Color.black);


  // draw the transitions emanating from this State
  Iterator it = transitions.iterator();
  Transition trans;
  while (it.hasNext())
    {	trans = (Transition) it.next();
	trans.paint(g);
    }


}
}

