<commit_before>/**
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @since February 25, 2015
 * @version 0.1.1
 */

package edu.millersville.cs.bitsplease.model;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.List;


import javafx.beans.property.Property;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.control.TextField;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.Shape;
/**
 * A model-view representation of a UML relation symbol.
 * A UMLRelationSymbol object can be represented as any major
 * UML relation types
 */
public class UMLRelationSymbol extends UMLSymbol {

	final double ARROW_SIZE = 10d;
	final double DIAMOND_SIZE = 12d;
	
	private	UMLRelationType relationType;
	private UMLObjectSymbol sourceObject;
	private UMLObjectSymbol targetObject;
	private Polyline rLine;
	private Shape rSymbol;
	private TextField rText;
	
	/**
	 * Default constructor for externalization
	 */
	public UMLRelationSymbol(){
		
		super();
		
		this.setPickOnBounds(false);
		
		this.rLine = new Polyline();
		this.getChildren().add(rLine);
		
		rText = new TextField();
		rText.textProperty().bindBidirectional(identifier);
		rText.setMouseTransparent(true);
		rText.setFocusTraversable(false);
		rText.setVisible(true);
		rText.setStyle("-fx-border-color: transparent; -fx-background-color: transparent");
		rText.setPrefWidth(150);
		this.getChildren().add(rText);
		
		
	}
	
	public UMLRelationSymbol(UMLObjectSymbol sourceObject,
			UMLObjectSymbol targetObject, UMLRelationType relationType){
		super();
		
		this.sourceObject = sourceObject;
		this.targetObject = targetObject;
		this.relationType = relationType;
		identifier.setValue(relationType.toString());
		// clicks should NOT be captured based on bounding box
		this.setPickOnBounds(false);
		
		// create, add, and update line
		this.rLine = new Polyline();
		refreshLine();
		getChildren().add(rLine);
		
		// create and add identifier field
		rText = new TextField();
		rText.textProperty().bindBidirectional(identifier);
		rText.setMouseTransparent(true);
		rText.setFocusTraversable(false);
		rText.setVisible(true);
		rText.setStyle("-fx-border-color: transparent; -fx-background-color: transparent;");
		rText.setPrefWidth(150);
		getChildren().add(rText);
		
		// create and position relation head symbol
		initSymbol(this.relationType);
	}
	
	/**
	 * @return Point2D position of the first point of the relation line
	 */
	public Point2D getStartPoint() {
		List<Double> points = rLine.getPoints();
		if (points.size() < 2) {
			return null;
		} else {
			return new Point2D(points.get(0),points.get(1));
		}
	}
	
	/**
	 * @return Point2D position of the last point of the relation line
	 */
	public Point2D getEndPoint() {
		List<Double> points = rLine.getPoints();
		int size = points.size();
		if (size < 2) {
			return null;
		} else {
			return new Point2D(points.get(size-2),points.get(size-1));
		}
	}
	
	/**
	 * @return orientation of last segment of the line in radians; 
	 * Positive x-axis returns 0, positive y-axis returns PI/4, negative y-axis returns -PI/4; 
	 * Invalid lines return 0
	 */
	public double getEndOrientation() {
		List<Double> points = rLine.getPoints();
		int size = points.size();
		
		// must have at least 2 points to be 
		if (size < 4) {
			return 0d;
		} else {
			return Math.atan2(points.get(size-1)-points.get(size-3), points.get(size-2)-points.get(size-4));
		}
	}
	
	/***
	 * Refreshes the line component of the relation
	 */
	private void refreshLine() {
		
		rLine.getPoints().clear();
		
		// the following computes the edge center pair between the two objects
		// which has the shortest distance
		double[] distances = {
				sourceObject.getTopCenter().distance(targetObject.getBottomCenter()),
				sourceObject.getMiddleRight().distance(targetObject.getMiddleLeft()),
				sourceObject.getMiddleLeft().distance(targetObject.getMiddleRight()),
				sourceObject.getBottomCenter().distance(targetObject.getTopCenter())
		};
		
		int minIndex = 0;
		for (int i = 1; i < 4; i++) {
			if (distances[i] < distances[minIndex])
				minIndex = i;
		}
		
		switch (minIndex) {
			case 0:
				rLine.getPoints().addAll(new Double[]{
						sourceObject.getTopCenter().getX(),
						sourceObject.getTopCenter().getY(),
						targetObject.getBottomCenter().getX(),
						targetObject.getBottomCenter().getY()
				});
				break;
			case 1:
				rLine.getPoints().addAll(new Double[]{
						sourceObject.getMiddleRight().getX(),
						sourceObject.getMiddleRight().getY(),
						targetObject.getMiddleLeft().getX(),
						targetObject.getMiddleLeft().getY()
				});
				break;
			case 2:
				rLine.getPoints().addAll(new Double[]{
						sourceObject.getMiddleLeft().getX(),
						sourceObject.getMiddleLeft().getY(),
						targetObject.getMiddleRight().getX(),
						targetObject.getMiddleRight().getY()
				});
				break;
			case 3:
				rLine.getPoints().addAll(new Double[]{
						sourceObject.getBottomCenter().getX(),
						sourceObject.getBottomCenter().getY(),
						targetObject.getTopCenter().getX(),
						targetObject.getTopCenter().getY()
				});
				break;
		}
	}
	
	/**<commit_msg>adds self-referencing relation drawing (issue #23)<commit_after>/**
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 * @since February 25, 2015
 * @version 0.1.1
 */

package edu.millersville.cs.bitsplease.model;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.List;


import javafx.beans.property.Property;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.control.TextField;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline;
import javafx.scene.shape.Shape;
/**
 * A model-view representation of a UML relation symbol.
 * A UMLRelationSymbol object can be represented as any major
 * UML relation types
 */
public class UMLRelationSymbol extends UMLSymbol {

	final double ARROW_SIZE = 10d;
	final double DIAMOND_SIZE = 12d;
	final double SELF_RELATION_SIZE = 60d;
	
	private	UMLRelationType relationType;
	private UMLObjectSymbol sourceObject;
	private UMLObjectSymbol targetObject;
	private Polyline rLine;
	private Shape rSymbol;
	private TextField rText;
	
	/**
	 * Default constructor for externalization
	 */
	public UMLRelationSymbol(){
		
		super();
		
		this.setPickOnBounds(false);
		
		this.rLine = new Polyline();
		this.getChildren().add(rLine);
		
		rText = new TextField();
		rText.textProperty().bindBidirectional(identifier);
		rText.setMouseTransparent(true);
		rText.setFocusTraversable(false);
		rText.setVisible(true);
		rText.setStyle("-fx-border-color: transparent; -fx-background-color: transparent");
		rText.setPrefWidth(150);
		this.getChildren().add(rText);
		
		
	}
	
	public UMLRelationSymbol(UMLObjectSymbol sourceObject,
			UMLObjectSymbol targetObject, UMLRelationType relationType){
		super();
		
		this.sourceObject = sourceObject;
		this.targetObject = targetObject;
		this.relationType = relationType;
		identifier.setValue(relationType.toString());
		// clicks should NOT be captured based on bounding box
		this.setPickOnBounds(false);
		
		// create, add, and update line
		this.rLine = new Polyline();
		refreshLine();
		getChildren().add(rLine);
		
		// create and add identifier field
		rText = new TextField();
		rText.textProperty().bindBidirectional(identifier);
		rText.setMouseTransparent(true);
		rText.setFocusTraversable(false);
		rText.setVisible(true);
		rText.setStyle("-fx-border-color: transparent; -fx-background-color: transparent;");
		rText.setPrefWidth(150);
		getChildren().add(rText);
		
		// create and position relation head symbol
		initSymbol(this.relationType);
	}
	
	/**
	 * @return Point2D position of the first point of the relation line
	 */
	public Point2D getStartPoint() {
		List<Double> points = rLine.getPoints();
		if (points.size() < 2) {
			return null;
		} else {
			return new Point2D(points.get(0),points.get(1));
		}
	}
	
	/**
	 * @return Point2D position of the last point of the relation line
	 */
	public Point2D getEndPoint() {
		List<Double> points = rLine.getPoints();
		int size = points.size();
		if (size < 2) {
			return null;
		} else {
			return new Point2D(points.get(size-2),points.get(size-1));
		}
	}
	
	/**
	 * @return orientation of last segment of the line in radians; 
	 * Positive x-axis returns 0, positive y-axis returns PI/4, negative y-axis returns -PI/4; 
	 * Invalid lines return 0
	 */
	public double getEndOrientation() {
		List<Double> points = rLine.getPoints();
		int size = points.size();
		
		// must have at least 2 points to be 
		if (size < 4) {
			return 0d;
		} else {
			return Math.atan2(points.get(size-1)-points.get(size-3), points.get(size-2)-points.get(size-4));
		}
	}
	
	/***
	 * Refreshes the line component of the relation
	 */
	private void refreshLine() {
		
		rLine.getPoints().clear();
		
		if (sourceObject != targetObject) {
			// the following computes the edge center pair between the two objects
			// which has the shortest distance
			double[] distances = {
					sourceObject.getTopCenter().distance(targetObject.getBottomCenter()),
					sourceObject.getMiddleRight().distance(targetObject.getMiddleLeft()),
					sourceObject.getMiddleLeft().distance(targetObject.getMiddleRight()),
					sourceObject.getBottomCenter().distance(targetObject.getTopCenter())
			};
			
			int minIndex = 0;
			for (int i = 1; i < 4; i++) {
				if (distances[i] < distances[minIndex])
					minIndex = i;
			}
			
			switch (minIndex) {
				case 0:
					rLine.getPoints().addAll(new Double[]{
							sourceObject.getTopCenter().getX(),
							sourceObject.getTopCenter().getY(),
							targetObject.getBottomCenter().getX(),
							targetObject.getBottomCenter().getY()
					});
					break;
				case 1:
					rLine.getPoints().addAll(new Double[]{
							sourceObject.getMiddleRight().getX(),
							sourceObject.getMiddleRight().getY(),
							targetObject.getMiddleLeft().getX(),
							targetObject.getMiddleLeft().getY()
					});
					break;
				case 2:
					rLine.getPoints().addAll(new Double[]{
							sourceObject.getMiddleLeft().getX(),
							sourceObject.getMiddleLeft().getY(),
							targetObject.getMiddleRight().getX(),
							targetObject.getMiddleRight().getY()
					});
					break;
				case 3:
					rLine.getPoints().addAll(new Double[]{
							sourceObject.getBottomCenter().getX(),
							sourceObject.getBottomCenter().getY(),
							targetObject.getTopCenter().getX(),
							targetObject.getTopCenter().getY()
					});
					break;
			}
		} else {
			Point2D startPoint = sourceObject.getBottomCenter();
			Point2D endPoint = sourceObject.getMiddleLeft();
			
			rLine.getPoints().addAll(new Double[]{
					startPoint.getX(),
					startPoint.getY(),
					startPoint.getX(),
					startPoint.getY() + SELF_RELATION_SIZE,
					endPoint.getX() - SELF_RELATION_SIZE,
					startPoint.getY() + SELF_RELATION_SIZE,
					endPoint.getX() - SELF_RELATION_SIZE,
					endPoint.getY(),
					endPoint.getX(),
					endPoint.getY()
			});
		}
		
	}
	
	/**
{'fraction_non_alphanumeric': 0.1283701513306662, 'fraction_numerical': 0.009392937902243869, 'mean_word_length': 3.7457697069748246, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5450861', 'n_tokens_mistral': 4360, 'n_tokens_neox': 3569, 'n_words': 787}