/* *
 *
 * Author: Paweł Lysy
 *
 *
 * */
'use strict';
import Controllable from './Controllable.js';
import ControllablePath from './ControllablePath.js';
import { defined, merge } from '../../../Shared/Utilities.js';
/* *
 *
 *  Class
 *
 * */
/**
 * A controllable ellipse class.
 *
 * @internal
 * @requires modules/annotations
 *
 * @class
 * @name Highcharts.AnnotationControllableEllipse
 *
 * @param {Highcharts.Annotation} annotation an annotation instance
 * @param {Highcharts.AnnotationsShapeOptions} options a shape's options
 * @param {number} index of the Ellipse
 */
class ControllableEllipse extends Controllable {
    /* *
     *
     *  Constructor
     *
     * */
    constructor(annotation, options, index) {
        super(annotation, options, index, 'shape');
        /* *
         *
         *  Properties
         *
         * */
        this.type = 'ellipse';
    }
    /* *
     *
     *  Functions
     *
     * */
    init(annotation, options, index) {
        if (defined(options.yAxis)) {
            options.points.forEach((point) => {
                if (point && typeof point !== 'string') {
                    point.yAxis = options.yAxis;
                }
            });
        }
        if (defined(options.xAxis)) {
            options.points.forEach((point) => {
                if (point && typeof point !== 'string') {
                    point.xAxis = options.xAxis;
                }
            });
        }
        super.init(annotation, options, index);
    }
    /**
     * Render the element.
     *
     * @param {Highcharts.SVGElement} parent
     *        Parent SVG element.
     */
    render(parent) {
        this.graphic = this.annotation.chart.renderer.createElement('ellipse')
            .attr(this.attrsFromOptions(this.options))
            .add(parent);
        super.render();
    }
    /**
     * Translate the points. Mostly used to handle dragging of the ellipse.
     */
    translate(dx, dy) {
        super.translateShape(dx, dy, true);
    }
    /**
     * Get the distance from the line to the point.
     *
     * @param {object} point1
     *        First point which is on the line
     * @param {object} point2
     *        Second point
     * @param {number} x0
     *        Point's x value from which you want to calculate the distance from
     * @param {number} y0
     *        Point's y value from which you want to calculate the distance from
     */
    getDistanceFromLine(point1, point2, x0, y0) {
        return Math.abs((point2.y - point1.y) * x0 - (point2.x - point1.x) * y0 +
            point2.x * point1.y - point2.y * point1.x) / Math.sqrt((point2.y - point1.y) * (point2.y - point1.y) +
            (point2.x - point1.x) * (point2.x - point1.x));
    }
    /**
     * The function calculates the svg attributes of the ellipse, and returns
     * all parameters necessary to draw the ellipse.
     *
     * @param {Highcharts.BBoxObject} position
     *        Absolute position of the first point in points array
     * @param {Highcharts.BBoxObject} position2
     *        Absolute position of the second point in points array
     */
    getAttrs(position, position2) {
        const x1 = position.x, y1 = position.y, x2 = position2.x, y2 = position2.y, cx = (x1 + x2) / 2, cy = (y1 + y2) / 2, rx = Math.sqrt((x1 - x2) * (x1 - x2) / 4 + (y1 - y2) * (y1 - y2) / 4), tan = (y2 - y1) / (x2 - x1);
        let angle = Math.atan(tan) * 180 / Math.PI;
        if (cx < x1) {
            angle += 180;
        }
        const ry = this.getRY();
        return { cx, cy, rx, ry, angle };
    }
    /**
     * Get the value of minor radius of the ellipse.
     */
    getRY() {
        const yAxis = this.getYAxis();
        return defined(yAxis) ?
            Math.abs(yAxis.toPixels(this.options.ry) - yAxis.toPixels(0)) :
            this.options.ry;
    }
    /**
     * Get the yAxis object to which the ellipse is pinned.
     */
    getYAxis() {
        const yAxisIndex = this.options.yAxis;
        return this.chart.yAxis[yAxisIndex];
    }
    /**
     * Get the absolute coordinates of the MockPoint.
     *
     * @param {Highcharts.AnnotationPointType} point
     *        MockPoint that is added through options
     */
    getAbsolutePosition(point) {
        return this.anchor(point).absolutePosition;
    }
    /**
     * Redraw the element.
     *
     * @param {boolean} [animation]
     *        Display an animation
     */
    redraw(animation) {
        if (this.graphic) {
            const position = this.getAbsolutePosition(this.points[0]), position2 = this.getAbsolutePosition(this.points[1]), attrs = this.getAttrs(position, position2);
            if (position) {
                this.graphic[animation ? 'animate' : 'attr']({
                    cx: attrs.cx,
                    cy: attrs.cy,
                    rx: attrs.rx,
                    ry: attrs.ry,
                    rotation: attrs.angle,
                    rotationOriginX: attrs.cx,
                    rotationOriginY: attrs.cy
                });
            }
            else {
                this.graphic.attr({
                    x: 0,
                    y: -9e9
                });
            }
            this.graphic.placed = Boolean(position);
        }
        super.redraw(animation);
    }
    /**
     * Set the radius Y.
     *
     * @param {number} ry
     *        A radius in y direction to be set
     */
    setYRadius(ry) {
        const shapes = this.annotation.userOptions.shapes;
        this.options.ry = ry;
        if (shapes && shapes[0]) {
            shapes[0].ry = ry;
            shapes[0].ry = ry;
        }
    }
}
/* *
 *
 *  Static Properties
 *
 * */
/**
 * A map object which allows to map options attributes to element
 * attributes.
 *
 * @name Highcharts.AnnotationControllableEllipse.attrsMap
 * @type {Highcharts.Dictionary<string>}
 */
ControllableEllipse.attrsMap = merge(ControllablePath.attrsMap, {
    ry: 'ry'
});
/* *
 *
 *  Default Export
 *
 * */
/** @internal */
export default ControllableEllipse;
