const {St, GObject, Meta, Pango} = imports.gi;
const Main = imports.ui.main;
const Params = imports.misc.params;

const BoxPointer = imports.ui.boxpointer;

function createLabel(params) {
    let label = new St.Label(params);
    label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
    label.clutter_text.line_wrap = false;
    return label;
}

var InputPanel = GObject.registerClass(class InputPanel extends GObject.Object {
    _init(params) {
        params = Params.parse(params, {kimpanel : null});
        this._arrowSide = St.Side.TOP;
        // create boxpointer as UI
        this.panel = new BoxPointer.BoxPointer(this._arrowSide,
                                               {x_align : St.Align.START});

        this.kimpanel = params.kimpanel;

        this.actor = this.panel;
        this.actor._delegate = this;
        this.actor.style_class = 'popup-menu-boxpointer';
        this.actor.add_style_class_name('popup-menu');
        this.actor.add_style_class_name('minwidth-zero');
        this.actor.add_style_class_name('kimpanel-popup-boxpointer');

        this._cursor = new St.Label({});

        this.layout = new St.BoxLayout({
            style_class : 'popup-menu-content',
            vertical : true,
        });
        this.layout.add_style_class_name('kimpanel-popup-content');
        this.panel.bin.set_child(this.layout);

        this.upperLayout = new St.BoxLayout();

        this.lookupTableVertical = this.kimpanel.isLookupTableVertical();
        this.lookupTableLayout =
            new St.BoxLayout({vertical : this.lookupTableVertical});

        this.layout.add_child(this.upperLayout);

        this.text_style = this.kimpanel.getTextStyle();
        this.auxText = createLabel({
            style_class : 'kimpanel-label',
            style : this.text_style,
            text : ''
        });
        this.preeditText = createLabel({
            style_class : 'kimpanel-label',
            style : this.text_style,
            text : ''
        });

        this.upperLayout.add_child(this.auxText);
        this.upperLayout.add_child(this.preeditText);
        this.hide();
        this.actor.hide();
    }

    setAuxText(text) {
        this.auxText.set_text(text);
        if (!this.auxText.visible) {
            this.auxText.show();
        }
    }
    setPreeditText(text, pos) {
        let charArray = [...text ];
        let cat = charArray.slice(0, pos).join('') + "|" +
                  charArray.slice(pos).join('');
        this.preeditText.set_text(cat);
        if (!this.preeditText.visible)
            this.preeditText.show();
    }
    _candidateClicked(widget) {
        this.kimpanel.selectCandidate(widget.candidate_index);
    }
    setLookupTable(label, table, visible) {
        let len = visible ? table.length : 0;
        let labelLen = this.lookupTableLayout.get_children().length;

        if (labelLen > 0 && len == 0) {
            this.layout.remove_child(this.lookupTableLayout);
        } else if (labelLen == 0 && len > 0) {
            this.layout.add_child(this.lookupTableLayout);
        }

        // if number is not enough, create new
        if (len > labelLen) {
            for (let i = 0; i < len - labelLen; i++) {
                let item = createLabel({
                    style_class : 'kimpanel-candidate-item kimpanel-label',
                    style : this.text_style,
                    text : '',
                    reactive : true
                });
                item.candidate_index = 0;
                item.ignore_focus = true;
                item.connect('button-release-event', (widget) => {
                    if (!widget.ignore_focus)
                        this._candidateClicked(widget);
                });
                item.connect('enter-event', (widget) => {
                    if (!widget.ignore_focus)
                        widget.add_style_pseudo_class('hover');
                });
                item.connect('leave-event', (widget) => {
                    if (!widget.ignore_focus)
                        widget.remove_style_pseudo_class('hover');
                });
                this.lookupTableLayout.add_child(item);
            }
        } else if (len < labelLen) {
            // else destroy unnecessary one
            for (let i = 0; i < labelLen - len; i++) {
                this.lookupTableLayout.get_children()[0].destroy();
            }
        }

        // update label and text
        let lookupTable = this.lookupTableLayout.get_children();
        for (let i = 0; i < lookupTable.length; i++) {
            if (label[i].length == 0)
                lookupTable[i].ignore_focus = true;
            else
                lookupTable[i].ignore_focus = false;
            lookupTable[i].candidate_index = i;
            lookupTable[i].text = label[i] + table[i];
        }
    }
    setLookupTableCursor(cursor) {
        let labelLen = this.lookupTableLayout.get_children().length;
        for (var i = 0; i < labelLen; i++) {
            if (i == cursor)
                this.lookupTableLayout.get_children()[i].add_style_pseudo_class(
                    'active');
            else
                this.lookupTableLayout.get_children()[i]
                    .remove_style_pseudo_class('active');
        }
    }
    setVertical(vertical) { this.lookupTableLayout.set_vertical(vertical); }
    updateFont(textStyle) {
        this.text_style = textStyle;
        this.auxText.set_style(this.text_style);
        this.preeditText.set_style(this.text_style);
        let lookupTable = this.lookupTableLayout.get_children();
        for (let i = 0; i < lookupTable.length; i++)
            lookupTable[i].set_style(this.text_style);
    }
    hideAux() {
        if (this.auxText.visible)
            this.auxText.hide();
    }
    hidePreedit() {
        if (this.preeditText.visible)
            this.preeditText.hide();
    }

    updatePosition() {
        let kimpanel = this.kimpanel;
        let x = kimpanel.x;
        let y = kimpanel.y;
        let w = kimpanel.w;
        let h = kimpanel.h;
        if (kimpanel.relative) {
            if (global.display.focus_window) {
                let shellScale =
                    St.ThemeContext.get_for_stage(global.stage).scale_factor;
                let window =
                    global.display.focus_window.get_compositor_private();
                if (window) {
                    x = window.x + x * (shellScale / kimpanel.scale);
                    y = window.y + y * (shellScale / kimpanel.scale);
                    w = w * (shellScale / kimpanel.scale);
                    h = h * (shellScale / kimpanel.scale);
                }
            }
        }
        let rect = new Meta.Rectangle({x : x, y : y, width : w, height : h});
        let monitor =
            Main.layoutManager
                .monitors[global.display.get_monitor_index_for_rect(rect)];
        let panel_height = this.actor.get_height();

        if (h == 0) {
            h = 20;
            y = y - 20;
        }

        if (y + panel_height + h >= monitor.y + monitor.height) {
            this._arrowSide = St.Side.BOTTOM;

            if (y + h >= monitor.y + monitor.height) {
                y = monitor.y + monitor.height - 1;
                h = 1;
            }
        } else {
            this._arrowSide = St.Side.TOP;
        }

        if (x < monitor.x) {
            x = monitor.x;
        }
        if (x >= monitor.x + monitor.width) {
            x = monitor.x + monitor.width - 1;
        }

        this._cursor.set_position(x, y);
        this._cursor.set_size((w == 0 ? 1 : w), (h == 0 ? 1 : h));

        this.panel._arrowSide = this._arrowSide;

        this.visible = kimpanel.showAux || kimpanel.showPreedit ||
                       kimpanel.showLookupTable;
        if (this.visible) {
            this.show();
        } else {
            this.hide();
        }
    }

    show() {
        this.panel.setPosition(this._cursor, 0.0);
        this.panel.open(BoxPointer.PopupAnimation.NONE);
        this.panel.get_parent().set_child_above_sibling(this.panel, null);
    }
    hide() { this.panel.close(BoxPointer.PopupAnimation.NONE); }
});
