package com.baselet.element;

import java.util.List;

import javax.swing.JComponent;

import com.baselet.control.HandlerElementMap;
import com.baselet.control.basics.Converter;
import com.baselet.control.basics.geom.Point;
import com.baselet.diagram.DrawPanel;
import com.baselet.element.interfaces.GridElement;
import com.baselet.element.relation.Relation;

public class ElementUtils {

	/**
	 * Must be overwritten because Swing uses this method to tell if 2 elements are overlapping
	 * It's also used to determine which element gets selected if there are overlapping elements (the smallest one)
	 * IMPORTANT: on overlapping elements, contains is called for all elements until the first one returns true, then the others contain methods are not called
	 *
	 * In future this logic should be the same as in BaseletGWT.DrawPanel.getGridElementOnPosition() which is much simpler because its externally calculated
	 * (this migration is only possible if there are not GridElement Listeners, but instead only one Diagram Listener which delegates the event to the specific GridElement like in GWT)
	 */
	public static boolean checkForOverlap(GridElement gridElement, Point p) {
		JComponent component = (JComponent) gridElement.getComponent();
		java.awt.Rectangle rectangle = component.getVisibleRect();
		Point absolute = new Point(gridElement.getRectangle().getX() + p.getX(), gridElement.getRectangle().getY() + p.getY());
		if (!rectangle.contains(p.x, p.y)) {
			return false;
		}

		DrawPanel drawPanel = HandlerElementMap.getHandlerForElement(gridElement).getDrawPanel();
		List<GridElement> elements = drawPanel.getGridElements();
		Selector selector = drawPanel.getSelector();
		for (GridElement other : elements) {
			if (other == gridElement || other.getLayer() < gridElement.getLayer() || !other.isSelectableOn(absolute)) {
				continue; // ignore this element, elements with a lower layer and elements which are not selectable on the point
			}

			// issue #260: if a relation is the only selected element its selection should be retained
			if (gridElement instanceof Relation && other instanceof Relation) {
				if (selector.isSelectedOnly(gridElement)) {
					return true;
				}
				if (selector.isSelectedOnly(other)) {
					return false;
				}
			}

			JComponent otherComponent = (JComponent) other.getComponent();
			if (other.getLayer() > gridElement.getLayer()) { // elements with higher layer can "overwrite" contains-value of this
				// move point to coordinate system of other entity
				Point other_p = new Point(p.x + gridElement.getRectangle().x - other.getRectangle().x, p.y + gridElement.getRectangle().y - other.getRectangle().y);
				if (otherComponent.contains(Converter.convert(other_p))) {
					return false;
				}
			}

			java.awt.Rectangle other_rectangle = otherComponent.getVisibleRect();
			// move bounds to coordinate system of this component
			other_rectangle.x += other.getRectangle().x - gridElement.getRectangle().x;
			other_rectangle.y += other.getRectangle().y - gridElement.getRectangle().y;
			// when elements intersect, select the smaller element except if it is an old relation (because they have a larger rectangle than they use). NOTE: Old Relations are not checked because they do not properly implement isSelectableOn
			if (!(other instanceof com.baselet.element.old.element.Relation) && rectangle.intersects(other_rectangle) && firstSmallerThanSecond(other_rectangle, rectangle)) {
				return false;
			}
		}
		return true;
	}

	private static boolean firstSmallerThanSecond(java.awt.Rectangle first, java.awt.Rectangle second) {
		int areaFirst = first.getSize().height * first.getSize().width;
		int areaSecond = second.getSize().height * second.getSize().width;
		if (areaFirst < areaSecond) {
			return true;
		}
		return false;
	}

}
