window["require_setup"](module);

import * as electron from "electron";
const remote = electron.remote;
const {Menu, MenuItem} = remote;

import {isFunction} from "util";
import NativeImage = electron.NativeImage;

class ElectronContextMenu implements contextmenu.ContextMenuProvider {
    private _close_listeners: (() => any)[] = [];
    private _current_menu: electron.Menu;

    private _icon_mash_url: string;
    private _icon_mask_img: NativeImage;
    private _div: JQuery;

    despawn_context_menu() {
        if(!this._current_menu)
            return;
        this._current_menu.closePopup();
        this._current_menu = undefined;

        for(const listener of this._close_listeners)
            listener();
        this._close_listeners = [];
    }

    finalize() {
        this._icon_mask_img = undefined;
        this._icon_mash_url = undefined;
        if(this._div) this._div.detach();
        this._div = undefined;
        this._cache_klass_map = undefined;
    }

    initialize() {
        this.initialize_icons();
    }

    private async initialize_icons() {
        if(!this._div) {
            this._div = $.spawn("div");
            this._div.css('display', 'none');
            this._div.appendTo(document.body);
        }

        const image = new Image();
        image.src = 'img/client_icon_sprite.svg';
        await new Promise((resolve, reject) => {
            image.onload = resolve;
            image.onerror = reject;
        });

        /* TODO: Get a size! */
        const canvas = document.createElement("canvas");
        canvas.width = 1024;
        canvas.height = 1024;
        canvas.getContext("2d").drawImage(image, 0, 0);

        this._icon_mash_url = canvas.toDataURL();
        this._icon_mask_img = remote.nativeImage.createFromDataURL(this._icon_mash_url);
    }


    private _cache_klass_map: {[key: string]: NativeImage} = {};
    private class_to_image(klass: string) : NativeImage {
        if(!klass || !this._icon_mask_img)
            return undefined;
        if(this._cache_klass_map[klass])
            return this._cache_klass_map[klass];

        this._div[0].classList.value = 'icon ' + klass;
        const data = window.getComputedStyle(this._div[0]);

        const offset_x = parseInt(data.backgroundPositionX.split(",")[0]);
        const offset_y = parseInt(data.backgroundPositionY.split(",")[0]);

        //http://localhost/home/TeaSpeak/Web-Client/web/environment/development/img/client_icon_sprite.svg
        //const hight = element.css('height');
        //const width = element.css('width');
        console.log("Offset: x: %o y: %o;", offset_x, offset_y);
        return this._cache_klass_map[klass] = this._icon_mask_img.crop({
            height: 16,
            width: 16,
            x: offset_x == 0 ? 0 : -offset_x,
            y: offset_y == 0 ? 0 : -offset_y
        });
    }

    private _entry_id = 0;
    private build_menu(entry: contextmenu.MenuEntry) : electron.MenuItem {
        if(entry.type == contextmenu.MenuEntryType.CLOSE) {
            this._close_listeners.push(entry.callback);
            return undefined;
        }

        const click_callback = () => {
            if(entry.callback)
                entry.callback();
            this.despawn_context_menu();
        };
        const _id = "entry_" + (this._entry_id++);
        if(entry.type == contextmenu.MenuEntryType.ENTRY) {
            return new MenuItem({
                id: _id,
                label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string,
                type: "normal",
                click: click_callback,
                icon: this.class_to_image(entry.icon_class),
                visible: entry.visible,
                enabled: !entry.disabled
            });
        } else if(entry.type == contextmenu.MenuEntryType.HR) {
            if(typeof(entry.visible) === "boolean" && !entry.visible)
                return undefined;

            return new MenuItem({
                id: _id,
                type: "separator",
                label: '',
                click: click_callback
            })
        } else if(entry.type == contextmenu.MenuEntryType.CHECKBOX) {
            return new MenuItem({
                id: _id,
                label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string,
                type: "checkbox",
                checked: !!entry.checkbox_checked,
                click: click_callback,
                icon: this.class_to_image(entry.icon_class),
                visible: entry.visible,
                enabled: !entry.disabled
            });
        } else if (entry.type == contextmenu.MenuEntryType.SUB_MENU) {
            const sub_menu = new Menu();
            for(const e of entry.sub_menu) {
                const build = this.build_menu(e);
                if(!build)
                    continue;
                sub_menu.append(build);
            }
            return new MenuItem({
                id: _id,
                label: (isFunction(entry.name) ? (entry.name as (() => string))() : entry.name) as string,
                type: "submenu",
                submenu: sub_menu,
                click: click_callback,
                icon: this.class_to_image(entry.icon_class),
                visible: entry.visible,
                enabled: !entry.disabled
            });
        }
        return undefined;
    }

    spawn_context_menu(x: number, y: number, ...entries: contextmenu.MenuEntry[]) {
        this.despawn_context_menu();

        this._current_menu = new Menu();
        for(const entry of entries) {
            const build = this.build_menu(entry);
            if(!build)
                continue;
            this._current_menu.append(build);
        }

        this._current_menu.popup({
            window: remote.getCurrentWindow(),
            x: x,
            y: y,
            callback: () => this.despawn_context_menu()
        });
    }

    html_format_enabled() { return false; }
}

contextmenu.set_provider(new ElectronContextMenu());

export {};