/* exported init enable disable */


const Signals = imports.signals;

const {
    Atk, Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St,
} = imports.gi;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();

const Main = imports.ui.main;
const HeadsUpMessage = Me.imports.headsUpMessage;

const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;

class Extension {
    constructor() {
        ExtensionUtils.initTranslations();
    }

    enable() {
        this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.heads-up-display');
        this._idleTimeoutChangedId = this._settings.connect('changed::idle-timeout', this._onIdleTimeoutChanged.bind(this));
        this._settingsChangedId = this._settings.connect('changed', this._updateMessage.bind(this));

        this._idleMonitor = Meta.IdleMonitor.get_core();
        this._messageInhibitedUntilIdle = false;
        this._oldMapWindow = Main.wm._mapWindow;
        Main.wm._mapWindow = this._mapWindow;
        this._windowManagerMapId = global.window_manager.connect('map', this._onWindowMap.bind(this));

        if (Main.layoutManager._startingUp)
            this._startupCompleteId = Main.layoutManager.connect('startup-complete', this._onStartupComplete.bind(this));
        else
            this._onStartupComplete(this);
    }

    disable() {
        this._dismissMessage();

        if (this._idleWatchId) {
            this._idleMonitor.remove_watch(this._idleWatchId);
            this._idleWatchId = 0;
        }

        if (this._sessionModeUpdatedId) {
            Main.sessionMode.disconnect(this._sessionModeUpdatedId);
            this._sessionModeUpdatedId = 0;
        }

        if (this._overviewShowingId) {
            Main.overview.disconnect(this._overviewShowingId);
            this._overviewShowingId = 0;
        }

        if (this._overviewHiddenId) {
            Main.overview.disconnect(this._overviewHiddenId);
            this._overviewHiddenId = 0;
        }

        if (this._panelConnectionId) {
            Main.layoutManager.panelBox.disconnect(this._panelConnectionId);
            this._panelConnectionId = 0;
        }

        if (this._oldMapWindow) {
            Main.wm._mapWindow = this._oldMapWindow;
            this._oldMapWindow = null;
        }

        if (this._windowManagerMapId) {
            global.window_manager.disconnect(this._windowManagerMapId);
            this._windowManagerMapId = 0;
        }

        if (this._startupCompleteId) {
            Main.layoutManager.disconnect(this._startupCompleteId);
            this._startupCompleteId = 0;
        }

        if (this._settingsChangedId) {
            this._settings.disconnect(this._settingsChangedId);
            this._settingsChangedId = 0;
        }
    }

    _onWindowMap(shellwm, actor) {
        let windowObject = actor.meta_window;
        let windowType = windowObject.get_window_type();

        if (windowType != Meta.WindowType.NORMAL)
            return;

        if (!this._message || !this._message.visible)
            return;

        let messageRect = new Meta.Rectangle({ x: this._message.x, y: this._message.y, width: this._message.width, height: this._message.height });
        let windowRect = windowObject.get_frame_rect();

        if (windowRect.intersect(messageRect)) {
            windowObject.move_frame(false, windowRect.x, this._message.y + this._message.height);
        }
    }

    _onStartupComplete() {
        this._overviewShowingId = Main.overview.connect('showing', this._updateMessage.bind(this));
        this._overviewHiddenId = Main.overview.connect('hidden', this._updateMessage.bind(this));
        this._panelConnectionId = Main.layoutManager.panelBox.connect('notify::visible', this._updateMessage.bind(this));
        this._sessionModeUpdatedId = Main.sessionMode.connect('updated', this._onSessionModeUpdated.bind(this));

        this._updateMessage();
    }

    _onSessionModeUpdated() {
         if (!Main.sessionMode.hasWindows)
             this._messageInhibitedUntilIdle = false;
         this._updateMessage();
    }

    _onIdleTimeoutChanged() {
        if (this._idleWatchId) {
            this._idleMonitor.remove_watch(this._idleWatchId);
            this._idleWatchId = 0;
        }
        this._messageInhibitedUntilIdle = false;
    }

    _updateMessage() {
        if (this._messageInhibitedUntilIdle) {
            if (this._message)
                this._dismissMessage();
            return;
        }

        if (this._idleWatchId) {
            this._idleMonitor.remove_watch(this._idleWatchId);
            this._idleWatchId = 0;
        }

        if (Main.sessionMode.hasOverview && Main.overview.visible) {
            this._dismissMessage();
            return;
        }

        if (!Main.layoutManager.panelBox.visible) {
            this._dismissMessage();
            return;
        }

        let supportedModes = [];

        if (this._settings.get_boolean('show-when-unlocked'))
            supportedModes.push('user');

        if (this._settings.get_boolean('show-when-unlocking'))
            supportedModes.push('unlock-dialog');

        if (this._settings.get_boolean('show-when-locked'))
            supportedModes.push('lock-screen');

        if (this._settings.get_boolean('show-on-login-screen'))
            supportedModes.push('gdm');

        if (!supportedModes.includes(Main.sessionMode.currentMode) &&
            !supportedModes.includes(Main.sessionMode.parentMode)) {
            this._dismissMessage();
            return;
        }

        let heading = this._settings.get_string('message-heading');
        let body = this._settings.get_string('message-body');

        if (!heading && !body) {
            this._dismissMessage();
            return;
        }

        if (!this._message) {
            this._message = new HeadsUpMessage.HeadsUpMessage(heading, body);

            this._message.connect('notify::allocation', this._adaptSessionForMessage.bind(this));
            this._message.connect('clicked', this._onMessageClicked.bind(this));
        }

        this._message.reactive = true;
        this._message.track_hover = true;

        this._message.setHeading(heading);
        this._message.setBody(body);

        if (!Main.sessionMode.hasWindows) {
            this._message.track_hover = false;
            this._message.reactive = false;
        }
    }

    _onMessageClicked() {
        if (!Main.sessionMode.hasWindows)
          return;

        if (this._idleWatchId) {
            this._idleMonitor.remove_watch(this._idleWatchId);
            this._idleWatchId = 0;
        }

        let idleTimeout = this._settings.get_uint('idle-timeout');
        this._idleWatchId = this._idleMonitor.add_idle_watch(idleTimeout * 1000, this._onUserIdle.bind(this));
        this._messageInhibitedUntilIdle = true;
        this._updateMessage();
    }

    _onUserIdle() {
        this._messageInhibitedUntilIdle = false;
        this._updateMessage();
    }

    _dismissMessage() {
        if (!this._message) {
            return;
        }

        this._message.visible = false;
        this._message.destroy();
        this._message = null;
        this._resetMessageTray();
        this._resetLoginDialog();
    }

    _resetMessageTray() {
        if (!Main.messageTray)
            return;

        Main.messageTray.actor.set_translation(0, 0, 0);
    }

    _alignMessageTray() {
        if (!Main.messageTray)
            return;

        if (!this._message || !this._message.visible) {
            this._resetMessageTray()
            return;
        }

        let panelBottom = Main.layoutManager.panelBox.y + Main.layoutManager.panelBox.height;
        let messageBottom = this._message.y + this._message.height;

        Main.messageTray.actor.set_translation(0, messageBottom - panelBottom, 0);
    }

    _resetLoginDialog() {
        if (!Main.sessionMode.isGreeter)
            return;

        if (!Main.screenShield || !Main.screenShield._dialog)
            return;

        let dialog = Main.screenShield._dialog;

        if (this._authPromptAllocatedId) {
            dialog.disconnect(this._authPromptAllocatedId);
            this._authPromptAllocatedId = 0;
        }

        dialog.style = null;
        dialog._bannerView.style = null;
    }

    _adaptLoginDialogForMessage() {
        if (!Main.sessionMode.isGreeter)
            return;

        if (!Main.screenShield || !Main.screenShield._dialog)
            return;

        if (!this._message || !this._message.visible) {
            this._resetLoginDialog()
            return;
        }

        let dialog = Main.screenShield._dialog;

        let messageHeight = this._message.y + this._message.height;
        if (dialog._logoBin.visible)
            messageHeight -= dialog._logoBin.height;

        if (messageHeight <= 0) {
            dialog.style = null;
            dialog._bannerView.style = null;
        } else {
            dialog.style = `margin-top: ${messageHeight}px;`;

            let bannerOnSide = dialog._bannerView.x + dialog._bannerView.width < dialog._authPrompt.actor.x;

            if (bannerOnSide)
               dialog._bannerView.style = `margin-bottom: ${messageHeight}px;`;
            else
               dialog._bannerView.style = `margin-top: ${messageHeight}px`;
        }
    }

    _adaptSessionForMessage() {
        this._alignMessageTray();

        if (Main.sessionMode.isGreeter) {
            this._adaptLoginDialogForMessage();
            if (!this._authPromptAllocatedId) {
                let dialog = Main.screenShield._dialog;
                this._authPromptAllocatedId = dialog._authPrompt.actor.connect("notify::allocation", this._adaptLoginDialogForMessage.bind(this));
            }
        }
    }
}

function init() {
    return new Extension();
}
