'use strict';
import H from '../../parts/Globals.js';
import '../../parts/Utilities.js';

var Annotation = H.Annotation,
    MockPoint = Annotation.MockPoint,
    CrookedLine = Annotation.types.crookedLine;

/**
 * @class
 * @extends Annotation.CrookedLine
 * @memberOf Annotation
 */
function InfinityLine() {
    CrookedLine.apply(this, arguments);
}

InfinityLine.findEdgeCoordinate = function (
    firstPoint,
    secondPoint,
    xOrY,
    edgePointFirstCoordinate
) {
    var xOrYOpposite = xOrY === 'x' ? 'y' : 'x';

    // solves equation for x or y
    // y - y1 = (y2 - y1) / (x2 - x1) * (x - x1)
    return (
        (secondPoint[xOrY] - firstPoint[xOrY]) *
        (edgePointFirstCoordinate - firstPoint[xOrYOpposite]) /
        (secondPoint[xOrYOpposite] - firstPoint[xOrYOpposite]) +
        firstPoint[xOrY]
    );
};

InfinityLine.findEdgePoint = function (firstPoint, secondPoint) {
    var xAxis = firstPoint.series.xAxis,
        yAxis = secondPoint.series.yAxis,
        firstPointPixels = MockPoint.pointToPixels(firstPoint),
        secondPointPixels = MockPoint.pointToPixels(secondPoint),
        deltaX = secondPointPixels.x - firstPointPixels.x,
        deltaY = secondPointPixels.y - firstPointPixels.y,
        xAxisMin = xAxis.left,
        xAxisMax = xAxisMin + xAxis.width,
        yAxisMin = yAxis.top,
        yAxisMax = yAxisMin + yAxis.height,
        xLimit = deltaX < 0 ? xAxisMin : xAxisMax,
        yLimit = deltaY < 0 ? yAxisMin : yAxisMax,
        edgePoint = {
            x: deltaX === 0 ? firstPointPixels.x : xLimit,
            y: deltaY === 0 ? firstPointPixels.y : yLimit
        },
        edgePointX,
        edgePointY,
        swap;

    if (deltaX !== 0 && deltaY !== 0) {
        edgePointY = InfinityLine.findEdgeCoordinate(
            firstPointPixels,
            secondPointPixels,
            'y',
            xLimit
        );

        edgePointX = InfinityLine.findEdgeCoordinate(
            firstPointPixels,
            secondPointPixels,
            'x',
            yLimit
        );

        if (edgePointY >= yAxisMin && edgePointY <= yAxisMax) {
            edgePoint.x = xLimit;
            edgePoint.y = edgePointY;
        } else {
            edgePoint.x = edgePointX;
            edgePoint.y = yLimit;
        }
    }

    edgePoint.x -= xAxisMin;
    edgePoint.y -= yAxisMin;

    if (firstPoint.series.chart.inverted) {
        swap = edgePoint.x;
        edgePoint.x = edgePoint.y;
        edgePoint.y = swap;
    }

    return edgePoint;
};

var edgePoint = function (startIndex, endIndex) {
    return function (target) {
        var annotation = target.annotation,
            points = annotation.points,
            type = annotation.options.typeOptions.type;

        if (type === 'horizontalLine') {
            // Horizontal line has only one point,
            // make a copy of it:
            points = [
                points[0],
                new MockPoint(
                    annotation.chart,
                    points[0].target,
                    {
                        x: points[0].x + 1,
                        y: points[0].y,
                        xAxis: points[0].options.xAxis,
                        yAxis: points[0].options.yAxis
                    }
                )
            ];
        } else if (type === 'verticalLine') {
            // The same for verticalLine type:
            points = [
                points[0],
                new MockPoint(
                    annotation.chart,
                    points[0].target,
                    {
                        x: points[0].x,
                        y: points[0].y + 1,
                        xAxis: points[0].options.xAxis,
                        yAxis: points[0].options.yAxis
                    }
                )
            ];
        }

        return InfinityLine.findEdgePoint(
            points[startIndex],
            points[endIndex]
        );
    };
};

InfinityLine.endEdgePoint = edgePoint(0, 1);
InfinityLine.startEdgePoint = edgePoint(1, 0);

H.extendAnnotation(
    InfinityLine,
    CrookedLine,
    /** @lends Annotation.InfinityLine# */
    {
        addShapes: function () {
            var typeOptions = this.options.typeOptions,
                points = [
                    this.points[0],
                    InfinityLine.endEdgePoint
                ];

            if (typeOptions.type.match(/Line/g)) {
                points[0] = InfinityLine.startEdgePoint;
            }

            var line = this.initShape(
                H.merge(typeOptions.line, {
                    type: 'path',
                    points: points
                }),
                false
            );

            typeOptions.line = line.options;
        }

    }
);

/**
 * An infinity line annotation.
 *
 * @sample highcharts/annotations-advanced/infinity-line/
 *         Infinity Line
 *
 * @extends   annotations.crookedLine
 * @product   highstock
 * @apioption annotations.infinityLine
 */

Annotation.types.infinityLine = InfinityLine;

export default InfinityLine;
