import { __values } from "tslib";
import { isObject, each, get, groupBy, isNil, filter } from '@antv/util';
import { polarToCartesian } from '../../../../util/graphics';
import { antiCollision } from './util';
/** label text和line距离 4px */
var MARGIN = 4;
/**
 * 配置 labelline
 * @param item PolarLabelItem
 */
function drawLabelline(item /** PolarLabelItem */, coordinate) {
    /** 坐标圆心 */
    var center = coordinate.getCenter();
    /** 圆半径 */
    var radius = coordinate.getRadius();
    if (item && item.labelLine) {
        var angle = item.angle, labelOffset = item.offset;
        // 贴近圆周
        var startPoint = polarToCartesian(center.x, center.y, radius, angle);
        var itemX = item.x + get(item, 'offsetX', 0) * (Math.cos(angle) > 0 ? 1 : -1);
        var itemY = item.y + get(item, 'offsetY', 0) * (Math.sin(angle) > 0 ? 1 : -1);
        var endPoint = {
            x: itemX - Math.cos(angle) * MARGIN,
            y: itemY - Math.sin(angle) * MARGIN,
        };
        var smoothConnector = item.labelLine.smooth;
        var path = [];
        var dx = endPoint.x - center.x;
        var dy = endPoint.y - center.y;
        var endAngle = Math.atan(dy / dx);
        // 第三象限 & 第四象限
        if (dx < 0) {
            endAngle += Math.PI;
        }
        // 默认 smooth, undefined 也为 smooth
        if (smoothConnector === false) {
            if (!isObject(item.labelLine)) {
                // labelLine: true
                item.labelLine = {};
            }
            // 表示弧线的方向，0 表示从起点到终点沿逆时针画弧, 1 表示顺时针
            var sweepFlag = 0;
            // 第一象限
            if ((angle < 0 && angle > -Math.PI / 2) || angle > Math.PI * 1.5) {
                if (endPoint.y > startPoint.y) {
                    sweepFlag = 1;
                }
            }
            // 第二象限
            if (angle >= 0 && angle < Math.PI / 2) {
                if (endPoint.y > startPoint.y) {
                    sweepFlag = 1;
                }
            }
            // 第三象限
            if (angle >= Math.PI / 2 && angle < Math.PI) {
                if (startPoint.y > endPoint.y) {
                    sweepFlag = 1;
                }
            }
            // 第四象限
            if (angle < -Math.PI / 2 || (angle >= Math.PI && angle < Math.PI * 1.5)) {
                if (startPoint.y > endPoint.y) {
                    sweepFlag = 1;
                }
            }
            var distance = labelOffset / 2 > 4 ? 4 : Math.max(labelOffset / 2 - 1, 0);
            var breakPoint = polarToCartesian(center.x, center.y, radius + distance, angle);
            // 圆弧的结束点
            var breakPoint3 = polarToCartesian(center.x, center.y, radius + labelOffset / 2, endAngle);
            /**
             * @example
             * M 100 100 L100 90 A 50 50 0 0 0 150 50
             * 移动至 (100, 100), 连接到 (100, 90), 以 (50, 50) 为圆心，绘制圆弧至 (150, 50);
             * A 命令的第 4 个参数 large-arc-flag, 决定弧线是大于还是小于 180 度: 0 表示小角度弧，1 表示大角
             * 第 5 个参数: 是否顺时针绘制
             */
            // 默认小弧
            var largeArcFlag = 0;
            // step1: 移动至起点
            path.push("M ".concat(startPoint.x, " ").concat(startPoint.y));
            // step2: 连接拐点
            path.push("L ".concat(breakPoint.x, " ").concat(breakPoint.y));
            // step3: 绘制圆弧 至 结束点
            path.push("A ".concat(center.x, " ").concat(center.y, " 0 ").concat(largeArcFlag, " ").concat(sweepFlag, " ").concat(breakPoint3.x, " ").concat(breakPoint3.y));
            // step4: 连接结束点
            path.push("L ".concat(endPoint.x, " ").concat(endPoint.y));
        }
        else {
            var breakPoint = polarToCartesian(center.x, center.y, radius + (labelOffset / 2 > 4 ? 4 : Math.max(labelOffset / 2 - 1, 0)), angle);
            // G2 旧的拉线
            // path.push('Q', `${breakPoint.x}`, `${breakPoint.y}`, `${endPoint.x}`, `${endPoint.y}`);
            var xSign = startPoint.x < center.x ? 1 : -1;
            // step1: 连接结束点
            path.push("M ".concat(endPoint.x, " ").concat(endPoint.y));
            var slope1 = (startPoint.y - center.y) / (startPoint.x - center.x);
            var slope2 = (endPoint.y - center.y) / (endPoint.x - center.x);
            if (Math.abs(slope1 - slope2) > Math.pow(Math.E, -16)) {
                // step2: 绘制 curve line (起点 & 结合点与圆心的斜率不等时, 由于存在误差, 使用近似处理)
                path.push.apply(path, [
                    'C',
                    endPoint.x + xSign * 4,
                    endPoint.y,
                    2 * breakPoint.x - startPoint.x,
                    2 * breakPoint.y - startPoint.y,
                    startPoint.x,
                    startPoint.y,
                ]);
            }
            // step3: 连接至起点
            path.push("L ".concat(startPoint.x, " ").concat(startPoint.y));
        }
        item.labelLine.path = path.join(' ');
    }
}
/**
 * 饼图 outer-label 布局, 适用于 type = pie 且 label offset > 0 的标签
 */
export function pieOuterLabelLayout(originalItems, labels, shapes, region) {
    var e_1, _a;
    var items = filter(originalItems, function (item) { return !isNil(item); });
    /** 坐标系 */
    var coordinate = labels[0] && labels[0].get('coordinate');
    if (!coordinate) {
        return;
    }
    /** 坐标圆心 */
    var center = coordinate.getCenter();
    /** 圆半径 */
    var radius = coordinate.getRadius();
    /** label shapes */
    var labelsMap = {};
    try {
        for (var labels_1 = __values(labels), labels_1_1 = labels_1.next(); !labels_1_1.done; labels_1_1 = labels_1.next()) {
            var labelShape = labels_1_1.value;
            labelsMap[labelShape.get('id')] = labelShape;
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (labels_1_1 && !labels_1_1.done && (_a = labels_1.return)) _a.call(labels_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
    // note labelHeight 可以控制 label 的行高
    var labelHeight = get(items[0], 'labelHeight', 14);
    var labelOffset = get(items[0], 'offset', 0);
    if (labelOffset <= 0) {
        return;
    }
    var LEFT_HALF_KEY = 'left';
    var RIGHT_HALF_KEY = 'right';
    // step 1: separate labels
    var separateLabels = groupBy(items, function (item) { return (item.x < center.x ? LEFT_HALF_KEY : RIGHT_HALF_KEY); });
    var start = coordinate.start, end = coordinate.end;
    // step2: calculate totalHeight
    var totalHeight = Math.min((radius + labelOffset + labelHeight) * 2, coordinate.getHeight());
    var totalR = totalHeight / 2;
    /** labels 容器的范围(后续根据组件的布局设计进行调整) */
    var labelsContainerRange = {
        minX: start.x,
        maxX: end.x,
        minY: center.y - totalR,
        maxY: center.y + totalR,
    };
    // step 3: antiCollision
    each(separateLabels, function (half, key) {
        var maxLabelsCountForOneSide = Math.floor(totalHeight / labelHeight);
        if (half.length > maxLabelsCountForOneSide) {
            half.sort(function (a, b) {
                // sort by percentage DESC
                return b.percent - a.percent;
            });
            each(half, function (labelItem, idx) {
                if (idx + 1 > maxLabelsCountForOneSide) {
                    labelsMap[labelItem.id].set('visible', false);
                    labelItem.invisible = true;
                }
            });
        }
        antiCollision(half, labelHeight, labelsContainerRange);
    });
    each(separateLabels, function (half, key) {
        each(half, function (item) {
            var isRight = key === RIGHT_HALF_KEY;
            var labelShape = labelsMap[item.id];
            // because group could not effect content-shape, should set content-shape position manually
            var content = labelShape.getChildByIndex(0);
            // textShape 发生过调整
            if (content) {
                var r = radius + labelOffset;
                // (x - cx)^2 + (y - cy)^2 = totalR^2
                var dy = item.y - center.y;
                var rPow2 = Math.pow(r, 2);
                var dyPow2 = Math.pow(dy, 2);
                var dxPow2 = rPow2 - dyPow2 > 0 ? rPow2 - dyPow2 : 0;
                var dx = Math.sqrt(dxPow2);
                var dx_offset = Math.abs(Math.cos(item.angle) * r);
                if (!isRight) {
                    // left
                    item.x = center.x - Math.max(dx, dx_offset);
                }
                else {
                    // right
                    item.x = center.x + Math.max(dx, dx_offset);
                }
            }
            // adjust labelShape
            if (content) {
                content.attr('y', item.y);
                content.attr('x', item.x);
            }
            drawLabelline(item, coordinate);
        });
    });
}
//# sourceMappingURL=outer.js.map