import './util.css';
import './dialog.css';
import utils from 'somes';
import { ViewController } from './ctr';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { EventNoticer } from 'somes/event';
import { List } from 'somes/event';
var DEFAULT_SCALE = 1;
export function getDefaultId(obj) {
    utils.assert(obj);
    if (!obj.hasOwnProperty('__default_id')) {
        obj.__default_id = String(utils.getId());
    }
    return String(obj.__default_id);
}
export class DialogStack {
    constructor(panel = document.body) {
        this._dialogStack = new List();
        this._IDs = new Map();
        utils.assert(panel, 'Panel cannot be empty');
        this._panel = panel;
    }
    get preventCover() {
        var _a, _b, _c;
        return ((_c = (_b = (_a = this._dialogStack) === null || _a === void 0 ? void 0 : _a.last) === null || _b === void 0 ? void 0 : _b.value) === null || _c === void 0 ? void 0 : _c.preventCover) || false;
    }
    async show(D, opts, animate = true, act) {
        var id = (opts === null || opts === void 0 ? void 0 : opts.id) ? String(opts.id) : getDefaultId(D);
        utils.assert(!this._IDs.has(id), `Dialog already exists, "${id}"`);
        var div = document.createElement('div');
        this._panel.appendChild(div);
        var instance = await new Promise(r => ReactDom.render(React.createElement(D, Object.assign({}, opts, { __activity: act, __panel: div })), div, function () { r(this); }));
        var prev = this._dialogStack.last;
        if (prev) {
            prev.value.hide();
        }
        var item = this._dialogStack.push(instance);
        instance.onClose.on(({ data }) => {
            this._dialogStack.del(item);
            this._IDs.delete(id);
            utils.sleep(200).then(() => {
                var last = this._dialogStack.last;
                if (last) {
                    last.value.show(data.animate);
                }
            });
        });
        this._IDs.set(id, item);
        instance.show(animate);
        return instance;
    }
    close(id, animate = true) {
        var _id = typeof id == 'string' ? String(id) : getDefaultId(id);
        var item = this._IDs.get(_id);
        if (item) {
            item.value.close(animate);
        }
        else {
            console.warn(`Dialog no exists, "${id}"`);
        }
    }
    closeAll() {
        var item = this._dialogStack.first;
        while (item) {
            var next = item.next;
            item.value.close(false);
            item = next;
        }
    }
}
var _globaDialogStack;
export class Dialog extends ViewController {
    constructor() {
        super(...arguments);
        this.onClose = new EventNoticer('Close', this);
        this.__activity = this.props.__activity;
        this.__panel = this.props.__panel;
        this._maskClick = (event) => {
            if (event.target === this.refs.root) {
                this.triggerMaskClick();
            }
        };
    }
    get preventCover() {
        return true;
    }
    get activity() {
        return this.__activity;
    }
    triggerMaskClick() {
    }
    render() {
        var style = {};
        if (this.noMask) {
            style.background = 'none';
        }
        return (React.createElement("div", { ref: "root", className: "dialog", style: style, onClick: this._maskClick },
            React.createElement("div", { className: "core", ref: "core" }, this.renderBody())));
    }
    async _enableAnimate(animate) {
        if (!this.refs.root)
            return;
        if (animate) {
            this.refs.root.style.transitionDuration = '300ms';
            this.refs.core.style.transitionDuration = '300ms';
        }
        else {
            this.refs.root.style.transitionDuration = '0ms';
            this.refs.core.style.transitionDuration = '0ms';
        }
        this.refs.root.style.display = 'flex';
        await utils.sleep(30);
    }
    async hide(animate = true) {
        await this._enableAnimate(animate);
        if (!this.refs.root)
            return;
        if (!this.noMask)
            this.refs.root.style.background = 'rgba(0,0,0,0.01)';
        this.refs.core.style.opacity = '0';
        this.refs.core.style.transform = 'scale(0.3)';
        await utils.sleep(300);
        if (!this.refs.root)
            return;
        this.refs.root.style.display = 'none';
    }
    async show(animate = true) {
        await this._enableAnimate(animate);
        if (!this.refs.root)
            return;
        if (!this.noMask)
            this.refs.root.style.background = 'rgba(0,0,0,0.75)';
        this.refs.core.style.opacity = '1';
        this.refs.core.style.transform = 'scale(1)';
        await utils.sleep(300);
    }
    async close(animate = true) {
        if (this.refs.root) {
            this.onClose.trigger({ animate });
            await this.hide(animate);
        }
        if (this.__panel) {
            ReactDom.unmountComponentAtNode(this.__panel);
            this.__panel.parentNode.removeChild(this.__panel);
            this.__panel = undefined;
        }
    }
    get noMask() {
        return false;
    }
    static get globaDialogStack() {
        if (!_globaDialogStack) {
            _globaDialogStack = new DialogStack();
        }
        return _globaDialogStack;
    }
}
export default class DefaultDialog extends Dialog {
    triggerMounted() {
        if (this.refs.prompt) {
            var props = this.props;
            var input = this.refs.prompt;
            input.value = typeof props.prompt == 'string' ? props.prompt : '';
        }
        super.triggerMounted();
    }
    _handleClick_1(cb) {
        var root = this.refs.root;
        if (root) {
            cb(this);
            this.close();
        }
    }
    get noMask() {
        return !!this.props.noMask;
    }
    renderButtons() {
        var buttons = this.props.buttons || { '@确定': (e) => { } };
        var r = [];
        for (let i in buttons) {
            var t = i[0] == '@' ? i.substr(1) : i;
            var cls = i[0] == '@' ? 'ok' : '';
            r.push(React.createElement("div", { key: i, className: cls, onClick: () => this._handleClick_1(buttons[i]) }, t));
        }
        return r;
    }
    renderBody() {
        var props = this.props;
        return (React.createElement("div", { className: "default", style: { transform: `scale(${DefaultDialog.scale})` } },
            React.createElement("div", { className: "a" }, props.title || ''),
            props.prompt ?
                React.createElement("div", { className: "b" },
                    React.createElement("div", null, props.text),
                    (() => {
                        var Input = props.prompt.input;
                        var type = props.prompt.type || 'text';
                        var placeholder = props.prompt.placeholder || '';
                        var inputProps = {
                            ref: 'prompt',
                            placeholder: placeholder,
                            style: {
                                border: 'solid 0.015rem #ccc',
                                width: '90%',
                                marginTop: '0.1rem',
                                height: '0.5rem',
                                padding: '0 2px',
                            },
                        };
                        return (Input ?
                            React.createElement(Input, Object.assign({}, inputProps, { value: props.prompt.value, type: type, initFocus: true })) :
                            React.createElement("input", Object.assign({}, inputProps, { defaultValue: props.prompt.value, type: type })));
                    })()) :
                React.createElement("div", { className: "b" }, props.text || ''),
            React.createElement("div", { className: "btns" }, this.renderButtons())));
    }
    static setScale(scale) {
        DEFAULT_SCALE = Math.max(1, Math.min(4, scale));
    }
    static get scale() {
        return DEFAULT_SCALE;
    }
    static show(opts, stack) {
        return (stack || Dialog.globaDialogStack).show(this, Object.assign({ id: utils.getId() }, opts));
    }
    static alert(In, cb, stack) {
        var _cb = cb || function () { };
        var o = typeof In == 'string' ? { text: In, title: '', id: '' } : In;
        var { text, title, id } = o;
        return this.show({
            id, title, text,
            buttons: {
                '@确定': () => { _cb(); },
            }
        }, stack);
    }
    static confirm(In, cb, stack) {
        var _cb = cb || function () { };
        var o = typeof In == 'string' ? { text: In, title: '', id: '' } : In;
        var { text, title, id } = o;
        return this.show({ id, title, text, buttons: {
                '取消': () => _cb(false),
                '@确定': () => _cb(true),
            } }, stack);
    }
    static prompt(In, cb, stack) {
        var _cb = cb || function () { };
        var o = typeof In == 'string' ? { text: In, title: '', value: '', type: 'text', id: '' } : In;
        var { text, title, value, type, input, placeholder, id } = o;
        return this.show({ id, title, text, buttons: {
                '取消': e => _cb(e.refs.prompt.value, false),
                '@确定': e => _cb(e.refs.prompt.value, true),
            }, prompt: { value, type, input, placeholder } }, stack);
    }
}
export function show(opts, stack) {
    return DefaultDialog.show(opts, stack);
}
export function alert(In, cb, stack) {
    return DefaultDialog.alert(In, cb, stack);
}
export function confirm(In, cb, stack) {
    return DefaultDialog.confirm(In, cb, stack);
}
export function prompt(In, cb, stack) {
    return DefaultDialog.prompt(In, cb, stack);
}
