// PathVisio,
// a tool for data visualization and analysis using Biological Pathways
// Copyright 2006-2011 BiGCaT Bioinformatics
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.pathvisio.core.view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import org.pathvisio.core.model.GraphLink.GraphIdContainer;
import org.pathvisio.core.model.GraphLink.GraphRefContainer;

/**
 * A LinkAnchor is a small round target on a Shape or Line that appears
 * only when you drag a line end around. If the line end is near a LinkAnchor,
 * the line end "connects" to the Shape or Line.
 */
public class LinkAnchor extends VPathwayElement 
{
	static final double DRAW_RADIUS = 5;
	static final double MATCH_RADIUS = DRAW_RADIUS + 5;
	static final int HINT_STROKE_SIZE = 10;

	double relX, relY;
	GraphIdContainer idContainer;
	VPathwayElement parent;
	
	public LinkAnchor(VPathway canvas, VPathwayElement parent, GraphIdContainer idContainer, double relX, double relY) 
	{
		super (canvas);
		this.relX = relX;
		this.relY = relY;
		this.idContainer = idContainer;
		this.parent = parent;
	}

	public Shape getMatchArea() {
		Point2D abs = idContainer.toAbsoluteCoordinate(
				new Point2D.Double(relX, relY)
		);
		return canvas.vFromM(new Ellipse2D.Double(
				abs.getX() - MATCH_RADIUS,
				abs.getY() - MATCH_RADIUS,
				MATCH_RADIUS * 2,
				MATCH_RADIUS * 2
		));
	}

	public Point2D getPosition() {
		return new Point2D.Double(relX, relY);
	}

	private Shape getShape(boolean includeHighlight) {
		Point2D abs = idContainer.toAbsoluteCoordinate(getPosition());
		Shape s = canvas.vFromM(new Ellipse2D.Double(
				abs.getX() - DRAW_RADIUS,
				abs.getY() -DRAW_RADIUS,
				DRAW_RADIUS * 2,
				DRAW_RADIUS * 2
		));
		if(drawHighlight && includeHighlight) {
			return new BasicStroke(HINT_STROKE_SIZE).createStrokedShape(s);
		} else {
			return s;
		}
	}

	public Shape getShape() {
		return getShape(true);
	}

	@Override
	public void doDraw(Graphics2D g2d) 
	{
		if(drawHighlight) {
			g2d.setColor(new Color(0, 255, 0, 128));
			g2d.fill(getShape());
		}

		//Draw a bulls eye
		Shape shape = getShape(false);
		Rectangle2D bounds = shape.getBounds2D();
		double r = bounds.getWidth() / 2;
		double cx = bounds.getCenterX();
		double cy = bounds.getCenterY();

		Ellipse2D outer = new Ellipse2D.Double(
				cx - r,
				cy -r,
				r * 2,
				r * 2
		);
		Ellipse2D white = new Ellipse2D.Double(
				cx - r * 2 / 3,
				cy - r * 2 / 3,
				4 * r / 3,
				4 * r / 3
		);
		Ellipse2D inner = new Ellipse2D.Double(
				cx - r / 3,
				cy - r / 3,
				2 * r / 3,
				2 * r / 3
		);

		Color fill = new Color(255, 0, 0, 255);

		g2d.setColor(fill);
		g2d.fill(outer);
		g2d.setColor(Color.WHITE);
		g2d.fill(white);
		g2d.setColor(fill);
		g2d.fill(inner);

		g2d.setColor(Color.BLACK);
		g2d.draw(shape);
	}

	public GraphIdContainer getGraphIdContainer() {
		return idContainer;
	}

	public void link(GraphRefContainer ref) {
		ref.linkTo(idContainer, relX, relY);
	}

	private boolean drawHighlight;

	/**
	 * Display a visual hint to show that this is the anchor that is
	 * being linked to.
	 */
	public void highlight() 
	{
		drawHighlight = true;
		markDirty();
	}

	public void unhighlight() 
	{
		drawHighlight = false;
		markDirty();
	}

	@Override
	protected Shape calculateVOutline()
	{
		return getShape();
	}

	@Override
	protected int getZOrder()
	{
		return parent.getZOrder() + 1;
	}
	
}
