import { __assign, __extends } from "tslib";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Component, createRef } from 'react';
import cx from 'classnames';
import identity from '../utils/identity';
import Pop from '../pop';
import { WindowResizeHandler } from '../utils/component/WindowResizeHandler';
import { getLineHeight } from '../utils/dom/getLineHeight';
import { containsEmoji } from '../utils/unicode/isEmoji';
import { containsCJK } from '../utils/unicode/isCJK';
var WORDBREAK_STYLES = {
    wordBreak: 'break-all',
    overflowWrap: 'break-word',
};
var ClampLines = (function (_super) {
    __extends(ClampLines, _super);
    function ClampLines(props) {
        var _this = _super.call(this, props) || this;
        _this.element = null;
        _this.innerElement = createRef();
        _this.resizeObserver = null;
        _this.containerWidth = NaN;
        _this.handleWindowResize = function () {
            _this.setState({ holdsFullText: false }, _this.clampLines);
        };
        _this.handleContainerResize = function (entries) {
            var _a = entries[0], contentBoxSize = _a.contentBoxSize, contentRect = _a.contentRect;
            var width = NaN;
            if (contentBoxSize) {
                width = Array.isArray(contentBoxSize)
                    ? contentBoxSize[0].inlineSize
                    : contentBoxSize.inlineSize;
            }
            else {
                width = contentRect.width;
            }
            if (!Number.isNaN(_this.containerWidth) && width !== _this.containerWidth) {
                _this.setState({ holdsFullText: false }, _this.clampLines);
            }
            _this.containerWidth = width;
        };
        _this.onContainerRefChange = function (node) {
            _this.element = node;
            _this.observe(node);
        };
        _this.onNoClampContainerRefChange = function (node) {
            _this.observe(node);
        };
        _this.state = {
            holdsFullText: false,
            textSuited: '',
        };
        return _this;
    }
    ClampLines.prototype.componentDidUpdate = function (prevProps) {
        var _this = this;
        if (prevProps.text !== this.props.text ||
            prevProps.mode !== this.props.mode ||
            prevProps.lines !== this.props.lines) {
            this.setState({ holdsFullText: false }, function () {
                _this.clampLines();
            });
        }
    };
    ClampLines.prototype.componentDidMount = function () {
        this.clampLines();
    };
    ClampLines.prototype.componentWillUnmount = function () {
        var observer = this.getResizeObserver();
        if (observer) {
            observer.disconnect();
        }
    };
    ClampLines.prototype.getResizeObserver = function () {
        if (!this.resizeObserver && window.ResizeObserver) {
            this.resizeObserver = new window.ResizeObserver(this.handleContainerResize);
        }
        return this.resizeObserver;
    };
    ClampLines.prototype.observe = function (node) {
        var observer = this.getResizeObserver();
        if (!observer || !this.props.resizable) {
            return;
        }
        this.containerWidth = NaN;
        observer.disconnect();
        if (node) {
            observer.observe(node);
        }
    };
    ClampLines.prototype.clampLines = function () {
        if (!this.innerElement.current || !this.element) {
            return;
        }
        this.props.mode === 'performance'
            ? this._clampLinesFast()
            : this._clampLinesAccurate();
    };
    ClampLines.prototype._clampLinesFast = function () {
        var text = this.props.text;
        var lineHeight = inferContentLineHeight(this.element, text);
        var maxHeight = lineHeight * this.props.lines;
        this.innerElement.current.textContent = text;
        if (this.element.clientHeight <= maxHeight) {
            this.setState({
                textSuited: text,
                holdsFullText: true,
            });
            return;
        }
        var chars = Array.from(text);
        var start = 0;
        var middle = 0;
        var end = chars.length;
        while (start < end) {
            middle = Math.floor((start + end) / 2);
            this.innerElement.current.textContent =
                slice(chars, 0, middle) + this.getEllipsis();
            var height = this.element.clientHeight;
            if (height > maxHeight) {
                end = middle;
            }
            else {
                start = middle + 1;
            }
        }
        var overflowIndex = end - 1;
        var textSuited = slice(chars, 0, overflowIndex) + this.getEllipsis();
        this.innerElement.current.textContent = textSuited;
        this.setState({
            textSuited: textSuited,
            holdsFullText: false,
        });
    };
    ClampLines.prototype._clampLinesAccurate = function () {
        var miniLineHeight = getLineHeight(this.element);
        var text = this.props.text;
        var chars = Array.from(text);
        var lines = this.props.lines;
        var prevIndex = 0;
        var prevStr = chars[prevIndex];
        var textSuited = '';
        this.innerElement.current.textContent = prevStr;
        var prevHeight = this.element.clientHeight;
        var i = 1;
        for (; i < chars.length && lines > 0; i++) {
            var str = prevStr + chars[i];
            this.innerElement.current.textContent = str;
            var height = this.element.clientHeight;
            if (height - prevHeight >= miniLineHeight) {
                lines--;
            }
            if (lines > 0) {
                prevHeight = height;
                prevIndex = i;
                prevStr = str;
            }
            else {
                while (prevIndex) {
                    prevStr = slice(chars, 0, prevIndex--);
                    var str_1 = prevStr + this.getEllipsis();
                    this.innerElement.current.textContent = str_1;
                    if (prevHeight === this.element.clientHeight) {
                        textSuited = str_1;
                        break;
                    }
                }
            }
        }
        if (lines > 0) {
            this.setState({
                textSuited: text,
                holdsFullText: true,
            });
        }
        else {
            this.setState({
                textSuited: textSuited,
                holdsFullText: false,
            });
        }
    };
    ClampLines.prototype.getEllipsis = function () {
        return !this.state.holdsFullText ? this.props.ellipsis : '';
    };
    ClampLines.prototype.renderResizable = function () {
        if (this.props.resizable && !window.ResizeObserver) {
            return _jsx(WindowResizeHandler, { onResize: this.handleWindowResize }, void 0);
        }
        return null;
    };
    ClampLines.prototype.renderClampedText = function () {
        var className = this.props.className;
        var classString = cx('zent-clamp-lines', className);
        return (_jsxs("div", __assign({ className: classString, style: WORDBREAK_STYLES, "data-zv": 'v10.0.12' }, { children: [_jsxs("div", __assign({ ref: this.onContainerRefChange, "data-zv": 'v10.0.12' }, { children: [_jsx("span", __assign({ ref: this.innerElement, "data-zv": 'v10.0.12' }, { children: this.state.textSuited }), void 0), this.props.extra] }), void 0), this.renderResizable()] }), void 0));
    };
    ClampLines.prototype.render = function () {
        var _a = this.props, text = _a.text, className = _a.className, showPop = _a.showPop, popWidth = _a.popWidth, trigger = _a.trigger, renderPop = _a.renderPop;
        if (!text) {
            return null;
        }
        if (this.state.holdsFullText) {
            return (_jsxs("div", __assign({ ref: this.onNoClampContainerRefChange, className: className, style: WORDBREAK_STYLES, "data-zv": 'v10.0.12' }, { children: [text, this.renderResizable()] }), void 0));
        }
        if (showPop) {
            return (_jsx(Pop, __assign({ trigger: trigger, content: _jsx("div", __assign({ style: __assign({ maxWidth: popWidth }, WORDBREAK_STYLES), "data-zv": 'v10.0.12' }, { children: renderPop(text) }), void 0) }, { children: this.renderClampedText() }), void 0));
        }
        return this.renderClampedText();
    };
    ClampLines.defaultProps = {
        className: '',
        lines: 2,
        ellipsis: '...',
        showPop: true,
        popWidth: 250,
        trigger: 'hover',
        renderPop: identity,
        resizable: false,
        mode: 'performance',
        extra: null,
    };
    return ClampLines;
}(Component));
export { ClampLines };
function slice(chars, start, end) {
    return chars.slice(start, end).join('');
}
function inferContentLineHeight(node, str) {
    var emojiHeight = containsEmoji(str)
        ? getLineHeight(node, '🇨🇳')
        : -Infinity;
    var cjkHeight = containsCJK(str) ? getLineHeight(node, '世界') : -Infinity;
    var asciiHeight = getLineHeight(node);
    return Math.max(emojiHeight, cjkHeight, asciiHeight);
}
export default ClampLines;
