(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "../../App", "../../core/Bind", "../../core/XNode", "../styles/AtomWindowStyle", "./AtomControl", "./AtomTemplate"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.AtomWindow = exports.AtomWindowFrameTemplate = exports.getTemplateParent = void 0;
    const App_1 = require("../../App");
    const Bind_1 = require("../../core/Bind");
    const XNode_1 = require("../../core/XNode");
    const AtomWindowStyle_1 = require("../styles/AtomWindowStyle");
    const AtomControl_1 = require("./AtomControl");
    const AtomTemplate_1 = require("./AtomTemplate");
    function getTemplateParent(e) {
        const tp = e._templateParent;
        if (tp) {
            return tp;
        }
        const p = e._logicalParent || e.parentElement;
        if (p) {
            return getTemplateParent(p);
        }
    }
    exports.getTemplateParent = getTemplateParent;
    class AtomWindowFrameTemplate extends AtomTemplate_1.AtomTemplate {
        get templateParent() {
            return getTemplateParent(this.element);
        }
        preCreate() {
            this.titlePresenter = null;
            this.commandPresenter = null;
            this.contentPresenter = null;
            super.preCreate();
        }
        create() {
            // remember, if you do not wish to use dynamic themes
            // then use one time binding
            this.render(XNode_1.default.create("div", { class: "frame", styleWidth: Bind_1.default.oneWay(() => this.templateParent.width || undefined), styleHeight: Bind_1.default.oneWay(() => this.templateParent.height || undefined), styleLeft: Bind_1.default.oneWay(() => this.templateParent.x >= 0 ? `${this.templateParent.x}px` : undefined), styleTop: Bind_1.default.oneWay(() => this.templateParent.y >= 0 ? `${this.templateParent.y}px` : undefined), styleMarginTop: Bind_1.default.oneWay(() => this.templateParent.x >= 0 ? "0" : undefined), styleMarginLeft: Bind_1.default.oneWay(() => this.templateParent.x >= 0 ? "0" : undefined), styleMarginRight: Bind_1.default.oneWay(() => this.templateParent.x >= 0 ? "0" : undefined), styleMarginBottom: Bind_1.default.oneWay(() => this.templateParent.x >= 0 ? "0" : undefined) },
                XNode_1.default.create("div", { class: "title-presenter", presenter: Bind_1.default.presenter("titlePresenter") }),
                XNode_1.default.create("div", { class: "content-presenter", presenter: Bind_1.default.presenter("contentPresenter") }),
                XNode_1.default.create("div", { class: "command-bar-presenter", presenter: Bind_1.default.presenter("commandPresenter") })));
            // this.bind(this.element, "styleClass", [["templateParent", "controlStyle", "frame"]]);
            // this.bind(this.element, "styleWidth", [["templateParent", "width"]], false, (v) => v || undefined);
            // this.bind(this.element, "styleHeight", [["templateParent", "height"]], false, (v) => v || undefined);
            // this.bind(this.element, "styleLeft", [["templateParent", "x"]],
            //     false, (v) => v >= 0 ? v + "px" : undefined);
            // this.bind(this.element, "styleTop", [["templateParent", "y"]],
            //     false, (v) => v >= 0 ? v + "px" : undefined);
            // this.bind(this.element, "styleMarginTop", [["templateParent", "x"]], false, (v) => v >= 0 ? "0" : undefined);
            // this.bind(this.element, "styleMarginLeft", [["templateParent", "x"]],
            //  false, (v) => v >= 0 ? "0" : undefined);
            // this.bind(this.element, "styleMarginRight", [["templateParent", "x"]],
            // false, (v) => v >= 0 ? "0" : undefined);
            // this.bind(this.element, "styleMarginBottom", [["templateParent", "x"]],
            // false, (v) => v >= 0 ? "0" : undefined);
            // // add title host
            // const titlePresenter = document.createElement("div");
            // this.bind(titlePresenter, "styleClass", [["templateParent", "controlStyle", "titlePresenter"]]);
            // // titleHost.classList.add(style.titleHost.className);
            // this.titlePresenter = titlePresenter;
            // this.element.appendChild(titlePresenter);
            // // add content presenter
            // const cp = document.createElement("div");
            // this.bind(cp, "styleClass", [["templateParent", "controlStyle", "content"]]);
            // // cp.classList.add(style.content.className);
            // this.contentPresenter = cp;
            // this.element.appendChild(cp);
            // // create command presenter
            // const cdp = document.createElement("div");
            // // cdp.classList.add(style.commandBar.className);
            // this.bind(cdp, "styleClass", [["templateParent", "controlStyle", "commandBar"]]);
            // this.commandPresenter = cdp;
            // this.element.appendChild(cdp);
        }
    }
    exports.AtomWindowFrameTemplate = AtomWindowFrameTemplate;
    class AtomWindowTitleTemplate extends AtomControl_1.AtomControl {
        get templateParent() {
            return getTemplateParent(this.element);
        }
        create() {
            this.render(XNode_1.default.create("div", { class: "title-host" },
                XNode_1.default.create("span", { class: "title", text: Bind_1.default.oneWay(() => this.templateParent.title) }),
                XNode_1.default.create("button", { class: "close-button", eventClick: Bind_1.default.event(() => this.templateParent.close()) })));
            // this.bind(this.element, "styleClass", [["templateParent", "controlStyle", "titleHost"]]);
            // // add title
            // const title = document.createElement("span");
            // this.bind(title, "styleClass", [["templateParent", "controlStyle", "title"]]);
            // // title.classList.add(style.title.className);
            // this.bind(title, "text", [["templateParent", "title"]], false);
            // // add close button
            // const closeButton = document.createElement("button");
            // this.bind(closeButton, "styleClass", [["templateParent", "controlStyle", "closeButton"]]);
            // // closeButton.textContent = "x";
            // this.bindEvent(closeButton, "click", (e) => {
            //     const w = getTemplateParent(this.element) as AtomWindow;
            //     w.close();
            // });
            // // append title host > title
            // this.append(title);
            // this.append(closeButton);
        }
    }
    class AtomWindow extends AtomControl_1.AtomControl {
        constructor() {
            super(...arguments);
            this.title = "";
            this.width = "";
            this.height = "";
            this.x = -1;
            this.y = -1;
            this.titleTemplate = AtomWindowTitleTemplate;
            this.frameTemplate = AtomWindowFrameTemplate;
            this.isReady = false;
        }
        get templateParent() {
            return getTemplateParent(this.element);
        }
        onPropertyChanged(name) {
            switch (name) {
                case "windowTemplate":
                case "commandTemplate":
                case "frameTemplate":
                    this.invalidate();
                    break;
            }
        }
        close() {
            const vm = this.viewModel;
            if (vm.cancel) {
                this.app.runAsync(() => vm.cancel());
                return;
            }
            const message = `atom-window-cancel:${this.id}`;
            const device = this.app.resolve(App_1.App);
            device.broadcast(message, "cancelled");
        }
        onUpdateUI() {
            if (!(this.windowTemplate && this.frameTemplate)) {
                return;
            }
            if (this.isReady) {
                return;
            }
            this.bind(this.element, "title", [["viewModel", "title"]]);
            // let us create frame first...
            const frame = new (this.frameTemplate)(this.app);
            const fe = frame.element;
            // setup drag and drop for the frame...
            const titleContent = new (this.titleTemplate)(this.app);
            (titleContent.element)._templateParent = this;
            frame.titlePresenter.appendChild(titleContent.element);
            this.setupDragging(frame.titlePresenter);
            this.element.classList.add("frame-host");
            fe._logicalParent = this.element;
            fe._templateParent = this;
            if (!frame.contentPresenter) {
                throw new Error("ContentPresenter must be set inside frameTemplate before creating window");
            }
            const content = new (this.windowTemplate)(this.app);
            (content.element)._templateParent = this;
            this.setElementClass(content.element, { content: 1 });
            frame.contentPresenter.appendChild(content.element);
            if (this.commandTemplate) {
                if (!frame.commandPresenter) {
                    throw new Error("CommandPresenter must be set inside frameTemplate" +
                        "before creating window if command template is present");
                }
                const command = new (this.commandTemplate)(this.app);
                (command.element)._templateParent = this;
                this.setElementClass(command.element, { "command-bar": 1 });
                frame.commandPresenter.appendChild(command.element);
            }
            this.append(frame);
            // lets center frame...
            setTimeout(() => {
                this.centerFrame(frame.element);
            }, 100);
            this.isReady = true;
        }
        preCreate() {
            this.defaultControlStyle = AtomWindowStyle_1.AtomWindowStyle;
            this.title = null;
            this.width = "";
            this.height = "";
            this.x = -1;
            this.y = -1;
            this.windowTemplate = null;
            this.commandTemplate = null;
            this.titleTemplate = AtomWindowTitleTemplate;
            this.frameTemplate = AtomWindowFrameTemplate;
            super.preCreate();
            this.render(XNode_1.default.create("div", { styleClass: Bind_1.default.oneTime(() => this.controlStyle.name) }));
        }
        centerFrame(e) {
            /// window is destroyed probably..
            if (!this.element) {
                return;
            }
            const parent = this.element.parentElement;
            if (parent === window || parent === document.body) {
                return;
            }
            if (parent.offsetWidth <= 0 || parent.offsetHeight <= 0) {
                setTimeout(() => {
                    this.centerFrame(e);
                }, 100);
                return;
            }
            if (e.offsetWidth <= 0 || e.offsetHeight <= 0) {
                setTimeout(() => {
                    this.centerFrame(e);
                }, 100);
                return;
            }
            const x = (parent.offsetWidth - e.offsetWidth) / 2;
            const y = (parent.offsetHeight - e.offsetHeight) / 2;
            this.x = x;
            this.y = y;
            e.style.opacity = "1";
            this.element.style.removeProperty("opacity");
        }
        setupDragging(tp) {
            this.bindEvent(tp, "mousedown", (startEvent) => {
                startEvent.preventDefault();
                const disposables = [];
                // const offset = AtomUI.screenOffset(tp);
                const offset = { x: tp.parentElement.offsetLeft, y: tp.parentElement.offsetTop };
                const rect = { x: startEvent.clientX, y: startEvent.clientY };
                const cursor = tp.style.cursor;
                tp.style.cursor = "move";
                disposables.push(this.bindEvent(document.body, "mousemove", (moveEvent) => {
                    const { clientX, clientY } = moveEvent;
                    const dx = clientX - rect.x;
                    const dy = clientY - rect.y;
                    offset.x += dx;
                    offset.y += dy;
                    this.x = offset.x;
                    this.y = offset.y;
                    rect.x = clientX;
                    rect.y = clientY;
                }));
                disposables.push(this.bindEvent(document.body, "mouseup", (endEvent) => {
                    tp.style.cursor = cursor;
                    for (const iterator of disposables) {
                        iterator.dispose();
                    }
                }));
            });
        }
    }
    exports.AtomWindow = AtomWindow;
    AtomWindow.windowTemplate = XNode_1.default.prepare("windowTemplate", true, true);
    AtomWindow.commandTemplate = XNode_1.default.prepare("commandTemplate", true, true);
    AtomWindow.titleTemplate = XNode_1.default.prepare("titleTemplate", true, true);
    AtomWindow.frameTemplate = XNode_1.default.prepare("frameTemplate", true, true);
});
//# sourceMappingURL=AtomWindow.js.map