import { __assign } from "tslib";
import { isArray, isFunction, isString } from '@antv/util';
import { normalPadding } from '../../utils/padding';
import { log, LEVEL, getContainerSize } from '../../utils';
import { functor, wordCloud } from '../../utils/transform/word-cloud';
/**
 * 用 DataSet 转换词云图数据
 * @param params
 */
export function transform(params) {
    var rawOptions = params.options, chart = params.chart;
    var _a = chart, width = _a.width, height = _a.height, chartPadding = _a.padding, appendPadding = _a.appendPadding, ele = _a.ele;
    var data = rawOptions.data, imageMask = rawOptions.imageMask, wordField = rawOptions.wordField, weightField = rawOptions.weightField, colorField = rawOptions.colorField, wordStyle = rawOptions.wordStyle, timeInterval = rawOptions.timeInterval, random = rawOptions.random, spiral = rawOptions.spiral, _b = rawOptions.autoFit, autoFit = _b === void 0 ? true : _b, placementStrategy = rawOptions.placementStrategy;
    if (!data || !data.length) {
        return [];
    }
    var fontFamily = wordStyle.fontFamily, fontWeight = wordStyle.fontWeight, padding = wordStyle.padding, fontSize = wordStyle.fontSize;
    var arr = getSingleKeyValues(data, weightField);
    var range = [min(arr), max(arr)];
    // 变换出 text 和 value 字段
    var words = data.map(function (datum) { return ({
        text: datum[wordField],
        value: datum[weightField],
        color: datum[colorField],
        datum: datum,
    }); });
    var options = {
        imageMask: imageMask,
        font: fontFamily,
        fontSize: getFontSizeMapping(fontSize, range),
        fontWeight: fontWeight,
        // 图表宽高减去 padding 之后的宽高
        size: getSize({
            width: width,
            height: height,
            padding: chartPadding,
            appendPadding: appendPadding,
            autoFit: autoFit,
            container: ele,
        }),
        padding: padding,
        timeInterval: timeInterval,
        random: random,
        spiral: spiral,
        rotate: getRotate(rawOptions),
    };
    // 自定义布局函数
    if (isFunction(placementStrategy)) {
        var result = words.map(function (word, index, words) { return (__assign(__assign(__assign({}, word), { hasText: !!word.text, font: functor(options.font)(word, index, words), weight: functor(options.fontWeight)(word, index, words), rotate: functor(options.rotate)(word, index, words), size: functor(options.fontSize)(word, index, words), style: 'normal' }), placementStrategy.call(chart, word, index, words))); });
        // 添加两个参照数据，分别表示左上角和右下角
        result.push({
            text: '',
            value: 0,
            x: 0,
            y: 0,
            opacity: 0,
        });
        result.push({
            text: '',
            value: 0,
            x: options.size[0],
            y: options.size[1],
            opacity: 0,
        });
        return result;
    }
    // 数据准备在外部做，wordCloud 单纯就是做布局
    return wordCloud(words, options);
}
/**
 * 获取最终的实际绘图尺寸：[width, height]
 * @param chart
 */
export function getSize(options) {
    var width = options.width, height = options.height;
    var container = options.container, autoFit = options.autoFit, padding = options.padding, appendPadding = options.appendPadding;
    // 由于词云图每个词语的坐标都是先通过 DataSet 根据图表宽高计算出来的，
    // 也就是说，如果一开始提供给 DataSet 的宽高信息和最终显示的宽高不相同，
    // 那么就会出现布局错乱的情况，所以这里处理的目的就是让一开始提供给 DataSet 的
    // 宽高信息与最终显示的宽高信息相同，避免显示错乱。
    if (autoFit) {
        var containerSize = getContainerSize(container);
        width = containerSize.width;
        height = containerSize.height;
    }
    // 宽高不能为 0，否则会造成死循环
    width = width || 400;
    height = height || 400;
    var _a = resolvePadding({ padding: padding, appendPadding: appendPadding }), top = _a[0], right = _a[1], bottom = _a[2], left = _a[3];
    var result = [width - (left + right), height - (top + bottom)];
    return result;
}
/**
 * 根据图表的 padding 和 appendPadding 计算出图表的最终 padding
 * @param chart
 */
function resolvePadding(options) {
    var padding = normalPadding(options.padding);
    var appendPadding = normalPadding(options.appendPadding);
    var top = padding[0] + appendPadding[0];
    var right = padding[1] + appendPadding[1];
    var bottom = padding[2] + appendPadding[2];
    var left = padding[3] + appendPadding[3];
    return [top, right, bottom, left];
}
/**
 * 处理 imageMask 可能为 url 字符串的情况
 * @param  {HTMLImageElement | string} img
 * @return {Promise}
 */
export function processImageMask(img) {
    return new Promise(function (res, rej) {
        if (img instanceof HTMLImageElement) {
            res(img);
            return;
        }
        if (isString(img)) {
            var image_1 = new Image();
            image_1.crossOrigin = 'anonymous';
            image_1.src = img;
            image_1.onload = function () {
                res(image_1);
            };
            image_1.onerror = function () {
                log(LEVEL.ERROR, false, 'image %s load failed !!!', img);
                rej();
            };
            return;
        }
        log(LEVEL.WARN, img === undefined, 'The type of imageMask option must be String or HTMLImageElement.');
        rej();
    });
}
/**
 * 把用户提供的 fontSize 值转换成符合 DataSet 要求的值
 * @param options
 * @param range
 */
export function getFontSizeMapping(fontSize, range) {
    if (isFunction(fontSize)) {
        return fontSize;
    }
    if (isArray(fontSize)) {
        var fMin_1 = fontSize[0], fMax_1 = fontSize[1];
        if (!range) {
            return function () { return (fMax_1 + fMin_1) / 2; };
        }
        var min_1 = range[0], max_1 = range[1];
        if (max_1 === min_1) {
            return function () { return (fMax_1 + fMin_1) / 2; };
        }
        return function fontSize(_a) {
            var value = _a.value;
            return ((fMax_1 - fMin_1) / (max_1 - min_1)) * (value - min_1) + fMin_1;
        };
    }
    return function () { return fontSize; };
}
export function getSingleKeyValues(data, key) {
    return data
        .map(function (v) { return v[key]; })
        .filter(function (v) {
        // 过滤非 number
        if (typeof v === 'number' && !isNaN(v))
            return true;
        return false;
    });
}
/**
 * 把用户提供的关于旋转角度的字段值转换成符合 DataSet 要求的值
 * @param options
 */
function getRotate(options) {
    var _a = resolveRotate(options), rotation = _a.rotation, rotationSteps = _a.rotationSteps;
    if (!isArray(rotation))
        return rotation;
    var min = rotation[0];
    var max = rotation[1];
    // 等于 1 时不旋转，所以把每份大小设为 0
    var perSize = rotationSteps === 1 ? 0 : (max - min) / (rotationSteps - 1);
    return function rotate() {
        if (max === min)
            return max;
        return Math.floor(Math.random() * rotationSteps) * perSize;
    };
}
/**
 * 确保值在要求范围内
 * @param options
 */
function resolveRotate(options) {
    var rotationSteps = options.wordStyle.rotationSteps;
    if (rotationSteps < 1) {
        log(LEVEL.WARN, false, 'The rotationSteps option must be greater than or equal to 1.');
        rotationSteps = 1;
    }
    return {
        rotation: options.wordStyle.rotation,
        rotationSteps: rotationSteps,
    };
}
/**
 * 传入一个元素为数字的数组，
 * 返回该数组中值最小的数字。
 * @param numbers
 */
function min(numbers) {
    return Math.min.apply(Math, numbers);
}
/**
 * 传入一个元素为数字的数组，
 * 返回该数组中值最大的数字。
 * @param numbers
 */
function max(numbers) {
    return Math.max.apply(Math, numbers);
}
//# sourceMappingURL=utils.js.map