/*
 * 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.RectAnchor2D;
import icy.util.XMLUtil;

import java.awt.Color;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;

import org.w3c.dom.Node;

/**
 * Base class for rectangular shape ROI.
 * 
 * @author Stephane
 */
public abstract class ROI2DRectShape extends ROI2DShape
{
    protected class ROI2DRectAnchor2D extends RectAnchor2D
    {
        public ROI2DRectAnchor2D(Point2D position, Color color, Color selectedColor)
        {
            super(position, color, selectedColor);
        }

        @Override
        protected Anchor2D getOppositePoint()
        {
            if (this == topLeft)
                return bottomRight;
            if (this == topRight)
                return bottomLeft;
            if (this == bottomLeft)
                return topRight;

            return topLeft;
        };
    }

    public static final String ID_TOPLEFT = "top_left";
    public static final String ID_BOTTOMRIGHT = "bottom_right";

    protected final Anchor2D topLeft;
    protected final Anchor2D topRight;
    protected final Anchor2D bottomLeft;
    protected final Anchor2D bottomRight;

    protected boolean internalPositionSet;

    /**
     * 
     */
    public ROI2DRectShape(RectangularShape shape, Point2D topLeft, Point2D bottomRight)
    {
        super(shape);

        this.topLeft = createAnchor(topLeft);
        this.topRight = createAnchor(new Point2D.Double(bottomRight.getX(), topLeft.getY()));
        this.bottomLeft = createAnchor(new Point2D.Double(topLeft.getX(), bottomRight.getY()));
        this.bottomRight = createAnchor(bottomRight);
        // select the bottom right point by default for interactive mode
        this.bottomRight.setSelected(true);

        internalPositionSet = false;

        // order is important as we compute distance from connected points
        addPoint(this.topLeft);
        addPoint(this.topRight);
        addPoint(this.bottomRight);
        addPoint(this.bottomLeft);
    }

    @Override
    protected Anchor2D createAnchor(Point2D pos)
    {
        return new ROI2DRectAnchor2D(pos, getColor(), getFocusedColor());
    }

    protected RectangularShape getRectangularShape()
    {
        return (RectangularShape) shape;
    }

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

    @Override
    public void setBounds2D(Rectangle2D bounds)
    {
        beginUpdate();
        try
        {
            // set anchors (only 2 significants anchors need to be adjusted)
            topLeft.setPosition(bounds.getMinX(), bounds.getMinY());
            bottomRight.setPosition(bounds.getMaxX(), bounds.getMaxY());
        }
        finally
        {
            endUpdate();
        }
    }

    @Override
    protected void updateShape()
    {
        getRectangularShape().setFrameFromDiagonal(topLeft.getPosition(), bottomRight.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
    public void controlPointPositionChanged(Anchor2D source)
    {
        // we are modifying internally the position --> exit
        if (internalPositionSet)
            return;

        internalPositionSet = true;
        try
        {
            // adjust dependents anchors
            if (source == topLeft)
            {
                bottomLeft.setX(topLeft.getX());
                topRight.setY(topLeft.getY());
            }
            else if (source == topRight)
            {
                bottomRight.setX(topRight.getX());
                topLeft.setY(topRight.getY());
            }
            else if (source == bottomLeft)
            {
                topLeft.setX(bottomLeft.getX());
                bottomRight.setY(bottomLeft.getY());
            }
            else if (source == bottomRight)
            {
                topRight.setX(bottomRight.getX());
                bottomLeft.setY(bottomRight.getY());
            }
        }
        finally
        {
            internalPositionSet = false;
        }

        super.controlPointPositionChanged(source);
    }

    @Override
    public void translate(double dx, double dy)
    {
        beginUpdate();
        try
        {
            // translate (only 2 significants anchors need to be adjusted)
            topLeft.translate(dx, dy);
            bottomRight.translate(dx, dy);
        }
        finally
        {
            endUpdate();
        }
    }

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

            topLeft.loadPositionFromXML(XMLUtil.getElement(node, ID_TOPLEFT));
            bottomRight.loadPositionFromXML(XMLUtil.getElement(node, ID_BOTTOMRIGHT));
        }
        finally
        {
            endUpdate();
        }

        return true;
    }

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

        topLeft.savePositionToXML(XMLUtil.setElement(node, ID_TOPLEFT));
        bottomRight.savePositionToXML(XMLUtil.setElement(node, ID_BOTTOMRIGHT));

        return true;
    }

}