"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_STYLE = void 0;
const addListener_1 = require("../../../../../client/addListener");
const classnames_1 = require("../../../../../client/classnames");
const mergeStyle_1 = require("../../../../../client/component/mergeStyle");
const element_1 = require("../../../../../client/element");
const custom_1 = require("../../../../../client/event/custom");
const resize_1 = require("../../../../../client/event/resize");
const parentElement_1 = require("../../../../../client/platform/web/parentElement");
const simulation_1 = require("../../../../../client/simulation");
const theme_1 = require("../../../../../client/theme");
const f_1 = require("../../../../core/relation/Clamp/f");
const Component_1 = __importDefault(require("../../Div/Component"));
const Component_2 = __importStar(require("../Drawer/Component"));
exports.DEFAULT_STYLE = {
    position: 'absolute',
    right: '0',
    top: '0',
    width: '0',
    height: '0',
};
class Cabinet extends element_1.Element {
    constructor($props, $system) {
        super($props, $system);
        this._drawer = {};
        this._drawer_component = {};
        this._drawer_node = {};
        this._drawer_active = new Set();
        this._drawer_y = {};
        this._component_frame = {};
        this._width = 0;
        this._height = 0;
        this._z_index = 1;
        this._dy = 0;
        this._tick = () => {
            for (const drawer_id in this._drawer_node) {
                const { y } = this._drawer_node[drawer_id];
                const drawer = this._drawer_component[drawer_id];
                drawer.setProp('y', y);
            }
        };
        this._force = (alpha) => {
            const entries = Object.entries(this._drawer_node);
            const n = entries.length;
            for (let i = 0; i < n; i++) {
                const a_entry = entries[i];
                const [a_id, a] = a_entry;
                const ay = a.y;
                const ah = a.height;
                for (let j = i + 1; j < n; j++) {
                    const b_entry = entries[j];
                    const [b_id, b] = b_entry;
                    const by = b.y;
                    const bh = b.height;
                    let l = 1;
                    let s = 1;
                    if (ay + ah <= by) {
                        l = by - ay - ah;
                        s = -1;
                    }
                    else if (ay <= by) {
                        const l0 = by - ay;
                        const l1 = ay + ah - by;
                        l = Math.min(l0, l1);
                        s = l0 < l1 ? 1 : -1;
                    }
                    else if (by + bh <= ay) {
                        l = ay - by - bh;
                    }
                    else if (by <= ay) {
                        l = by + bh - ay;
                        s = 3;
                    }
                    else {
                        s = -1;
                    }
                    l = Math.max(l, 3);
                    const k = (s * (alpha * 150)) / l;
                    if (!this._drawer_inactivating.has(a_id)) {
                        a.vy += k;
                    }
                    if (!this._drawer_inactivating.has(b_id)) {
                        b.vy -= k;
                    }
                }
            }
            for (const drawer_id in this._drawer_node) {
                if (!this._drawer_inactivating.has(drawer_id)) {
                    const node = this._drawer_node[drawer_id];
                    const { y, height } = node;
                    const dy = y + height / 2 - this._height / 2 + this._dy;
                    node.vy -= (dy * alpha) / 10;
                }
            }
        };
        this._on_context_resize = 
        // debounce(
        () => {
            // console.log('Cabinet', '_on_context_resize')
            const { $width, $height } = this.$context;
            this._on_resize($width, $height);
        };
        // , 300)
        this._on_drawer_drag_start = (drawerId, y) => {
            // console.log('Cabinet', '_on_drawer_drag_start', y)
            const node = this._drawer_node[drawerId];
            if (node) {
                node.hy = y - node.y;
                node.fy = node.y;
            }
        };
        this._on_drawer_dragged = (drawerId, y) => {
            // console.log('Cabinet', '_on_drawer_dragged', y)
            const node = this._drawer_node[drawerId];
            if (node) {
                node.fy = y - node.hy;
                node.y = node.fy;
                this._startSimulation();
            }
        };
        this._on_drawer_drag_end = (drawerId) => {
            // console.log('Cabinet', '_on_drawer_drag_end')
            // this._start_simulation()
            const node = this._drawer_node[drawerId];
            if (node) {
                node.hy = 0;
                if (!this._drawer_active.has(drawerId)) {
                    node.fy = undefined;
                }
            }
        };
        this.addDrawers = (drawers) => {
            for (const drawerId in drawers) {
                const drawer = drawers[drawerId];
                this.addDrawer(drawerId, drawer);
            }
        };
        this._drawer_inactivating = new Set();
        this.addDrawer = (drawerId, cabinetDrawer) => {
            // console.log('Cabinet', 'addDrawer')
            // const { $width } = this.$context
            const { style = {}, hidden } = this.$props;
            let { component, icon, title, active, state = {}, width = 0, height = Component_2.KNOB_HEIGHT, shortcut, } = cabinetDrawer;
            const { y = 0 } = state;
            const { color = 'currentColor', backgroundColor = theme_1.COLOR_NONE } = style;
            this._drawer[drawerId] = cabinetDrawer;
            const drawer_component = new Component_2.default({
                className: 'cabinet-drawer',
                component,
                active,
                icon,
                title,
                y,
                width,
                height,
                hidden,
                style: {
                    backgroundColor,
                    color,
                },
                shortcut,
            }, this.$system);
            drawer_component.addEventListener((0, custom_1.makeCustomListener)('active', () => {
                // console.log('Cabinet', '_on_drawer_active')
                // increase z-index of this drawer on active
                this._incDrawerZIndex(drawerId);
                this._memSetActive(drawerId, true);
                this._drawer_y[drawerId] = this._drawer_node[drawerId].y;
                const drawer = this._drawer[drawerId];
                const node = this._drawer_node[drawerId];
                const { component } = drawer;
                if (component) {
                    this._fixed_drawer_node.add(drawerId);
                    node.fy = node.y;
                    node.height = drawer.height;
                    this._startSimulation();
                }
                this.dispatchEvent('draweractive', { drawerId });
            }));
            drawer_component.addEventListener((0, custom_1.makeCustomListener)('activated', () => {
                // console.log('Cabinet', '_on_drawer_activated')
            }));
            drawer_component.addEventListener((0, custom_1.makeCustomListener)('inactive', () => {
                // console.log('Cabinet', '_on_drawer_inactive')
                const { api: { window: { setTimeout }, }, } = this.$system;
                this._memSetActive(drawerId, false);
                const drawer = this._drawer[drawerId];
                const { component } = drawer;
                if (component) {
                    const y = this._drawer_y[drawerId] ?? this._height / 2;
                    this._drawer_inactivating.add(drawerId);
                    setTimeout(() => {
                        this._drawer_inactivating.delete(drawerId);
                        this._startSimulation(0.05);
                    }, 200);
                    this._addDrawerNode(drawerId, y);
                    this._startSimulation(0.05);
                }
                this.dispatchEvent('drawerinactive', { drawerId });
            }));
            drawer_component.addEventListener((0, custom_1.makeCustomListener)('dragstart', ({ y }) => {
                // increase this drawer zIndex on dragstart
                this._incDrawerZIndex(drawerId);
                this._drawer_y[drawerId] = y;
                this._on_drawer_drag_start(drawerId, y);
            }));
            drawer_component.addEventListener((0, custom_1.makeCustomListener)('dragged', ({ y }) => {
                this._drawer_y[drawerId] = y;
                this._on_drawer_dragged(drawerId, y);
            }));
            drawer_component.addEventListener((0, custom_1.makeCustomListener)('dragend', () => {
                this._on_drawer_drag_end(drawerId);
            }));
            this._drawer_component[drawerId] = drawer_component;
            this._cabinet.appendChild(drawer_component);
            const { frame } = drawer_component;
            this._component_frame[drawerId] = frame;
            if (component) {
                frame.appendChild(component);
            }
            if (!active) {
                this._addDrawerNode(drawerId, y);
            }
        };
        this._addDrawerNode = (drawerId, y) => {
            const x = 0;
            const r = Component_2.KNOB_HEIGHT / 2;
            const node = {
                _x: x,
                _y: y,
                ax: 0,
                ay: 0,
                x,
                y,
                fx: undefined,
                fy: undefined,
                shape: 'rect',
                r,
                width: 0,
                height: Component_2.KNOB_HEIGHT,
                vx: 0,
                vy: 0,
                hx: 0,
                hy: 0,
            };
            this._drawer_node[drawerId] = node;
        };
        this._removeDrawerNode = (drawerId) => {
            delete this._drawer_node[drawerId];
        };
        this._fixed_drawer_node = new Set();
        this._startSimulation = (alpha = 0.1) => {
            // console.log('Cabinet', '_startSimulation')
            this._simulation.alpha(alpha);
            this._simulation.start();
        };
        this._incDrawerZIndex = (drawerId) => {
            // increase zIndex of this drawer
            const drawer_component = this._drawer_component[drawerId];
            drawer_component.drawer.$element.style.zIndex = `${this._z_index}`;
            this._z_index++;
        };
        this._on_resize = ($width, $height) => {
            // console.log('Cabinet', '_on_resize', $width, $height)
            const dh = $height - this._height;
            const dy = dh / 2;
            this._width = $width;
            this._height = $height;
            for (const drawer_id in this._drawer_component) {
                const y = this._drawer_y[drawer_id] ?? 0;
                const drawer_component = this._drawer_component[drawer_id];
                const _y = (0, f_1.clamp)(y + dy, 0, $height - Component_2.KNOB_HEIGHT + 1);
                drawer_component.setProp('y', _y);
                const node = this._drawer_node[drawer_id];
                if (node) {
                    node.y += dy;
                }
            }
            this._tick();
        };
        this._hidden = false;
        this.show_tooltips = () => {
            for (const drawer_id in this._drawer_component) {
                const drawer = this._drawer_component[drawer_id];
                if (drawer.$props.shortcut) {
                    drawer.show_tooltip();
                }
            }
        };
        this.hide_tooltips = () => {
            for (const drawer_id in this._drawer_component) {
                const drawer = this._drawer_component[drawer_id];
                drawer.hide_tooltip();
            }
        };
        const { className, style = {}, dy = 0 } = $props;
        this._dy = 0;
        const cabinet = new Component_1.default({
            className: (0, classnames_1.classnames)('cabinet', className),
            style: {
                ...exports.DEFAULT_STYLE,
                ...style,
            },
        }, this.$system);
        this._cabinet = cabinet;
        this._simulation = new simulation_1.Simulation({
            n: 6,
            force: this._force,
        });
        this._simulation.nodes(this._drawer_node);
        this._simulation.addListener('tick', this._tick);
        const $element = (0, parentElement_1.parentElement)($system);
        this.$element = $element;
        this.$unbundled = false;
        this.$primitive = true;
        this.setSubComponents({
            cabinet,
        });
        this.registerRoot(cabinet);
    }
    _memSetActive(drawerId, active) {
        if (active) {
            this._drawer_active.add(drawerId);
        }
        else {
            this._drawer_active.delete(drawerId);
        }
    }
    onPropChanged(prop, current) {
        if (prop === 'className') {
            this._cabinet.setProp('className', current);
        }
        else if (prop === 'style') {
            this._cabinet.setProp('style', {
                ...exports.DEFAULT_STYLE,
                ...current,
            });
            const { style = {} } = this.$props;
            const { color = 'currentColor', backgroundColor = theme_1.COLOR_NONE } = style;
            for (const drawerId in this._component_frame) {
                const drawer = this._drawer_component[drawerId];
                (0, mergeStyle_1.mergePropStyle)(drawer, {
                    color,
                    backgroundColor,
                });
            }
        }
        if (prop === 'hidden') {
            if (this._hidden && !current) {
                this.show(false);
            }
            else if (!this._hidden && current) {
                this.hide(false);
            }
        }
        else if (prop === 'dy') {
            this._dy = current ?? 0;
            this._startSimulation();
        }
    }
    setActive(drawerId, active) {
        const drawer = this._drawer_component[drawerId];
        drawer.setProp('active', active);
    }
    isActive(drawerId) {
        return this._drawer_active.has(drawerId);
    }
    getDrawer(drawerId) {
        return this._drawer_component[drawerId];
    }
    setDrawerProp(drawerId, name, value) {
        const drawer_component = this.getDrawer(drawerId);
        drawer_component.setProp(name, value);
    }
    removeDrawer(drawerId) {
        const drawer = this._drawer_component[drawerId];
        this._cabinet.removeChild(drawer);
        delete this._drawer[drawerId];
        delete this._drawer_component[drawerId];
        delete this._drawer_node[drawerId];
        delete this._drawer_y[drawerId];
        delete this._drawer_active[drawerId];
    }
    getDrawers() {
        return this._drawer_component;
    }
    onMount() {
        // console.log('Cabinet', 'onMount')
        const { $width, $height } = this.$context;
        this._width = $width;
        this._height = $height;
        this._context_unlisten = (0, addListener_1.addListeners)(this.$context, [
            (0, resize_1.makeResizeListener)(this._on_context_resize),
        ]);
        this._startSimulation();
    }
    onUnmount() {
        this._simulation.stop();
        this._context_unlisten();
    }
    show(animate) {
        this._hidden = false;
        for (const drawer_id in this._drawer_component) {
            const drawer = this._drawer_component[drawer_id];
            drawer.show(animate);
        }
    }
    hide(animate) {
        this._hidden = true;
        for (const drawer_id in this._drawer_component) {
            const drawer = this._drawer_component[drawer_id];
            drawer.hide(animate);
        }
    }
}
exports.default = Cabinet;
//# sourceMappingURL=Component.js.map