"use strict";
// *****************************************************************************
// Copyright (C) 2017 TypeFox and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShouldSaveDialog = exports.setDirty = exports.SaveableWidget = exports.close = exports.Saveable = void 0;
const keys_1 = require("./keyboard/keys");
const dialogs_1 = require("./dialogs");
const widgets_1 = require("./widgets");
const vscode_uri_1 = require("vscode-uri");
var Saveable;
(function (Saveable) {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function isSource(arg) {
        return !!arg && ('saveable' in arg) && is(arg.saveable);
    }
    Saveable.isSource = isSource;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function is(arg) {
        return !!arg && ('dirty' in arg) && ('onDirtyChanged' in arg);
    }
    Saveable.is = is;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function isUntitled(arg) {
        return !!arg && ('uri' in arg) && vscode_uri_1.URI.parse(arg.uri).scheme === 'untitled';
    }
    Saveable.isUntitled = isUntitled;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function get(arg) {
        if (is(arg)) {
            return arg;
        }
        if (isSource(arg)) {
            return arg.saveable;
        }
        return undefined;
    }
    Saveable.get = get;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function getDirty(arg) {
        const saveable = get(arg);
        if (saveable && saveable.dirty) {
            return saveable;
        }
        return undefined;
    }
    Saveable.getDirty = getDirty;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function isDirty(arg) {
        return !!getDirty(arg);
    }
    Saveable.isDirty = isDirty;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    async function save(arg, options) {
        const saveable = get(arg);
        if (saveable) {
            await saveable.save(options);
        }
    }
    Saveable.save = save;
    async function closeWithoutSaving(doRevert = true) {
        const saveable = get(this);
        if (saveable && doRevert && saveable.dirty && saveable.revert) {
            await saveable.revert();
        }
        this[exports.close]();
        return (0, widgets_1.waitForClosed)(this);
    }
    function createCloseWithSaving(getOtherSaveables) {
        let closing = false;
        return async function (options) {
            if (closing) {
                return;
            }
            const saveable = get(this);
            if (!saveable) {
                return;
            }
            closing = true;
            try {
                const result = await shouldSave(saveable, () => {
                    var _a;
                    const notLastWithDocument = !closingWidgetWouldLoseSaveable(this, (_a = getOtherSaveables === null || getOtherSaveables === void 0 ? void 0 : getOtherSaveables()) !== null && _a !== void 0 ? _a : []);
                    if (notLastWithDocument) {
                        return this.closeWithoutSaving(false).then(() => undefined);
                    }
                    if (options && options.shouldSave) {
                        return options.shouldSave();
                    }
                    return new ShouldSaveDialog(this).open();
                });
                if (typeof result === 'boolean') {
                    if (result) {
                        await Saveable.save(this);
                    }
                    await this.closeWithoutSaving();
                }
            }
            finally {
                closing = false;
            }
        };
    }
    async function confirmSaveBeforeClose(toClose, others) {
        var _a;
        for (const widget of toClose) {
            const saveable = Saveable.get(widget);
            if (saveable === null || saveable === void 0 ? void 0 : saveable.dirty) {
                if (!closingWidgetWouldLoseSaveable(widget, others)) {
                    continue;
                }
                const userWantsToSave = await new ShouldSaveDialog(widget).open();
                if (userWantsToSave === undefined) { // User clicked cancel.
                    return undefined;
                }
                else if (userWantsToSave) {
                    await saveable.save();
                }
                else {
                    await ((_a = saveable.revert) === null || _a === void 0 ? void 0 : _a.call(saveable));
                }
            }
        }
        return true;
    }
    Saveable.confirmSaveBeforeClose = confirmSaveBeforeClose;
    /**
     * @param widget the widget that may be closed
     * @param others widgets that will not be closed.
     * @returns `true` if widget is saveable and no widget among the `others` refers to the same saveable. `false` otherwise.
     */
    function closingWidgetWouldLoseSaveable(widget, others) {
        const saveable = get(widget);
        return !!saveable && !others.some(otherWidget => otherWidget !== widget && get(otherWidget) === saveable);
    }
    function apply(widget, getOtherSaveables) {
        if (SaveableWidget.is(widget)) {
            return widget;
        }
        const saveable = Saveable.get(widget);
        if (!saveable) {
            return undefined;
        }
        const saveableWidget = widget;
        setDirty(saveableWidget, saveable.dirty);
        saveable.onDirtyChanged(() => setDirty(saveableWidget, saveable.dirty));
        const closeWithSaving = createCloseWithSaving(getOtherSaveables);
        return Object.assign(saveableWidget, {
            closeWithoutSaving,
            closeWithSaving,
            close: closeWithSaving,
            [exports.close]: saveableWidget.close,
        });
    }
    Saveable.apply = apply;
    async function shouldSave(saveable, cb) {
        if (!saveable.dirty) {
            return false;
        }
        if (saveable.autoSave !== 'off') {
            return true;
        }
        return cb();
    }
    Saveable.shouldSave = shouldSave;
})(Saveable = exports.Saveable || (exports.Saveable = {}));
exports.close = Symbol('close');
var SaveableWidget;
(function (SaveableWidget) {
    function is(widget) {
        return !!widget && 'closeWithoutSaving' in widget;
    }
    SaveableWidget.is = is;
    function getDirty(widgets) {
        return get(widgets, Saveable.isDirty);
    }
    SaveableWidget.getDirty = getDirty;
    function* get(widgets, filter = () => true) {
        for (const widget of widgets) {
            if (SaveableWidget.is(widget) && filter(widget)) {
                yield widget;
            }
        }
    }
    SaveableWidget.get = get;
})(SaveableWidget = exports.SaveableWidget || (exports.SaveableWidget = {}));
;
/**
 * The class name added to the dirty widget's title.
 */
const DIRTY_CLASS = 'theia-mod-dirty';
function setDirty(widget, dirty) {
    const dirtyClass = ` ${DIRTY_CLASS}`;
    widget.title.className = widget.title.className.replace(dirtyClass, '');
    if (dirty) {
        widget.title.className += dirtyClass;
    }
}
exports.setDirty = setDirty;
class ShouldSaveDialog extends dialogs_1.AbstractDialog {
    constructor(widget) {
        super({
            title: `Do you want to save the changes you made to ${widget.title.label || widget.title.caption}?`
        });
        this.shouldSave = true;
        const messageNode = document.createElement('div');
        messageNode.textContent = "Your changes will be lost if you don't save them.";
        messageNode.setAttribute('style', 'flex: 1 100%; padding-bottom: calc(var(--theia-ui-padding)*3);');
        this.contentNode.appendChild(messageNode);
        this.dontSaveButton = this.appendDontSaveButton();
        this.appendCloseButton();
        this.appendAcceptButton('Save');
    }
    appendDontSaveButton() {
        const button = this.createButton("Don't save");
        this.controlPanel.appendChild(button);
        button.classList.add('secondary');
        return button;
    }
    onAfterAttach(msg) {
        super.onAfterAttach(msg);
        this.addKeyListener(this.dontSaveButton, keys_1.Key.ENTER, () => {
            this.shouldSave = false;
            this.accept();
        }, 'click');
    }
    get value() {
        return this.shouldSave;
    }
}
exports.ShouldSaveDialog = ShouldSaveDialog;
//# sourceMappingURL=saveable.js.map