//######################################################################################
package pipe.dataLayer;

import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
//######################################################################################
/**
 * <b>PlaceTransitionObject</b> - Petri-Net PLace or Transition SuperClass<b> - <i>Abstract</i></b>
 *
 * @see <p><a href="..\PNMLSchema\index.html">PNML  -  Petri-Net XMLSchema (stNet.xsd)</a>
 * @see </p><p><a href="..\..\..\UML\dataLayer.html">UML  -  PNML Package </a></p>
 * @version 1.0
 * @author James D Bloom
 */
//######################################################################################
public abstract class PlaceTransitionObject extends PetriNetObject {
//######################################################################################
  /** X-axis Position on screen*/
  protected double positionX;
  /** Y-axis Position on screen*/
  protected double positionY;
  
  protected double componentWidth;
  protected double componentHeight;

  /** Used in the mouse events to control dragging*/
  private boolean isDragging;

  private Collection connectTo = new LinkedList();
  private Collection connectFrom = new LinkedList();
  protected static Arc someArc;
//######################################################################################
   /**
   * Create Petri-Net Object
   *
   * @param positionXInput X-axis Position
   * @param positionYInput Y-axis Position
   * @param idInput Place id
   * @param nameInput Name
   * @param nameOffsetXInput Name X-axis Position
   * @param nameOffsetYInput Name Y-axis Position
   * @param colorInput Color
   */
  public PlaceTransitionObject(double positionXInput, double positionYInput, String idInput,
  		String nameInput, double nameOffsetXInput, double nameOffsetYInput){

    this(positionXInput,positionYInput, idInput);
    setName(nameInput);
  }
//######################################################################################
  /**
   * Create Petri-Net Object
   *
   * @param positionXInput X-axis Position
   * @param positionYInput Y-axis Position
   * @param idInput Place id
   * @param colorInput Color
   */
  public PlaceTransitionObject(double positionXInput, double positionYInput, String idInput){
    this(positionXInput,positionYInput);
    id = idInput;

  }
//######################################################################################
  /**
   * Create Petri-Net Object
   * This constructor does all the work, the others just call it.
   *
   * @param positionXInput X-axis Position
   * @param positionYInput Y-axis Position
   * @param colorInput Color
   *
   */
  public PlaceTransitionObject(double positionXInput, double positionYInput){
    positionX = positionXInput;
    positionY = positionYInput;

    /*sets up Namelabel for each PN object*/
    pnName = new NameLabel();
    pnName.setPosition((int)positionXInput,(int)(positionYInput+30));
  }
//######################################################################################
  /**
   * Create empty Petri-Net Object
   *
   */
  public PlaceTransitionObject(){

  }
//######################################################################################
  /**
   * Set X-axis position
   *
   * @param positionXInput Double value for X-axis position
   */
  public void setPositionX(double positionXInput) {
    positionX = positionXInput;
  }
//######################################################################################
  /**
   * Set Y-axis position
   *
   * @param positionYInput Double value for Y-axis position
   */
  public void setPositionY(double positionYInput) {
    positionY = positionYInput;
  }
//######################################################################################
  /**
   * Set id
   *
   * @param idInput String value for Place id;
   */
  public void setId(String idInput) {
    id = idInput;
    setName(id);
//    System.out.println("setting id to: " + idInput);
  }
//######################################################################################
  /**
   * Set name
   *
   * @param nameInput String value for Place name;
   */
  public void setName(String nameInput) {
    //sets the text within the label
//     System.out.println("setting name to: " + nameInput);
    pnName.setText(nameInput);
    pnName.updateSize();

  }
//######################################################################################
//  /**
//   * Set X-axis offset for name position
//   *
//   * @param nameOffsetXInput Double value for name X-axis offset
//   */
//  public void setNameOffsetX(double nameOffsetXInput) {
//    nameOffsetX = new Double(nameOffsetXInput);
//  }
//
//  /**
//   * Set Y-axis offset for name position
//   *
//   * @param nameOffsetYInput Double value for name Y-axis offset
//   */
//  public void setNameOffsetY(double nameOffsetYInput) {
//    nameOffsetY = new Double(nameOffsetYInput);
//  }

  /**
   * Get X-axis position
   *
   * @return Double value for X-axis position
   */
  public double getPositionX() {
    return positionX;
  }
//######################################################################################
  /**
   * Get Y-axis position
   *
   * @return Double value for Y-axis position
   */
  public double getPositionY() {
    return positionY;
  }
//######################################################################################
  /**
   * Get id
   *
   * @return String value for Place id;
   */
  public String getId() {
    if(id != null)
      return id;
    else
      return pnName.getText();
  }
//######################################################################################
  /**
   * Get name
   *
   * @return String value for Place name;
   */
  public String getName() {
    if(pnName != null)
      return pnName.getText();
    else
      return id;
  }
//######################################################################################
//  /**
//   * Get X-axis offset for name position
//   *
//   * @return Double value for name X-axis offset
//   */
//  public double getNameOffsetX() {
//    if(nameOffsetX == null)
//      return 0;
//    return nameOffsetX.doubleValue();
//  }

//  /**
//   * Get Y-axis offset for name position
//   *
//   * @return Double value for name Y-axis offset
//   */
//  public double getNameOffsetY() {
//    if(nameOffsetY == null)
//      return 0;
//    return nameOffsetY.doubleValue();
//  }

  /**
   * Get X-axis position
   * returns null if value not yet entered
   *
   * @return Double value for X-axis position
   */
  public Double getPositionXObject() {
    return new Double(positionX);
  }
//######################################################################################
  /**
   * Get Y-axis position
   * returns null if value not yet entered
   *
   * @return Double value for Y-axis position
   *
   */
  public Double getPositionYObject() {
    return new Double(positionY);
  }
//######################################################################################
//  /**
//   * Get X-axis offset for name position
//   * returns null if value not yet entered
//   *
//   * @return Double value for name X-axis offset
//   */
//  public Double getNameOffsetXObject() {
//    return nameOffsetX;
//  }

//  /**
//   * Get Y-axis offset for name position
//   * returns null if value not yet entered
//   *
//   * @return Double value for name Y-axis offset
//   */
//  public Double getNameOffsetYObject() {
//    return nameOffsetY;
//  }


  /* MOUSE EVENT HANDLERS - most now do nothing as functionality moved into handlers*/


  /** Event handler for when the user presses down on the mouse, this is used in
   *  conjunction with mouseDragged and mouseReleased to implement the moving action
   * @param e Mouse Event
   */
  public void mousePressed(MouseEvent e) {
    Insets insets = getInsets();
    int eventX = e.getX();
    int eventY = e.getY();
  }
//######################################################################################
  /** Implemented the moving action - now moved into the handler
   * @param e Mouse Event
   */
  public void mouseReleased(MouseEvent e) { }

//######################################################################################
  /** Implemented the moving of the objects - now done in the handler
   * @param e Mouse Event
   */
  public void mouseDragged(MouseEvent e) { }
//######################################################################################
  /** Implemented in subclasses as involves some tailoring according to the shape
   * @param e Mouse Event
   */
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
  }
//######################################################################################
  public Point2D getIntersectOffset(Point2D start)
  {
  	return new Point2D.Double();
  }
//######################################################################################
  /** Returns the width bounds we want to use when initially creating the place on the gui
   * @return Width bounds of Place
   */
  public int boundsWidth() {
    return WIDTH+1;
  }
//######################################################################################
  /** Returns the height bounds we want to use when initially creating the place on the gui
   * @return Height bounds of Place
   */
  public int boundsHeight() {
    return HEIGHT+1;
  }
//######################################################################################
  /** Returns the distance between the outside of the component to the centre, in order
   *  to position the centre of the place where the mouse clicks on the screen
   * @return Top offset of Place
   */
  public int centreOffsetTop() {
  	return (int)componentHeight/2;
  }
//######################################################################################
  /** Returns the distance between the outside of the component to the centre, in order
   *  to position the centre of the place where the mouse clicks on the screen
   * @return Left offset of Place
   */
  public int centreOffsetLeft() {
  	return (int)componentWidth /2;
  }
//###################################################################################### 
  /** Calculates the BoundsOffsets used for setBounds() method */
  public void updateBounds(){
  	bounds.setBounds((int)positionX, (int)positionY, (int)componentWidth, (int)componentHeight);
  	bounds.grow(COMPONENT_DRAW_OFFSET, COMPONENT_DRAW_OFFSET);
  	setBounds(bounds); 
  }
//######################################################################################
  /** Adds outwards arc to place/transition */
  public void addConnectTo(Arc newArc) {
  	connectTo.add(newArc);
  }
//######################################################################################  
  /** Adds inwards arc to place/transition */
  public void addConnectFrom(Arc newArc) {
  	connectFrom.add(newArc);
  }
//######################################################################################
  public void removeFromArc(Arc oldArc) {
  	connectFrom.remove(oldArc);
  }
//######################################################################################
  public void removeToArc(Arc oldArc) {
  	connectTo.remove(oldArc);
  }
//###################################################################################### 
  /** Updates location of any attached arcs */
  public void updateConnected() {
  	Iterator arcsFrom = connectFrom.iterator();
  	while(arcsFrom.hasNext()) {
  		someArc = ((Arc)arcsFrom.next());
  		updateEndPoint(someArc);
  		someArc.updateArcPosition();
  	}
  	
  	Iterator arcsTo = connectTo.iterator();
  	while(arcsTo.hasNext()) {
  		someArc = ((Arc)arcsTo.next());
  		updateEndPoint(someArc);
  		someArc.updateArcPosition();
  	}
  }
//######################################################################################  
  /** Translates the component by x,y */
  public void translate(int x, int y) {
  	positionX = positionX + x;
  	positionY = positionY + y;
  	updateBounds();
  	pnName.translate(x,y);
  }
//######################################################################################  
  /** Sets the center of the component to position x, y */
  public void setCentre(double x,double y) {
  	positionX = x - componentWidth/2;
  	positionY = y - componentHeight/2;
  	updateBounds();
  	updateLabelLocation();
  	updateConnected();
  }
  
  public Point2D.Double getCentre() {
  	return new Point2D.Double(positionX +componentWidth/2, positionY + componentHeight/2);
  }
  
  private void updateLabelLocation() {
  	pnName.setPosition((int)positionX,(int)(positionY+30));
  }
//######################################################################################
  public void delete() {
  	getParent().remove(pnName);
  	super.delete();
  }
//######################################################################################
  /** Handles selection for Place/Transitions */
  public void select() {
  	if (selectable && !selected) {	
  		super.select();
  		Iterator arcsFrom = connectFrom.iterator();
  		while(arcsFrom.hasNext()) {
  			((Arc)arcsFrom.next()).select();
  		}
  	
  		Iterator arcsTo = connectTo.iterator();
  		while(arcsTo.hasNext()) {
  			((Arc)arcsTo.next()).select();
  		}
  	} 	
  }
//######################################################################################
  public void addedToGui() {
  	addLabelToContainer(); 	
  }
//######################################################################################
  public boolean areNotSameType(PlaceTransitionObject o)
  {
  	return (((this instanceof Place) && (o instanceof Transition))
  			|| ((this instanceof Transition ) && (o instanceof Place)));
  }
//######################################################################################
    public Iterator getConnectFromIterator() {
    	return connectFrom.iterator();
    }
//######################################################################################
    public Iterator getConnectToIterator() {
    	return connectTo.iterator();
    }
//######################################################################################   
    abstract public void updateEndPoint(Arc arc);
//######################################################################################
}
//######################################################################################