package CH.ifa.draw.figures;

import java.awt.Point;
import java.io.Serial;
import java.util.Vector;

/**
 * Extension of PolyLineFigure to enhance smoothness and performance by reducing the points used for a polyline by
 * using the Ramer-Douglas-Peucker-Algorithm that is applied after a new point is added.
 */
public class SmoothPolyLineFigure extends PolyLineFigure {
    /*
     * Serialization support.
     */
    @Serial
    private static final long serialVersionUID = -7951352179906577773L;

    /**
     * Normalized smoothness when render the figure with B-Spline. Normalized smoothness value is in range 0...1
     * 0 means no smoothing and 1 means maximum smoothing.
     */
    private final double _smoothness;

    /**
     * Creates a new SmoothPolyLineFigure and sets the smoothness to the given value.
     *
     * @param smoothness value the smoothness is set to
     */
    public SmoothPolyLineFigure(double smoothness) {
        this._smoothness = smoothness;
        fPoints = new Vector<>(4);
    }

    /**
     * Creates a new SmoothPolyLineFigure with the given starting point and smoothness.
     *
     * @param x x-coordinate of the starting point
     * @param y y-coordinate of the starting point
     * @param smoothness value the smoothness is set to
     */
    public SmoothPolyLineFigure(int x, int y, double smoothness) {
        this._smoothness = smoothness;
        fPoints = new Vector<>();
        fPoints.addElement(new Point(x, y));
    }

    @Override
    public void addPoint(int x, int y) {
        fPoints.addElement(new Point(x, y));

        // Simplify points before rendering
        fPoints = RamerDouglasPeucker.simplifyTailBySmoothness(fPoints, _smoothness);

        if (_spline != null) {
            _spline.setPoints(fPoints);
        }
        changed();
    }

    @Override
    protected boolean drawAsSpline() {
        // Always use Spline to render SmoothPolyLineFigure
        return true;
    }

    /**
     * Converts the current figure to an equivalent PolyLineFigure with the same data model.
     *
     * @return A new PolyLineFigure with the same points and line shape as the current figure.
     */
    public PolyLineFigure getEquivalentPolylineFigure() {
        PolyLineFigure figure = new PolyLineFigure();
        figure.setAttribute("LineShape", PolyLineFigure.BSPLINE_SHAPE);
        figure.fPoints = this.fPoints;
        return figure;
    }

}