"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __spread = (this && this.__spread) || function () {
    for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
    return ar;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.shapeViewModel = void 0;
var d3_array_1 = require("d3-array");
var d3_scale_1 = require("d3-scale");
var color_library_wrappers_1 = require("../../../../common/color_library_wrappers");
var scales_1 = require("../../../../scales");
var constants_1 = require("../../../../scales/constants");
var canvas_text_bbox_calculator_1 = require("../../../../utils/bbox/canvas_text_bbox_calculator");
var common_1 = require("../../../../utils/common");
function getValuesInRange(values, startValue, endValue) {
    var startIndex = values.indexOf(startValue);
    var endIndex = Math.min(values.indexOf(endValue) + 1, values.length);
    return values.slice(startIndex, endIndex);
}
function getTicks(chartWidth, xAxisLabelConfig) {
    var bboxCompute = new canvas_text_bbox_calculator_1.CanvasTextBBoxCalculator();
    var labelSample = xAxisLabelConfig.formatter(Date.now());
    var width = bboxCompute.compute(labelSample, xAxisLabelConfig.padding, xAxisLabelConfig.fontSize, xAxisLabelConfig.fontFamily).width;
    bboxCompute.destroy();
    var maxTicks = Math.floor(chartWidth / width);
    return maxTicks / 2;
}
function shapeViewModel(textMeasure, spec, config, settingsSpec, chartDimensions, heatmapTable, colorScale, filterRanges, _a) {
    var _b, _c;
    var height = _a.height, pageSize = _a.pageSize;
    var gridStrokeWidth = (_b = config.grid.stroke.width) !== null && _b !== void 0 ? _b : 1;
    var table = heatmapTable.table, yValues = heatmapTable.yValues, xDomain = heatmapTable.xDomain;
    var boxedYValues = yValues.map(function (value) {
        return __assign({ text: config.yAxisLabel.formatter(value), value: value }, config.yAxisLabel);
    });
    var yScale = d3_scale_1.scaleBand().domain(yValues).range([0, height]);
    var yInvertedScale = d3_scale_1.scaleQuantize().domain([0, height]).range(yValues);
    var xValues = xDomain.domain;
    var timeScale = xDomain.type === constants_1.ScaleType.Time
        ? new scales_1.ScaleContinuous({
            type: constants_1.ScaleType.Time,
            domain: xDomain.domain,
            range: [0, chartDimensions.width],
            nice: false,
        }, {
            desiredTickCount: getTicks(chartDimensions.width, config.xAxisLabel),
            timeZone: config.timeZone,
        })
        : null;
    if (timeScale) {
        var result = [];
        var _d = __read(xValues, 1), timePoint = _d[0];
        while (timePoint < xValues[1]) {
            result.push(timePoint);
            timePoint += xDomain.minInterval;
        }
        xValues = result;
    }
    var xScale = d3_scale_1.scaleBand().domain(xValues).range([0, chartDimensions.width]);
    var xInvertedScale = d3_scale_1.scaleQuantize().domain([0, chartDimensions.width]).range(xValues);
    var cellWidth = config.cell.maxWidth !== 'fill' && xScale.bandwidth() > config.cell.maxWidth
        ? config.cell.maxWidth
        : xScale.bandwidth();
    var cellHeight = yScale.bandwidth();
    var currentGridHeight = cellHeight * pageSize;
    var getTextValue = function (formatter, scaleCallback) {
        if (scaleCallback === void 0) { scaleCallback = xScale; }
        return function (value) {
            return __assign(__assign({ text: formatter(value, { timeZone: config.timeZone }), value: value }, config.xAxisLabel), { x: chartDimensions.left + (scaleCallback(value) || 0), y: cellHeight * pageSize + config.xAxisLabel.fontSize / 2 + config.xAxisLabel.padding });
        };
    };
    var textXValues = timeScale
        ? timeScale.ticks().map(getTextValue(config.xAxisLabel.formatter, function (x) { return timeScale.scale(x); }))
        : xValues.map(function (textBox) {
            return __assign(__assign({}, getTextValue(config.xAxisLabel.formatter)(textBox)), { x: chartDimensions.left + (xScale(textBox) || 0) + xScale.bandwidth() / 2 });
        });
    var padding = config.yAxisLabel.padding;
    var rightPadding = typeof padding === 'number' ? padding : (_c = padding.right) !== null && _c !== void 0 ? _c : 0;
    var textYValues = boxedYValues.map(function (d) {
        return __assign(__assign({}, d), { x: chartDimensions.left - rightPadding, y: cellHeight / 2 + (yScale(d.value) || 0) });
    });
    var cellMap = table.reduce(function (acc, d) {
        var x = xScale(String(d.x));
        var y = yScale(String(d.y)) + gridStrokeWidth;
        var yIndex = yValues.indexOf(d.y);
        var color = colorScale.config(d.value);
        if (x === undefined || y === undefined || yIndex === -1) {
            return acc;
        }
        var cellKey = getCellKey(d.x, d.y);
        acc[cellKey] = {
            x: (config.cell.maxWidth !== 'fill' ? x + xScale.bandwidth() / 2 - config.cell.maxWidth / 2 : x) + gridStrokeWidth,
            y: y,
            yIndex: yIndex,
            width: cellWidth - gridStrokeWidth * 2,
            height: cellHeight - gridStrokeWidth * 2,
            datum: d,
            fill: {
                color: color_library_wrappers_1.stringToRGB(color),
            },
            stroke: {
                color: color_library_wrappers_1.stringToRGB(config.cell.border.stroke),
                width: config.cell.border.strokeWidth,
            },
            value: d.value,
            visible: !isFilteredValue(filterRanges, d.value),
            formatted: spec.valueFormatter(d.value),
        };
        return acc;
    }, {});
    var pickQuads = function (x, y) {
        if (x > 0 && x < chartDimensions.left && y > chartDimensions.top && y < chartDimensions.height) {
            var yLabelKey_1 = yInvertedScale(y);
            var yLabelValue = textYValues.find(function (v) { return v.value === yLabelKey_1; });
            if (yLabelValue) {
                return yLabelValue;
            }
        }
        if (x < chartDimensions.left || y < chartDimensions.top) {
            return [];
        }
        if (x > chartDimensions.width + chartDimensions.left || y > chartDimensions.height) {
            return [];
        }
        var xValue = xInvertedScale(x - chartDimensions.left);
        var yValue = yInvertedScale(y);
        if (xValue === undefined || yValue === undefined) {
            return [];
        }
        var cellKey = getCellKey(xValue, yValue);
        var cell = cellMap[cellKey];
        if (cell) {
            return [cell];
        }
        return [];
    };
    var pickDragArea = function (bound) {
        var _a = __read(bound, 2), start = _a[0], end = _a[1];
        var left = chartDimensions.left, top = chartDimensions.top, width = chartDimensions.width;
        var topLeft = [Math.min(start.x, end.x) - left, Math.min(start.y, end.y) - top];
        var bottomRight = [Math.max(start.x, end.x) - left, Math.max(start.y, end.y) - top];
        var startX = xInvertedScale(common_1.clamp(topLeft[0], 0, width));
        var endX = xInvertedScale(common_1.clamp(bottomRight[0], 0, width));
        var startY = yInvertedScale(common_1.clamp(topLeft[1], 0, currentGridHeight - 1));
        var endY = yInvertedScale(common_1.clamp(bottomRight[1], 0, currentGridHeight - 1));
        var allXValuesInRange = getValuesInRange(xValues, startX, endX);
        var allYValuesInRange = getValuesInRange(yValues, startY, endY);
        var invertedXValues = timeScale && typeof endX === 'number' ? [startX, endX + xDomain.minInterval] : __spread(allXValuesInRange);
        var cells = [];
        allXValuesInRange.forEach(function (x) {
            allYValuesInRange.forEach(function (y) {
                var cellKey = getCellKey(x, y);
                cells.push(cellMap[cellKey]);
            });
        });
        return {
            cells: cells.filter(Boolean),
            x: invertedXValues,
            y: allYValuesInRange,
        };
    };
    var pickHighlightedArea = function (x, y) {
        var startValue = x[0];
        var endValue = x[x.length - 1];
        var leftIndex = typeof startValue === 'number' ? d3_array_1.bisectLeft(xValues, startValue) : xValues.indexOf(startValue);
        var rightIndex = typeof endValue === 'number' ? d3_array_1.bisectLeft(xValues, endValue) : xValues.indexOf(endValue) + 1;
        var isRightOutOfRange = rightIndex > xValues.length - 1 || rightIndex < 0;
        var isLeftOutOfRange = leftIndex > xValues.length - 1 || leftIndex < 0;
        var startFromScale = xScale(isLeftOutOfRange ? xValues[0] : xValues[leftIndex]);
        var endFromScale = xScale(isRightOutOfRange ? xValues[xValues.length - 1] : xValues[rightIndex]);
        if (startFromScale === undefined || endFromScale === undefined) {
            return null;
        }
        var xStart = chartDimensions.left + startFromScale;
        var width = endFromScale - startFromScale + (isRightOutOfRange || isLeftOutOfRange ? cellWidth : 0);
        var _a = y
            .filter(function (v) { return yValues.includes(v); })
            .reduce(function (acc, current, i) {
            if (i === 0) {
                acc.y = yScale(current) || 0;
            }
            acc.totalHeight += cellHeight;
            return acc;
        }, { y: 0, totalHeight: 0 }), yStart = _a.y, totalHeight = _a.totalHeight;
        return {
            x: xStart,
            y: yStart,
            width: width,
            height: totalHeight,
        };
    };
    var pickDragShape = function (bound) {
        var area = pickDragArea(bound);
        return pickHighlightedArea(area.x, area.y);
    };
    var xLines = [];
    for (var i = 0; i < xValues.length + 1; i++) {
        var x = chartDimensions.left + i * cellWidth;
        var y1 = chartDimensions.top;
        var y2 = cellHeight * pageSize;
        xLines.push({ x1: x, y1: y1, x2: x, y2: y2 });
    }
    var yLines = [];
    for (var i = 0; i < pageSize + 1; i++) {
        var y = i * cellHeight;
        yLines.push({ x1: chartDimensions.left, y1: y, x2: chartDimensions.width + chartDimensions.left, y2: y });
    }
    return {
        config: config,
        heatmapViewModel: {
            gridOrigin: {
                x: chartDimensions.left,
                y: chartDimensions.top,
            },
            gridLines: {
                x: xLines,
                y: yLines,
                stroke: {
                    color: color_library_wrappers_1.stringToRGB(config.grid.stroke.color),
                    width: gridStrokeWidth,
                },
            },
            pageSize: pageSize,
            cells: Object.values(cellMap),
            xValues: textXValues,
            yValues: textYValues,
        },
        pickQuads: pickQuads,
        pickDragArea: pickDragArea,
        pickDragShape: pickDragShape,
        pickHighlightedArea: pickHighlightedArea,
    };
}
exports.shapeViewModel = shapeViewModel;
function getCellKey(x, y) {
    return [String(x), String(y)].join('&_&');
}
function isFilteredValue(filterRanges, value) {
    return filterRanges.some(function (_a) {
        var _b = __read(_a, 2), min = _b[0], max = _b[1];
        if (max !== null && value > min && value < max) {
            return true;
        }
        return max === null && value > min;
    });
}
//# sourceMappingURL=viewmodel.js.map