/*
 * Copyright 2010-2015 Institut Pasteur.
 * 
 * This file is part of Icy.
 * 
 * Icy is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Icy is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
 */
package plugins.kernel.roi.roi2d;

import icy.canvas.IcyCanvas;
import icy.painter.Anchor2D;
import icy.painter.LineAnchor2D;
import icy.resource.ResourceUtil;
import icy.roi.ROI;
import icy.type.point.Point2DUtil;
import icy.type.point.Point5D;
import icy.util.XMLUtil;

import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.List;

import org.w3c.dom.Node;

/**
 * ROI 2D Line.
 * 
 * @author Stephane
 */
public class ROI2DLine extends ROI2DShape
{
    protected class ROI2DLineAnchor2D extends LineAnchor2D
    {
        public ROI2DLineAnchor2D(Point2D position)
        {
            super(position, getOverlay().getColor(), getOverlay().getFocusedColor());
        }

        @Override
        protected Anchor2D getPreviousPoint()
        {
            if (this == pt1)
                return pt2;
            return pt1;
        }
    }

    public class ROI2DLinePainter extends ROI2DShapePainter
    {
        @Override
        protected boolean isTiny(Rectangle2D bounds, Graphics2D g, IcyCanvas canvas)
        {
            if (isSelected())
                return false;

            return super.isTiny(bounds, g, canvas);
        }
    }

    public static final String ID_PT1 = "pt1";
    public static final String ID_PT2 = "pt2";

    protected final Anchor2D pt1;
    protected final Anchor2D pt2;

    public ROI2DLine(Point2D pt1, Point2D pt2)
    {
        super(new Line2D.Double());

        this.pt1 = createAnchor(pt1);
        this.pt2 = createAnchor(pt2);
        // keep pt2 selected to size the line for "interactive mode"
        this.pt2.setSelected(true);

        addPoint(this.pt1);
        addPoint(this.pt2);

        // set icon (default name is defined by getDefaultName()) 
        setIcon(ResourceUtil.ICON_ROI_LINE);
    }

    public ROI2DLine(Line2D line)
    {
        this(line.getP1(), line.getP2());
    }

    /**
     * @deprecated
     */
    @SuppressWarnings("unused")
    @Deprecated
    public ROI2DLine(Point2D pt, boolean cm)
    {
        this(pt);
    }

    public ROI2DLine(Point2D pt)
    {
        this(new Point2D.Double(pt.getX(), pt.getY()), pt);
    }

    /**
     * Generic constructor for interactive mode
     */
    public ROI2DLine(Point5D pt)
    {
        this(pt.toPoint2D());
        // getOverlay().setMousePos(pt);
    }

    public ROI2DLine(double x1, double y1, double x2, double y2)
    {
        this(new Point2D.Double(x1, y1), new Point2D.Double(x2, y2));
    }

    public ROI2DLine()
    {
        this(new Point2D.Double(), new Point2D.Double());
    }
    
    @Override
    public String getDefaultName()
    {
        return "Line2D";
    }

    @Override
    protected ROI2DShapePainter createPainter()
    {
        return new ROI2DLinePainter();
    }

    @Override
    protected Anchor2D createAnchor(Point2D pos)
    {
        return new ROI2DLineAnchor2D(pos);
    }

    public Line2D getLine()
    {
        return (Line2D) shape;
    }

    @Override
    public boolean canSetBounds()
    {
        return true;
    }

    @Override
    public void setBounds2D(Rectangle2D bounds)
    {
        beginUpdate();
        try
        {
            pt1.setPosition(bounds.getMinX(), bounds.getMinY());
            pt2.setPosition(bounds.getMaxX(), bounds.getMaxY());
        }
        finally
        {
            endUpdate();
        }
    }

    public void setLine(Line2D line)
    {
        beginUpdate();
        try
        {
            pt1.setPosition(line.getP1());
            pt2.setPosition(line.getP2());
        }
        finally
        {
            endUpdate();
        }
    }

    @Override
    protected void updateShape()
    {
        getLine().setLine(pt1.getPosition(), pt2.getPosition());

        // call super method after shape has been updated
        super.updateShape();
    }

    @Override
    public boolean canAddPoint()
    {
        // this ROI doesn't support point add
        return false;
    }

    @Override
    public boolean canRemovePoint()
    {
        // this ROI doesn't support point remove
        return false;
    }

    @Override
    protected boolean removePoint(IcyCanvas canvas, Anchor2D pt)
    {
        // this ROI doesn't support point remove
        return false;
    }

    @Override
    protected double getTotalDistance(List<Point2D> points, double factorX, double factorY)
    {
        // for ROI2DLine the total length don't need last point connection
        return Point2DUtil.getTotalDistance(points, factorX, factorY, false);
    }

    @Override
    public double computeNumberOfPoints()
    {
        return 0d;
    }

    @Override
    public boolean contains(double x, double y)
    {
        return false;
    }

    @Override
    public boolean contains(Point2D p)
    {
        return false;
    }

    @Override
    public boolean contains(double x, double y, double w, double h)
    {
        return false;
    }

    @Override
    public boolean contains(Rectangle2D r)
    {
        return false;
    }

    @Override
    public boolean contains(ROI roi)
    {
        return false;
    }

    @Override
    public boolean intersects(ROI r)
    {
        // special case of ROI2DLine
        if (r instanceof ROI2DLine)
            return onSamePos(((ROI2DLine) r), false) && ((ROI2DLine) r).getLine().intersectsLine(getLine());
        // special case of ROI2DRectangle
        if (r instanceof ROI2DRectangle)
            return onSamePos(((ROI2DRectangle) r), false)
                    && ((ROI2DRectangle) r).getRectangle().intersectsLine(getLine());

        return super.intersects(r);
    }

    @Override
    public boolean loadFromXML(Node node)
    {
        beginUpdate();
        try
        {
            if (!super.loadFromXML(node))
                return false;

            pt1.loadPositionFromXML(XMLUtil.getElement(node, ID_PT1));
            pt2.loadPositionFromXML(XMLUtil.getElement(node, ID_PT2));
        }
        finally
        {
            endUpdate();
        }

        return true;
    }

    @Override
    public boolean saveToXML(Node node)
    {
        if (!super.saveToXML(node))
            return false;

        pt1.savePositionToXML(XMLUtil.setElement(node, ID_PT1));
        pt2.savePositionToXML(XMLUtil.setElement(node, ID_PT2));

        return true;
    }
}