// /AIWK_COMMON/win/aiwk_win.js
// AIWK v102-stage4.9-ext4-store-resize-noise-fix
(function () {
    "use strict";

    const AIWK = window.AIWK;
    const wins = {};
    let topZ = 2147483001;
    const LAYOUT_KEY = "win_open_layout";
    const STATE_KEY = "win_all_state";
    const RESTORE_BUSY_KEY = "win_restore_busy";
    let createSeq = 0;
    let globalCommandSeq = 0;
    let latestGlobalCommand = null;
    let tickTimer = null;

    function reportError(err, context) {
        if (AIWK.error && typeof AIWK.error.report === "function") {
            return AIWK.error.report(err, context || {});
        }
        try { console.error("AIWK win error", context || {}, err); } catch (e) {}
    }

    function ensureStore(context) {
        if (!AIWK.store || typeof AIWK.store.get !== "function" || typeof AIWK.store.set !== "function") {
            const err = new Error("AIWK.store is missing. aiwk_store.js가 로드되지 않았거나 로드 순서가 잘못되었습니다.");
            reportError(err, Object.assign({
                file: "AIWK_COMMON/win/aiwk_win.js",
                cause: "AIWK.store undefined",
                guide: "해결: chart/index.php에서 aiwk_core.js 다음, aiwk_win.js보다 먼저 aiwk_store.js가 로드되는지 확인하고 브라우저 캐시를 새로고침하십시오."
            }, context || {}));
            throw err;
        }
        return AIWK.store;
    }

    function storeGet(key, fallbackValue, context) {
        return ensureStore(context).get(key, fallbackValue);
    }

    function storeSet(key, value, context) {
        return ensureStore(context).set(key, value);
    }

    const AUTO_RESTORE_EXCLUDE_IDS = {
        "test-launcher-win": 1,
        "hello-win": 1,
        "registry-win": 1,
        "zone-registry-win": 1,
        "wss-test-win": 1,
        "bus-test-win": 1,
        "nr-test-win": 1,
        "site-profile-win": 1,
        "js-runner-win": 1
    };
    const AUTO_RESTORE_EXCLUDE_MODULES = {
        "dev.test_launcher": 1,
        "sample.hello": 1,
        "win.registry": 1,
        "zone.registry": 1,
        "comm.wss_test": 1,
        "comm.bus_test": 1,
        "comm.nr_test": 1,
        "site.profile_registry": 1,
        "dev.js_runner": 1
    };

    function isAutoRestoreExcluded(row) {
        if (!row) { return false; }
        const id = String(row.id || row.win_id || "");
        const module = String(row.module || "");
        return !!(AUTO_RESTORE_EXCLUDE_IDS[id] || AUTO_RESTORE_EXCLUDE_MODULES[module]);
    }

    function cleanupAutoRestoreList() {
        const before = savedList();
        const after = before.filter(function (row) { return row && row.id && row.module && !isAutoRestoreExcluded(row); });
        if (after.length !== before.length) {
            saveList(after);
            try {
                storeSet("win_restore_cleanup_v047", {
                    at: new Date().toISOString(),
                    before: before.length,
                    after: after.length,
                    removed: before.filter(function (row) { return isAutoRestoreExcluded(row); }).map(function (row) { return { id: row.id || row.win_id || "", module: row.module || "" }; })
                });
            } catch (err) {}
        }
        return after;
    }

    function fallbackRect() {
        return {
            x: 80,
            y: 90,
            w: 420,
            h: 260,
            collapsed: false
        };
    }

    function resolveRect(id, cfgRect) {
        const saved = storeGet("win_rect_" + id, null, {fn:"resolveRect", win_id:id});
        if (saved && typeof saved === "object") {
            return Object.assign({}, fallbackRect(), saved);
        }
        return Object.assign({}, fallbackRect(), cfgRect || {});
    }



    function savedList() {
        const list = storeGet(LAYOUT_KEY, [], {fn:"savedList"});
        return Array.isArray(list) ? list : [];
    }

    function saveList(list) {
        storeSet(LAYOUT_KEY, (list || []).filter(function (row) { return row && row.id && row.module; }), {fn:"saveList"});
    }

    function normalizeWinState(cfg) {
        if (AIWK.windowState && typeof AIWK.windowState.normalize === "function") {
            return AIWK.windowState.normalize(cfg || {});
        }
        cfg = cfg || {};
        return Object.assign({ project_id: "default", stage1_id: "st1_control", stage2_id: "st2_default", singleton: 1, fold_level: 0, visible: 1 }, cfg);
    }

    function saveAllState() {
        const all = Object.keys(wins).map(function (id) {
            return wins[id].toJSON ? wins[id].toJSON() : null;
        }).filter(Boolean);
        storeSet(STATE_KEY, all, {fn:"saveAllState"});
        return all;
    }

    function persistOne(win) {
        if (!win || !win.id || !win.moduleName) {
            return;
        }
        let list = savedList().filter(function (row) { return row.id !== win.id; });
        const state = normalizeWinState({
            id: win.id,
            win_id: win.id,
            module: win.moduleName || "",
            group: win.group || win.net || "home",
            net: win.group || win.net || "home",
            project_id: win.project_id,
            stage1_id: win.stage1_id,
            stage2_id: win.stage2_id,
            singleton: win.singleton,
            collapseLevel: win.collapseLevel || 0,
            hidden: !!(win.el && win.el.classList.contains("aiwk-win-hidden"))
        });
        list.push({
            id: win.id,
            win_id: win.id,
            title: win.title || win.id,
            shortTitle: win.shortTitle || "",
            icon: win.icon || "",
            module: win.moduleName || "",
            project_id: state.project_id,
            stage1_id: state.stage1_id,
            stage2_id: state.stage2_id,
            singleton: state.singleton,
            folder_route: win.folder_route || win.route || state.folder_route || state.route,
            route: win.folder_route || win.route || state.route,
            address: state.address,
            rect: Object.assign({}, win.rect || {}),
            iconRect: win.iconRect || null,
            collapseLevel: win.collapseLevel || 0,
            fold_level: win.collapseLevel || 0,
            hidden: !!(win.el && win.el.classList.contains("aiwk-win-hidden")),
            visible: win.el && win.el.classList.contains("aiwk-win-hidden") ? 0 : 1,
            order: win.restoreOrder || win.createOrder || Date.now(),
            updated_at: new Date().toISOString()
        });
        saveAllState();
        list.sort(function (a, b) { return (a.order || 0) - (b.order || 0); });
        saveList(list);
    }

    function setAllHidden(hidden) {
        issueGlobalCommand(hidden ? "hide" : "show", {});
        processGlobalCommandTick();
    }

    function setAllCollapseLevel(level) {
        issueGlobalCommand("collapse_level", { level: Number(level) });
        processGlobalCommandTick();
    }

    function textareaStoreKey(winId, textareaKey) {
        return "win_textarea_" + winId + "_" + textareaKey + "_height";
    }

    function issueGlobalCommand(action, payload) {
        globalCommandSeq += 1;
        latestGlobalCommand = {
            seq: globalCommandSeq,
            action: String(action || ""),
            payload: payload || {},
            issued_at: new Date().toISOString()
        };
        if (AIWK.events && typeof AIWK.events.emit === "function") {
            try { AIWK.events.emit("win:global-command", latestGlobalCommand); } catch (err) {}
        }
        return latestGlobalCommand;
    }

    function processGlobalCommandTick() {
        if (!latestGlobalCommand) {
            return;
        }
        Object.keys(wins).forEach(function (id) {
            const win = wins[id];
            if (!win || typeof win.applyGlobalCommand !== "function") {
                return;
            }
            try {
                win.applyGlobalCommand(latestGlobalCommand);
            } catch (err) {
                try { win.setStatus("GLOBAL COMMAND ERROR: " + (err && err.message ? err.message : String(err))); } catch (e) {}
            }
        });
    }

    function ensureCommandTick() {
        if (tickTimer) {
            return;
        }
        tickTimer = setInterval(processGlobalCommandTick, 180);
    }

    function bindTextareaPersist(win) {
        const list = win.parts.body.querySelectorAll("textarea");
        list.forEach(function (ta, idx) {
            const textareaKey = ta.getAttribute("data-aiwk-textarea-key") || ("textarea_" + idx);
            ta.setAttribute("data-aiwk-textarea-key", textareaKey);
            ta.style.width = "100%";
            ta.style.maxWidth = "100%";
            const savedHeight = storeGet(textareaStoreKey(win.id, textareaKey), null, {fn:"bindTextareaAutoHeight", win_id:win.id});
            if (savedHeight !== null && savedHeight !== undefined && savedHeight !== "") {
                const h = parseInt(savedHeight, 10);
                if (!isNaN(h) && h > 0) {
                    ta.style.height = h + "px";
                }
            }
            let lastHeight = Math.round(ta.getBoundingClientRect().height || ta.offsetHeight || 0);
            let timer = null;
            const save = function () {
                const h = Math.round(ta.getBoundingClientRect().height || ta.offsetHeight || 0);
                if (!h || h === lastHeight) {
                    return;
                }
                lastHeight = h;
                storeSet(textareaStoreKey(win.id, textareaKey), h, {fn:"bindTextareaAutoHeight", win_id:win.id});
                win.setStatus(AIWK.i18n.t("status.textarea_saved", "textarea saved") + " " + textareaKey + " h:" + h + " / " + win.rectText(AIWK.i18n.t("status.rect_ready", "rect ready")));
            };
            if (window.ResizeObserver) {
                const observer = new ResizeObserver(function () {
                    clearTimeout(timer);
                    timer = setTimeout(save, 120);
                });
                observer.observe(ta);
            }
            ta.addEventListener("pointerup", save);
            ta.addEventListener("keyup", save);
            ta.addEventListener("change", save);
        });
    }

    function pulseAllWins(kind, detail) {
        try {
            Object.keys(wins).forEach(function (id) {
                if (wins[id] && typeof wins[id].pulse === "function") wins[id].pulse(kind || "data", detail || "");
            });
        } catch (err) {}
    }
    try {
        AIWK.events.on("comm:wss:message", function () { pulseAllWins("wss", "WSS 수신"); });
        AIWK.events.on("comm:tab:message", function () { pulseAllWins("bus", "Tab BUS 수신"); });
        AIWK.events.on("comm:nr:message", function () { pulseAllWins("nr", "Node-RED 수신"); });
        AIWK.events.on("comm:wss:send", function () { pulseAllWins("wss", "WSS 전송"); });
        AIWK.events.on("comm:tab:send", function () { pulseAllWins("bus", "Tab BUS 전송"); });
        AIWK.events.on("comm:nr:send", function () { pulseAllWins("nr", "Node-RED 전송"); });
    } catch (err) {}

    // v045 communication pulse bridge
    AIWK.win = {
        registry: wins,
        nextZ: function () {
            topZ += 1;
            return topZ;
        },
        issueGlobalCommand: function (action, payload) {
            ensureCommandTick();
            return issueGlobalCommand(action, payload || {});
        },
        latestGlobalCommand: function () {
            return latestGlobalCommand ? Object.assign({}, latestGlobalCommand) : null;
        },
        tick: function () {
            processGlobalCommandTick();
            return { ok: 1, action: "tick", command: latestGlobalCommand, count: Object.keys(wins).length };
        },
        get: function (id) {
            return wins[id] || null;
        },
        list: function () {
            return Object.keys(wins).map(function (id) {
                return wins[id].toJSON();
            });
        },
        savedList: savedList,
        persistOne: persistOne,
        persistLayout: function () {
            Object.keys(wins).forEach(function (id) { persistOne(wins[id]); });
            return { ok: 1, count: savedList().length, list: savedList(), state: saveAllState() };
        },
        exportState: function () {
            return { ok: 1, version: AIWK.version || "v102-stage4.9-ext4-store-resize-noise-fix", state_key: STATE_KEY, count: saveAllState().length, windows: saveAllState() };
        },
        importLayout: function (layout) {
            layout = layout && layout.payload ? layout.payload : (layout || {});
            const list = Array.isArray(layout.windows) ? layout.windows : [];
            let created = 0;
            let updated = 0;
            list.forEach(function (row, idx) {
                if (!row || !row.id) { return; }
                const old = wins[row.id];
                if (old) {
                    if (row.rect) old.setRect(row.rect);
                    if (row.title || row.shortTitle || row.icon || row.order) old.setDisplayMeta({ title: row.title || old.title, shortTitle: row.shortTitle || old.shortTitle, icon: row.icon || old.icon, order: row.order || old.restoreOrder || old.createOrder });
                    if (row.module !== undefined) old.moduleName = String(row.module || "");
                    if (row.alpha !== undefined || row.alphaLevel !== undefined) {
                        old.alpha = Number(row.alpha || old.alpha || 1) || 1;
                        old.alphaLevel = Number(row.alphaLevel || old.alphaLevel || 1) || 1;
                        old.el.style.opacity = String(old.alpha);
                    }
                    if (row.collapseLevel !== undefined || row.fold_level !== undefined) old.setCollapseLevel(Number(row.collapseLevel !== undefined ? row.collapseLevel : row.fold_level) || 0);
                    persistOne(old);
                    updated += 1;
                    return;
                }
                AIWK.win.create({
                    id: row.id,
                    title: row.title || row.id,
                    shortTitle: row.shortTitle || "",
                    icon: row.icon || "",
                    module: row.module || row.moduleName || "",
                    rect: row.rect || {},
                    iconRect: row.iconRect || null,
                    alpha: row.alpha || 1,
                    alphaLevel: row.alphaLevel || 1,
                    collapseLevel: row.collapseLevel !== undefined ? row.collapseLevel : row.fold_level,
                    fold_level: row.fold_level !== undefined ? row.fold_level : row.collapseLevel,
                    hidden: !!row.hidden || row.visible === 0,
                    project_id: row.project_id || "default",
                    stage1_id: row.stage1_id || "st1_control",
                    stage2_id: row.stage2_id || "st2_default",
                    singleton: row.singleton !== undefined ? row.singleton : 1,
                    order: row.order || (idx + 1)
                });
                created += 1;
            });
            return { ok: 1, action: "import_layout", count: list.length, created: created, updated: updated };
        },
        normalizeState: normalizeWinState,
        removeFromSavedLayout: function (id) {
            saveList(savedList().filter(function (row) { return row.id !== id; }));
        },
        cleanupAutoRestoreList: function () {
            const list = cleanupAutoRestoreList();
            return { ok: 1, action: "cleanup_auto_restore", count: list.length, list: list };
        },
        hideAll: function () { setAllHidden(true); return { ok: 1, action: "hide_all", count: Object.keys(wins).length }; },
        showAll: function () { setAllHidden(false); return { ok: 1, action: "show_all", count: Object.keys(wins).length }; },
        collapseAll: function () { setAllCollapseLevel(1); return { ok: 1, action: "collapse_all", level: 1, count: Object.keys(wins).length }; },
        collapse2All: function () { setAllCollapseLevel(2); return { ok: 1, action: "collapse2_all", level: 2, count: Object.keys(wins).length }; },
        expandAll: function () { setAllCollapseLevel(0); return { ok: 1, action: "expand_all", level: 0, count: Object.keys(wins).length }; },
        iconAll: function () { setAllCollapseLevel(3); return { ok: 1, action: "icon_all", level: 3, count: Object.keys(wins).length }; },
        pulseAll: function (kind, detail) {
            Object.keys(wins).forEach(function (id) {
                if (wins[id] && typeof wins[id].pulse === "function") { wins[id].pulse(kind || "data", detail || ""); }
            });
            return { ok: 1, action: "pulse_all", kind: kind || "data", count: Object.keys(wins).length };
        },
        pulseWindow: function (id, kind, detail) {
            const win = wins[id];
            if (!win || typeof win.pulse !== "function") return { ok: 0, error: "WIN_NOT_FOUND", id: id };
            return win.pulse(kind || "data", detail || "");
        },
        closeAll: function () {
            const ids = Object.keys(wins);
            ids.forEach(function (id, idx) {
                const win = wins[id];
                if (!win) { return; }
                setTimeout(function () { if (wins[id]) { wins[id].close(); } }, idx * 120);
            });
            saveList([]);
            return { ok: 1, action: "close_all", count: ids.length };
        },
        restoreSavedSequential: async function () {
            const list = cleanupAutoRestoreList().slice().filter(function (row) { return row && row.id && row.module; });
            if (!list.length) {
                return { ok: 1, action: "restore_saved", count: 0 };
            }
            storeSet(RESTORE_BUSY_KEY, true, {fn:"restoreAll"});
            try {
                for (let i = 0; i < list.length; i += 1) {
                    const row = list[i];
                    if (!wins[row.id]) {
                        AIWK.win.create({
                            id: row.id,
                            title: row.title || row.id,
                            shortTitle: row.shortTitle || "",
                            icon: row.icon || "",
                            module: row.module,
                            rect: row.rect || {},
                            iconRect: row.iconRect || null,
                            collapseLevel: row.collapseLevel !== undefined ? row.collapseLevel : row.fold_level,
                            fold_level: row.fold_level !== undefined ? row.fold_level : row.collapseLevel,
                            hidden: !!row.hidden || row.visible === 0,
                            project_id: row.project_id || "default",
                            stage1_id: row.stage1_id || "st1_control",
                            stage2_id: row.stage2_id || "st2_default",
                            singleton: row.singleton !== undefined ? row.singleton : 1,
                            order: row.order || (i + 1)
                        });
                    }
                    await new Promise(function (resolve) { setTimeout(resolve, Math.min(500, 120 + i * 70)); });
                }
            } finally {
                storeSet(RESTORE_BUSY_KEY, false, {fn:"restoreAll"});
            }
            return { ok: 1, action: "restore_saved", count: list.length };
        },
        run: async function (id, msg) {
            const win = wins[id];
            if (!win) {
                throw new Error("WIN_NOT_FOUND: " + id + ". 해결: Win 목록에서 존재하는 id를 선택하십시오.");
            }
            return await win.run(msg || {});
        },
        create: function (cfg) {
            try {
                if (AIWK.debug && AIWK.debug.log) AIWK.debug.log("AIWK_WIN_CREATE_STEP", {step:"start", win_id:(cfg&&cfg.id)||"", module:(cfg&&cfg.module)||"", hasRoot:!!(AIWK&&AIWK.root), hasRootGet:!!(AIWK&&AIWK.root&&AIWK.root.get), hasStore:!!(AIWK&&AIWK.store), hasStoreGet:!!(AIWK&&AIWK.store&&AIWK.store.get)});
            cfg = cfg || {};
            const stateCfg = normalizeWinState(cfg);
            cfg.project_id = stateCfg.project_id;
            cfg.stage1_id = stateCfg.stage1_id;
            cfg.stage2_id = stateCfg.stage2_id;
            cfg.singleton = stateCfg.singleton;
            if (cfg.collapseLevel === undefined && cfg.fold_level === undefined) {
                cfg.collapseLevel = stateCfg.fold_level;
            }
            const id = cfg.id;
            const rect = resolveRect(id, cfg.rect);
            const order = Number(cfg.order || 0) || (++createSeq);
            const parts = AIWK.winRender.build({
                id: id,
                title: cfg.title || id,
                shortTitle: cfg.shortTitle || "",
                module: cfg.module || "",
                order: order,
                icon: cfg.icon || "",
                project_id: cfg.project_id,
                stage1_id: cfg.stage1_id,
                stage2_id: cfg.stage2_id,
                singleton: cfg.singleton
            });
            if (!AIWK.AIWKWin) {
                throw new Error("AIWK.win.create stopped: AIWK.AIWKWin is missing. 해결: manifest에서 aiwk_win_class.js를 aiwk_win.js보다 먼저 로드하십시오.");
            }

            const win = new AIWK.AIWKWin({
                id: id,
                title: cfg.title || id,
                shortTitle: cfg.shortTitle || "",
                module: cfg.module || "",
                parts: parts,
                rect: rect,
                order: order,
                icon: cfg.icon || "",
                project_id: cfg.project_id,
                stage1_id: cfg.stage1_id,
                stage2_id: cfg.stage2_id,
                singleton: cfg.singleton,
                alpha: cfg.alpha || 1,
                alphaLevel: cfg.alphaLevel || cfg.alpha_level || 1,
                collapseLevel: cfg.collapseLevel !== undefined ? cfg.collapseLevel : cfg.fold_level
            });

            win.createOrder = order;
            win.restoreOrder = order;
            if (cfg.iconRect) {
                win.iconRect = cfg.iconRect;
                storeSet("win_icon_rect_" + id, cfg.iconRect, {fn:"create", win_id:id});
            }
            win.setRect(rect);
            if (cfg.alpha !== undefined || cfg.alphaLevel !== undefined || cfg.alpha_level !== undefined) {
                win.alpha = Number(cfg.alpha || 1) || 1;
                win.alphaLevel = Number(cfg.alphaLevel || cfg.alpha_level || 1) || 1;
                win.el.style.opacity = String(win.alpha);
                win.el.dataset.aiwkAlpha = String(win.alpha);
                win.el.dataset.aiwkAlphaLevel = String(win.alphaLevel);
            }
            if (cfg.collapseLevel !== undefined || cfg.fold_level !== undefined) {
                win.collapseLevel = Number(cfg.collapseLevel !== undefined ? cfg.collapseLevel : cfg.fold_level) || 0;
                win.rect.collapseLevel = win.collapseLevel;
                win.rect.collapsed = win.collapseLevel > 0;
            }
            win.applyCollapseClass();
            win.bringFront();
            win.el.classList.add("aiwk-win-opening");
            setTimeout(function () { win.el.classList.remove("aiwk-win-opening"); }, 650);
            if (cfg.hidden) {
                win.el.classList.add("aiwk-win-hidden");
            }

            win.el.addEventListener("pointerdown", function () {
                win.bringFront();
            });

            AIWK.winDrag.attach(win);
            AIWK.winResize.attach(win);
            AIWK.winMenu.attach(win);

            if (!AIWK.root || typeof AIWK.root.get !== "function") {
                AIWK.root = AIWK.root || {};
                AIWK.root.get = function () {
                    let el = document.getElementById(AIWK.rootId || "aiwk-ext4-root");
                    if (!el) {
                        el = document.createElement("div");
                        el.id = AIWK.rootId || "aiwk-ext4-root";
                        el.setAttribute("data-aiwk-root", "fallback");
                        document.documentElement.appendChild(el);
                    }
                    return el;
                };
            }
            const root = AIWK.root.get();
            if (AIWK.debug && AIWK.debug.log) AIWK.debug.log("AIWK_WIN_CREATE_STEP", {step:"root_ok", win_id:id, root_id:root && root.id});
            root.appendChild(win.el);
            wins[id] = win;
            ensureCommandTick();
            persistOne(win);

            if (cfg.module) {
                if (AIWK.debug && AIWK.debug.log) AIWK.debug.log("AIWK_WIN_CREATE_STEP", {step:"module_mount_start", win_id:id, module:cfg.module});
                AIWK.modules.run(cfg.module, {
                    win: win,
                    body: parts.body,
                    status: parts.status,
                    AIWK: AIWK
                });
                if (AIWK.debug && AIWK.debug.log) AIWK.debug.log("AIWK_WIN_CREATE_STEP", {step:"module_mount_done", win_id:id, module:cfg.module});
            }

            if (window.AIWK_BUS && typeof window.AIWK_BUS.registerModule === "function") {
                window.AIWK_BUS.registerModule({
                    win_id: id,
                    module: win.moduleName || "",
                    title: win.title || id,
                    version: AIWK.version || "v018",
                    role: "win",
                    actions: {
                        run: async function (payload) {
                            return await win.run(payload || {});
                        },
                        selftest: async function (payload) {
                            const out = await win.test();
                            if (!out || !out.ok) {
                                throw new Error(out && out.error ? out.error : "WIN_SELFTEST_FAIL");
                            }
                            return { ok: 1, win_id: id, module: win.moduleName || "", result: out, received: payload || {} };
                        },
                        result: function () {
                            const box = win.parts && win.parts.body ? win.parts.body.querySelector('[data-aiwk-test-box="1"]') : null;
                            return { ok: 1, win_id: id, module: win.moduleName || "", text: box ? box.textContent : "" };
                        }
                    },
                    helpMap: {
                        run: "창 기본 run을 실행한다.",
                        selftest: "창 자체 테스트를 실행하고 통과하면 완성모듈로 처리한다.",
                        result: "창 테스트 결과를 반환한다."
                    }
                });
            }

            bindTextareaPersist(win);
            if (win.parts && win.parts.body && AIWK.ui && typeof AIWK.ui.applyPlaceholderTooltips === "function") {
                if (AIWK.debug && AIWK.debug.log) AIWK.debug.log("AIWK_WIN_CREATE_STEP", {step:"tooltip_start", win_id:id});
                AIWK.ui.applyPlaceholderTooltips(win.parts.body);
            }

            win.showRectStatus("status.rect_ready", "rect ready");
            AIWK.winRender.refreshAuth(win);
            win.offAuthChange = AIWK.events.on("auth:change", function () {
                AIWK.winRender.refreshAuth(win);
                if (win.parts && win.parts.status) {
                    win.setStatus(AIWK.i18n.t("auth.role_changed", "권한 변경") + ": " + AIWK.auth.role + " / " + win.rectText(AIWK.i18n.t("status.rect_ready", "rect ready")));
                }
            });
            AIWK.events.emit("win:create", { id: id, module: cfg.module });
            if (AIWK.debug && AIWK.debug.log) AIWK.debug.log("AIWK_WIN_CREATE_STEP", {step:"done", win_id:id});
            return win;
            } catch (err) {
                reportError(err, {file:"AIWK_COMMON/win/aiwk_win.js", fn:"AIWK.win.create", win_id:(cfg && cfg.id) || "", module:(cfg && cfg.module) || "", cause:"창 생성 중 의존성/설정 오류"});
                throw err;
            }
        }
    };
}());
