/* DING: Desktop Icons New Generation for GNOME Shell
 *
 * Adw-DING Copyright (C) 2022, 2025 Sundeep Mediratta (smedius@gmail.com)
 * Based on code original (C) Carlos Soriano and (c) Sergio Costas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import {Gtk, Gio} from '../dependencies/gi.js';
import {FileItemIcon} from '../dependencies/localFiles.js';

import {_} from '../dependencies/gettext.js';

export {VolumeIcon};

const VolumeIcon = class extends FileItemIcon {
    constructor(desktopManager, file, fileInfo, fileExtra, gioMount) {
        super(desktopManager, file, fileInfo, fileExtra, gioMount);
        this._ejectCancellable = null;
        this._umountCancellable = null;

        if (this._gioMount) {
            /* gjs doesn't handle some virtual implementations well*/
            Gio._promisify(this._gioMount.constructor.prototype,
                'eject_with_operation');
            Gio._promisify(this._gioMount.constructor.prototype,
                'unmount_with_operation');
        }
    }

    _destroy() {
        this._destroying = true;

        if (this._umountCancellable)
            this._umountCancellable.cancel();
        this._umountCancellable = null;

        if (this._ejectCancellable)
            this._ejectCancellable.cancel();
        this._ejectCancellable = null;

        super._destroy();
    }

    _getVisibleName() {
        if (this._fileTypeEnum === this.Enums.FileType.EXTERNAL_DRIVE)
            return this._gioMount.get_name();

        return super._getVisibleName();
    }

    _setAccesibilityName() {
        const visibleName = this._getVisibleName();
        const driveName = _('Drive');

        if (this._fileTypeEnum === this.Enums.FileType.EXTERNAL_DRIVE) {
        /** TRANSLATORS: when using a screen reader, this is the text
         * read when an external drive is selected.
         * Example: if a USB stick named "my_portable"
         * is selected, it will say "my_portable Drive" */
            this.container.update_property(
                [Gtk.AccessibleProperty.LABEL],
                [`${visibleName} ${driveName}`]
            );
        }
    }

    _getDefaultIcon() {
        if (this._fileTypeEnum === this.Enums.FileType.EXTERNAL_DRIVE)
            return this._gioMount.get_icon();

        return super._getDefaultIcon();
    }


    async eject(atWidget) {
        if (this._destroying || !this._gioMount || this._ejectCancellable)
            return;

        const parentWidget =  atWidget ?? this._grid._window;
        const mountOp = new Gtk.MountOperation();
        mountOp.set_parent(parentWidget);
        const cancellable = new Gio.Cancellable();
        this._ejectCancellable = cancellable;

        try {
            await this._gioMount.eject_with_operation(
                Gio.MountUnmountFlags.NONE,
                mountOp,
                cancellable
            );
        } catch (e) {
            // I cannot find the exact Gio Enum, Gio.MountOperationResult
            // does not work. Shortcut :)
            // logError(e, `Mount failed: ${e.domain} ${e.code}`);
            if (!this._isCancellationError(e) && !(e.domain === 195 && e.code === 30)) {
                console.error(
                    e,
                    `Exception ejecting Volume ${
                        this._getVisibleName()
                            ? this._getVisibleName()
                            : 'Volume icon'
                    }: ${e.message}`
                );
            }
        } finally {
            if (this._ejectCancellable === cancellable)
                this._ejectCancellable = null;
        }
    }

    async unmount(atWidget) {
        if (this._destroying || !this._gioMount || this._umountCancellable)
            return;

        const parentWidget = atWidget ?? this._grid._window;
        const mountOp = new Gtk.MountOperation();
        mountOp.set_parent(parentWidget);
        const cancellable = new Gio.Cancellable();
        this._umountCancellable = cancellable;

        try {
            await this._gioMount.unmount_with_operation(
                Gio.MountUnmountFlags.NONE,
                mountOp,
                cancellable
            );
        } catch (e) {
            // I cannot find the exact Gio Enum, Gio.MountOperationResult
            // does not work. Shortcut :)
            // logError(e, `Mount failed: ${e.domain} ${e.code}`);
            if (!this._isCancellationError(e) && !(e.domain === 195 && e.code === 30)) {
                console.error(
                    e,
                    `Exception unmounting Volume ${
                        this._getVisibleName()
                            ? this._getVisibleName()
                            : 'Volume icon'
                    }: ${e.message}`
                );
            }
        } finally {
            if (this._umountCancellable === cancellable)
                this._umountCancellable = null;
        }
    }

    get canEject() {
        if (this._gioMount)
            return this._gioMount.can_eject();
        else
            return false;
    }

    get canUnmount() {
        if (this._gioMount)
            return this._gioMount.can_unmount();
        else
            return false;
    }
};
