import { addEventListener } from '../component/event-handler';
var map = new Map();
var createEvent = function (name) { return new Event(name, { bubbles: true }); };
function assign(ta) {
    if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta))
        return;
    var heightOffset = NaN;
    var clientWidth = NaN;
    var cachedHeight = NaN;
    function init() {
        var style = window.getComputedStyle(ta, null);
        if (style.resize === 'vertical') {
            ta.style.resize = 'none';
        }
        else if (style.resize === 'both') {
            ta.style.resize = 'horizontal';
        }
        if (style.boxSizing === 'content-box') {
            heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
        }
        else {
            heightOffset =
                parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
        }
        if (isNaN(heightOffset)) {
            heightOffset = 0;
        }
        update();
    }
    function changeOverflow(value) {
        {
            var width = ta.style.width;
            ta.style.width = '0px';
            ta.offsetWidth;
            ta.style.width = width;
        }
        ta.style.overflowY = value;
    }
    function getParentOverflows(el) {
        var arr = [];
        while (el && el.parentNode && el.parentNode instanceof Element) {
            if (el.parentNode.scrollTop) {
                arr.push({
                    node: el.parentNode,
                    scrollTop: el.parentNode.scrollTop,
                });
            }
            el = el.parentNode;
        }
        return arr;
    }
    function resize() {
        if (ta.scrollHeight === 0) {
            return;
        }
        var overflows = getParentOverflows(ta);
        var docTop = document.documentElement && document.documentElement.scrollTop;
        ta.style.height = '';
        ta.style.height = ta.scrollHeight + heightOffset + 'px';
        clientWidth = ta.clientWidth;
        overflows.forEach(function (el) {
            el.node.scrollTop = el.scrollTop;
        });
        if (docTop) {
            document.documentElement.scrollTop = docTop;
        }
    }
    function update() {
        resize();
        var styleHeight = Math.round(parseFloat(ta.style.height));
        var computed = window.getComputedStyle(ta, null);
        var actualHeight = computed.boxSizing === 'content-box'
            ? Math.round(parseFloat(computed.height))
            : ta.offsetHeight;
        if (actualHeight < styleHeight) {
            if (computed.overflowY === 'hidden') {
                changeOverflow('scroll');
                resize();
                actualHeight =
                    computed.boxSizing === 'content-box'
                        ? Math.round(parseFloat(window.getComputedStyle(ta, null).height))
                        : ta.offsetHeight;
            }
        }
        else {
            if (computed.overflowY !== 'hidden') {
                changeOverflow('hidden');
                resize();
                actualHeight =
                    computed.boxSizing === 'content-box'
                        ? Math.round(parseFloat(window.getComputedStyle(ta, null).height))
                        : ta.offsetHeight;
            }
        }
        if (cachedHeight !== actualHeight) {
            cachedHeight = actualHeight;
            var evt = createEvent('autosize:resized');
            try {
                ta.dispatchEvent(evt);
            }
            catch (err) {
            }
        }
    }
    var pageResize = function () {
        if (ta.clientWidth !== clientWidth) {
            update();
        }
    };
    var eventCancelList = [];
    var destroy = (function (style) {
        eventCancelList.forEach(function (unsubscribe) { return unsubscribe(); });
        eventCancelList.splice(0, eventCancelList.length);
        Object.keys(style).forEach(function (key) {
            ta.style[key] = style[key];
        });
        map.delete(ta);
    }).bind(ta, {
        height: ta.style.height,
        resize: ta.style.resize,
        overflowY: ta.style.overflowY,
        overflowX: ta.style.overflowX,
        wordWrap: ta.style.wordWrap,
    });
    eventCancelList.push(addEventListener(ta, 'autosize:destroy', destroy));
    if ('onpropertychange' in ta && 'oninput' in ta) {
        eventCancelList.push(addEventListener(ta, 'keyup', update));
    }
    eventCancelList.push(addEventListener(window, 'resize', pageResize));
    eventCancelList.push(addEventListener(ta, 'input', update));
    eventCancelList.push(addEventListener(ta, 'autosize:update', update));
    ta.style.overflowX = 'hidden';
    ta.style.wordWrap = 'break-word';
    map.set(ta, {
        destroy: destroy,
        update: update,
    });
    init();
}
function _destroy(ta) {
    var methods = map.get(ta);
    if (methods) {
        methods.destroy();
    }
}
function _update(ta) {
    var methods = map.get(ta);
    if (methods) {
        methods.update();
    }
}
function isNodeList(el) {
    return 'length' in el;
}
export function autosize(el) {
    if (el) {
        Array.prototype.forEach.call(isNodeList(el) ? el : [el], function (x) { return assign(x); });
    }
    return el;
}
export function destroy(el) {
    if (el) {
        Array.prototype.forEach.call(isNodeList(el) ? el : [el], _destroy);
    }
    return el;
}
export function update(el) {
    if (el) {
        Array.prototype.forEach.call(isNodeList(el) ? el : [el], _update);
    }
    return el;
}
