const { GObject, Clutter, St, GLib } = imports.gi;
const { panelMenu, popupMenu } = imports.ui;
const { getCurrentExtension, getSettings } = imports.misc.extensionUtils;
const AppManager = getCurrentExtension().imports.AppManager;

var TrayIndicator = GObject.registerClass(
	class TrayIndicator extends panelMenu.Button {
		_init() {
			this._icons = [];

			super._init(0.0, null, false);
			this._overflow = false;

			this._indicators = new St.BoxLayout();
			this.add_child(this._indicators);

			this._icon = new St.Icon({
				icon_name: "view-more-horizontal",
				style_class: "system-status-icon",
				reactive: true,
				track_hover: true,
			});
			this._indicators.add_child(this._icon);

			this._menuItem = new popupMenu.PopupBaseMenuItem({
				reactive: false,
				can_focus: true,
			});
			this.menu.addMenuItem(this._menuItem);
			this.menu.actor.add_style_class_name("TrayIndicatorPopup");
			this.hide();
		}

		get size() {
			const context = St.ThemeContext.get_for_stage(global.stage);
			return this._size * context.scale_factor;
		}

		setSize(size, margin, padding) {
			this._size = size;
			this._margin = margin;
			this._padding = padding;

			this._icons.forEach((icon) => {
				icon.get_parent().style = this._getButtonStyle();
				icon.set_size(this._size, this._size);
			});
		}

		addIcon(icon) {
			const isHidden = AppManager.getAppSetting(icon, "hidden");
			if (isHidden) return;

			const button = new St.Button({
				child: icon,
				button_mask:
					St.ButtonMask.ONE | St.ButtonMask.TWO | St.ButtonMask.THREE,
				style: this._getButtonStyle(),
				style_class: "panel-button",
			});
			icon.opacity = 0;
			icon.set_x_align(Clutter.ActorAlign.CENTER);
			icon.set_y_align(Clutter.ActorAlign.CENTER);
			icon.inOverflow = this._overflow;
			GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => {
				icon.set_size(this.size, this.size);
				icon.ease({
					opacity: 255,
					duration: 400,
					mode: Clutter.AnimationMode.EASE_OUT_QUAD,
				});
				this._addEffectIcon(icon);
				return GLib.SOURCE_REMOVE;
			});
			icon.connect("destroy", () => {
				button.destroy();
			});

			button.connect("button-release-event", (actor, event) => {
				switch (event.get_button()) {
					case 1:
						AppManager.leftClick(icon, event);
						break;
					case 2:
						AppManager.middleClick(icon, event);
						break;
					case 3:
						icon.click(event);
						break;
				}
				if (AppManager.isWine(icon)) {
					GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1, () => {
						this.menu.close();
						return GLib.SOURCE_REMOVE;
					});
				} else {
					this.menu.close();
				}
			});

			this._icons.push(icon);

			if (this._overflow) {
				this._menuItem.actor.add(button);
			} else {
				this._indicators.insert_child_at_index(button, 0);
			}

			this.checkOverflow();
		}

		removeIcon(icon, ignoreCheckOverflow) {
			const index = this._icons.indexOf(icon);
			this._icons.splice(index, 1);

			const actor = icon.get_parent();
			actor.remove_actor(icon);
			actor.destroy();

			if (!ignoreCheckOverflow) {
				this.checkOverflow();
			}
		}

		checkOverflow() {
			if (this._icons.length >= getSettings().get_int("icons-limit")) {
				this._overflow = true;
				this._icon.visible = true;
				this.reactive = true;
				this.style_class = "panel-button TrayIndicator";
			} else {
				this._overflow = false;
				this._icon.visible = false;
				this.reactive = false;
				this.style_class = "TrayIndicator";
			}

			if (this._icons.length) {
				this.show();
			} else {
				this.hide();
			}

			this._refreshIcons(this._overflow);
		}

		_refreshIcons(overflow) {
			this._icons.forEach((icon) => {
				if (icon.inOverflow != overflow) {
					this.removeIcon(icon, true);
					this.addIcon(icon);
				}
			});
		}

		_getButtonStyle() {
			let style;
			if (!this._overflow) {
				style = `margin: ${this._margin.vertical}px ${this._margin.horizontal}px; padding: ${this._padding.vertical}px ${this._padding.horizontal}px`;
			}
			return `width: ${this.size}px; height: ${this.size}px;${style}`;
		}

		_addEffectIcon(icon) {
			let brightnessContrast = new Clutter.BrightnessContrastEffect({});
			brightnessContrast.set_contrast(
				getSettings().get_int("icon-contrast") / 100
			);
			brightnessContrast.set_brightness(
				getSettings().get_int("icon-brightness") / 100
			);
			icon.add_effect_with_name("brightnessContrast", brightnessContrast);
			icon.add_effect_with_name(
				"desaturate",
				new Clutter.DesaturateEffect({
					factor: getSettings().get_int("icon-saturation") / 100,
				})
			);
		}

		setEffect(contrast, saturation, brightness) {
			this._icons.forEach((icon) => {
				let brightnessContrast = icon.get_effect("brightnessContrast");
				brightnessContrast.set_contrast(contrast / 100);
				brightnessContrast.set_brightness(brightness / 100);

				let desaturate = icon.get_effect("desaturate");
				desaturate.set_factor(saturation / 100);
			});
		}
	}
);
