import { __spreadArray } from "tslib";
import { create as d3Create, select as d3Select } from 'd3-selection';
import { resolveCSSVariables } from '../../utilities/index';
export function toImage(chartContainer, opts) {
    if (opts === void 0) { opts = {}; }
    return new Promise(function (resolve, reject) {
        if (!chartContainer) {
            return reject(new Error('Chart container is not defined'));
        }
        try {
            var background = typeof opts.background === 'string' ? resolveCSSVariables(chartContainer, opts.background) : 'transparent';
            var svg = toSVG(chartContainer, background);
            var svgData = new XMLSerializer().serializeToString(svg.node);
            var svgDataUrl = 'data:image/svg+xml;base64,' + btoa(unescapePonyfill(encodeURIComponent(svgData)));
            svgToPng(svgDataUrl, {
                width: opts.width || svg.width,
                height: opts.height || svg.height,
                scale: opts.scale,
            })
                .then(resolve)
                .catch(reject);
        }
        catch (err) {
            return reject(err);
        }
    });
}
var SVG_STYLE_PROPERTIES = ['display', 'fill', 'fill-opacity', 'opacity', 'stroke', 'stroke-width', 'transform'];
var SVG_TEXT_STYLE_PROPERTIES = ['font-family', 'font-size', 'font-weight', 'text-anchor'];
function toSVG(chartContainer, background) {
    var svg = chartContainer.querySelector('svg');
    if (!svg) {
        throw new Error('SVG not found');
    }
    var clonedSvg = d3Select(svg.cloneNode(true))
        .attr('width', null)
        .attr('height', null)
        .attr('viewBox', null);
    var svgElements = svg.getElementsByTagName('*');
    var clonedSvgElements = clonedSvg.node().getElementsByTagName('*');
    for (var i = 0; i < svgElements.length; i++) {
        if (svgElements[i].tagName.toLowerCase() === 'text') {
            copyStyle(__spreadArray(__spreadArray([], SVG_STYLE_PROPERTIES, true), SVG_TEXT_STYLE_PROPERTIES, true), svgElements[i], clonedSvgElements[i]);
        }
        else {
            copyStyle(SVG_STYLE_PROPERTIES, svgElements[i], clonedSvgElements[i]);
        }
    }
    var _a = svg.getBoundingClientRect(), svgWidth = _a.width, svgHeight = _a.height;
    var legendGroup = cloneLegendsToSVG(chartContainer, svgWidth, svgHeight);
    var w1 = Math.max(svgWidth, legendGroup.width);
    var h1 = svgHeight + legendGroup.height;
    if (legendGroup.node) {
        clonedSvg.append(function () { return legendGroup.node; });
    }
    clonedSvg
        .insert('rect', ':first-child')
        .attr('x', 0)
        .attr('y', 0)
        .attr('width', w1)
        .attr('height', h1)
        .attr('fill', background);
    clonedSvg.attr('width', w1).attr('height', h1).attr('viewBox', "0 0 ".concat(w1, " ").concat(h1));
    return {
        node: clonedSvg.node(),
        width: w1,
        height: h1,
    };
}
var LEGEND_RECT_STYLE_PROPERTIES_MAP = {
    'background-color': 'fill',
    'border-color': 'stroke',
};
var LEGEND_TEXT_STYLE_PROPERTIES_MAP = {
    color: 'fill',
    'font-family': 'font-family',
    'font-size': 'font-size',
    'font-weight': 'font-weight',
    opacity: 'opacity',
};
function cloneLegendsToSVG(chartContainer, svgWidth, svgHeight) {
    var legendButtons = chartContainer.querySelectorAll("\n    button[class^=\"legend-\"],\n    [class^=\"legendContainer-\"] div[class^=\"overflowIndicationTextStyle-\"],\n    [class^=\"legendsContainer-\"] div[class^=\"overflowIndicationTextStyle-\"]\n  ");
    if (legendButtons.length === 0) {
        return {
            node: null,
            width: 0,
            height: 0,
        };
    }
    var legendGroup = d3Create('svg:g');
    var legendX = 0;
    var legendY = 8;
    var legendLine = [];
    var legendLines = [];
    var legendLineWidths = [];
    var _loop_1 = function (i) {
        var legendWidth = legendButtons[i].getBoundingClientRect().width;
        var legendItem = legendGroup.append('g');
        legendLine.push(legendItem);
        if (legendX + legendWidth > svgWidth && legendLine.length > 1) {
            legendLine.pop();
            legendLines.push(legendLine);
            legendLineWidths.push(legendX);
            legendLine = [legendItem];
            legendX = 0;
            legendY += 32;
        }
        var legendText;
        var textOffset = 0;
        if (legendButtons[i].tagName.toLowerCase() === 'button') {
            var legendRect_1 = legendButtons[i].querySelector('[class^="rect"]');
            legendText = legendButtons[i].querySelector('[class^="text"]');
            legendItem
                .append('rect')
                .attr('x', legendX + 8)
                .attr('y', svgHeight + legendY + 8)
                .attr('width', 12)
                .attr('height', 12)
                .attr('stroke-width', 1)
                .call(function (selection) { return copyStyle(LEGEND_RECT_STYLE_PROPERTIES_MAP, legendRect_1, selection.node()); });
            textOffset = 28;
        }
        else {
            legendText = legendButtons[i];
            textOffset = 8;
        }
        legendItem
            .append('text')
            .attr('x', legendX + textOffset)
            .attr('y', svgHeight + legendY + 8)
            .attr('dominant-baseline', 'hanging')
            .text(legendText.textContent)
            .call(function (selection) { return copyStyle(LEGEND_TEXT_STYLE_PROPERTIES_MAP, legendText, selection.node()); });
        legendX += legendWidth;
    };
    for (var i = 0; i < legendButtons.length; i++) {
        _loop_1(i);
    }
    legendLines.push(legendLine);
    legendLineWidths.push(legendX);
    legendY += 32;
    var centerLegends = true;
    if (centerLegends) {
        legendLines.forEach(function (ln, idx) {
            var offsetX = Math.max((svgWidth - legendLineWidths[idx]) / 2, 0);
            ln.forEach(function (item) {
                item.attr('transform', "translate(".concat(offsetX, ", 0)"));
            });
        });
    }
    return {
        node: legendGroup.node(),
        width: Math.max.apply(Math, legendLineWidths),
        height: legendY,
    };
}
function svgToPng(svgDataUrl, opts) {
    if (opts === void 0) { opts = {}; }
    return new Promise(function (resolve, reject) {
        var scale = opts.scale || 1;
        var w0 = opts.width || 300;
        var h0 = opts.height || 150;
        var w1 = scale * w0;
        var h1 = scale * h0;
        var canvas = document.createElement('canvas');
        var img = new Image();
        canvas.width = w1;
        canvas.height = h1;
        img.onload = function () {
            var ctx = canvas.getContext('2d');
            if (!ctx) {
                return reject(new Error('Canvas context is null'));
            }
            ctx.clearRect(0, 0, w1, h1);
            ctx.drawImage(img, 0, 0, w1, h1);
            var imgData = canvas.toDataURL('image/png');
            resolve(imgData);
        };
        img.onerror = function (err) {
            reject(err);
        };
        img.src = svgDataUrl;
    });
}
var hex2 = /^[\da-f]{2}$/i;
var hex4 = /^[\da-f]{4}$/i;
/**
 * A ponyfill for the deprecated `unescape` method, taken from the `core-js` library.
 *
 * Source: {@link https://github.com/zloirock/core-js/blob/167136f479d3b8519953f2e4c534ecdd1031d3cf/packages/core-js/modules/es.unescape.js core-js/packages/core-js/modules/es.unescape.js}
 */
function unescapePonyfill(str) {
    var result = '';
    var length = str.length;
    var index = 0;
    var chr;
    var part;
    while (index < length) {
        chr = str.charAt(index++);
        if (chr === '%') {
            if (str.charAt(index) === 'u') {
                part = str.slice(index + 1, index + 5);
                if (hex4.exec(part)) {
                    result += String.fromCharCode(parseInt(part, 16));
                    index += 5;
                    continue;
                }
            }
            else {
                part = str.slice(index, index + 2);
                if (hex2.exec(part)) {
                    result += String.fromCharCode(parseInt(part, 16));
                    index += 2;
                    continue;
                }
            }
        }
        result += chr;
    }
    return result;
}
function copyStyle(properties, fromEl, toEl) {
    var styles = getComputedStyle(fromEl);
    if (Array.isArray(properties)) {
        properties.forEach(function (prop) {
            d3Select(toEl).style(prop, styles.getPropertyValue(prop));
        });
    }
    else {
        Object.entries(properties).forEach(function (_a) {
            var fromProp = _a[0], toProp = _a[1];
            d3Select(toEl).style(toProp, styles.getPropertyValue(fromProp));
        });
    }
}
//# sourceMappingURL=imageExporter.js.map