const Applet = imports.ui.applet;
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const St = imports.gi.St;
const Gtk = imports.gi.Gtk;
const CinnamonDesktop = imports.gi.CinnamonDesktop;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Settings = imports.ui.settings;

function LayoutMenuItem() {
    this._init.apply(this, arguments);
}

LayoutMenuItem.prototype = {
    __proto__: PopupMenu.PopupBaseMenuItem.prototype,

    _init: function(ipsettings, id, index, indicator, long_name) {
        PopupMenu.PopupBaseMenuItem.prototype._init.call(this);

        this._ipsettings = ipsettings;
        this._id = id;
        this._index = index;
        this.label = new St.Label({ text: long_name });
        this.indicator = indicator;
        this.addActor(this.label);
        this.addActor(this.indicator);
    },

    activate: function(event) {
        PopupMenu.PopupBaseMenuItem.prototype.activate.call(this);
        this._ipsettings.set_value('current', GLib.Variant.new_uint32(this._index));
    }
};

function MyApplet(metadata, orientation, panel_height) {
    this._init(metadata, orientation, panel_height);
}

MyApplet.prototype = {
    __proto__: Applet.TextIconApplet.prototype,

    _init: function(metadata, orientation, panel_height) {        
        Applet.TextIconApplet.prototype._init.call(this, orientation, panel_height);
        
        try {  
            Gtk.IconTheme.get_default().append_search_path(metadata.path + "/flags");                              
            this.menuManager = new PopupMenu.PopupMenuManager(this);
            this.menu = new Applet.AppletPopupMenu(this, orientation);
            this.menuManager.addMenu(this.menu);                            

            this.actor.add_style_class_name('panel-status-button');            

            this._labelActors = [ ];
            this._layoutItems = [ ];

            this.settings = new Settings.AppletSettings(this, metadata["uuid"], this.instance_id);

            this.settings.bindProperty(Settings.BindingDirection.BIDIRECTIONAL,
                                       "use-flags",
                                       "_showFlags",
                                       this._syncConfig,
                                       null);

            this._xkbInfo = new CinnamonDesktop.XkbInfo();
            this._ipsettings = new Gio.Settings({ schema: 'org.cinnamon.desktop.input-sources' });
            this._ipsettings.connect('changed::sources', Lang.bind(this, this._syncConfig));
            this._ipsettings.connect('changed::current', Lang.bind(this, this._syncGroup));


            this._syncConfig();

            this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
            this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, function() {
                Main.overview.hide();
                Util.spawn(['gkbd-keyboard-display', '-l', this._selectedLayout._id]);
            }));                                
            this.menu.addAction(_("Show Character Table"), Lang.bind(this, function() {
                Main.overview.hide();
                Util.spawn(['gucharmap']);
            }));
            this.menu.addSettingsAction(_("Region and Language Settings"), 'region');                      
        }
        catch (e) {
            global.logError(e);
        }
    },
    
    on_applet_clicked: function(event) {
        this.menu.toggle();        
    },  

   _adjustGroupNames: function(names) {
        // Disambiguate duplicate names with a subscript
        // This is O(N^2) to avoid sorting names
        // but N <= 4 so who cares?

        for (let i = 0; i < names.length; i++) {
            let name = names[i];
            let cnt = 0;
            for (let j = i + 1; j < names.length; j++) {
                if (names[j] == name) {
                    cnt++;
                    // U+2081 SUBSCRIPT ONE
                    names[j] = name + String.fromCharCode(0x2081 + cnt);
                }
            }
            if (cnt != 0)
                names[i] = name + '\u2081';
        }

        return names;
    },

    _syncConfig: function() {
        let sources = this._ipsettings.get_value('sources');
        if (sources.n_children() > 1) {
            this.actor.show();
        } else {
            this.menu.close();
            this.actor.hide();
        }

        for (let i = 0; i < this._layoutItems.length; i++)
            this._layoutItems[i].destroy();

        for (let i = 0; i < this._labelActors.length; i++)
            this._labelActors[i].destroy();


        this._selectedLayout = null;
        this._layoutItems = [ ];
        this._labelActors = [ ];
        for (let i = 0; i < sources.n_children(); i++) {
            let [type, id] = sources.get_child_value(i).deep_unpack();
            let displayName = id;
            let shortName = id;
            let xkbLayout = id;
            if (type == 'xkb') {
                [_exists, displayName, shortName, xkbLayout, _xkbVariant] = this._xkbInfo.get_layout_info(id);
            } // TODO: errorhandling, handle 'ibus'
            let icon_name = xkbLayout; // FIXME: Really?
            let actor;
            if (this._showFlags)
                actor = new St.Icon({ icon_name: icon_name, icon_type: St.IconType.FULLCOLOR, style_class: 'popup-menu-icon' });
            else
                actor = new St.Label({ text: shortName });
            let item = new LayoutMenuItem(this._ipsettings, id, i, actor, displayName);
            item._icon_name = icon_name;
            this._layoutItems.push(item);
            this.menu.addMenuItem(item, i);

            let shortLabel = new St.Label({ text: shortName });
            this._labelActors.push(shortLabel);
        }

        this._syncGroup();
    },

    _syncGroup: function() {
        let current = this._ipsettings.get_uint('current');

        if (this._selectedLayout) {
            this._selectedLayout.setShowDot(false);
            this._selectedLayout = null;
        }

        let item = this._layoutItems[current];
        item.setShowDot(true);

        let selectedLabel = this._labelActors[current];

        if (this._showFlags) {
            this.set_applet_icon_name(item._icon_name);
            this.set_applet_label("");
        } else {
            this.hide_applet_icon();
            this.set_applet_label(selectedLabel.text);
        }       

        this._selectedLayout = item;
    }    
};

function main(metadata, orientation, panel_height) {  
    let myApplet = new MyApplet(metadata, orientation, panel_height);
    return myApplet;      
}
