/*
 * Copyright 2017 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
package io.flutter.view;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.Toggleable;
import com.intellij.openapi.application.ApplicationManager;
import io.flutter.run.daemon.FlutterApp;
import io.flutter.utils.StreamSubscription;
import io.flutter.vmService.ServiceExtensionState;
import io.flutter.vmService.ToggleableServiceExtensionDescription;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;

abstract class FlutterViewToggleableAction<T> extends FlutterViewAction implements Toggleable, Disposable {
  private final ToggleableServiceExtensionDescription<T> extensionDescription;
  private StreamSubscription<ServiceExtensionState> currentValueSubscription;

  FlutterViewToggleableAction(@NotNull FlutterApp app,
                              @Nullable Icon icon,
                              ToggleableServiceExtensionDescription<T> extensionDescription) {
    // Assume the button is not enabled by default and pass disabledText here.
    super(app, extensionDescription.getDisabledText(), null, icon);
    this.extensionDescription = extensionDescription;
  }

  @Override
  public final void update(@NotNull AnActionEvent e) {
    // selected
    final boolean selected = this.isSelected();
    final Presentation presentation = e.getPresentation();
    presentation.putClientProperty("selected", selected);

    if (!app.isSessionActive()) {
      dispose();
      e.getPresentation().setEnabled(false);
      return;
    }

    if (currentValueSubscription == null) {
      currentValueSubscription =
        app.getVMServiceManager().getServiceExtensionState(extensionDescription.getExtension()).listen((state) -> {
          if (presentation.getClientProperty("selected") != (Boolean)state.isEnabled()) {
            presentation.putClientProperty("selected", state.isEnabled());
          }
        }, true);
    }

    presentation.setText(
      isSelected()
      ? extensionDescription.getEnabledText()
      : extensionDescription.getDisabledText());

    app.hasServiceExtension(extensionDescription.getExtension(), (enabled) -> {
      e.getPresentation().setEnabled(app.isSessionActive() && enabled);
    });
  }

  @Override
  public void dispose() {
    if (currentValueSubscription != null) {
      currentValueSubscription.dispose();
      currentValueSubscription = null;
    }
  }

  @Override
  protected void perform(AnActionEvent event) {
    if (app.isSessionActive()) {
      app.callBooleanExtension(extensionDescription.getExtension(), isSelected());
    }
  }

  @Override
  public void actionPerformed(@NotNull AnActionEvent event) {
    this.setSelected(event, !isSelected());
    super.actionPerformed(event);
  }

  public boolean isSelected() {
    return app.getVMServiceManager().getServiceExtensionState(extensionDescription.getExtension()).getValue().isEnabled();
  }

  public void setSelected(@Nullable AnActionEvent event, boolean selected) {
    app.getVMServiceManager().setServiceExtensionState(
      extensionDescription.getExtension(),
      selected,
      selected ? extensionDescription.getEnabledValue() : extensionDescription.getDisabledValue());

    if (event != null) {
      ApplicationManager.getApplication().invokeLater(() -> this.update(event));
    }
  }
}

@@ -1031,16 +1031,75 @@
 ription;
+%0A  private StreamSubscription%3CBoolean%3E enabledSubscription;
 %0A%0A  Flut
@@ -1440,16 +1440,17 @@
  icon);%0A
+%0A
     this
@@ -2258,159 +2258,36 @@
 e);%0A
-    %7D%0A%0A    presentation.setText(%0A      isSelected()%0A      ? extensionDescription.getEnabledText()%0A      : extensionDescription.getDisabledText());%0A%0A   
+%0A      enabledSubscription =
  app
@@ -2361,30 +2361,27 @@
  -%3E %7B%0A      
-e.getP
+  p
 resentation(
@@ -2371,34 +2371,32 @@
     presentation
-()
 .setEnabled(app.
@@ -2434,12 +2434,161 @@
     
+  
 %7D);%0A
+    %7D%0A%0A    presentation.setText(%0A      isSelected()%0A      ? extensionDescription.getEnabledText()%0A      : extensionDescription.getDisabledText());%0A
   %7D%0A
@@ -2749,32 +2749,148 @@
 n = null;%0A    %7D%0A
+    if (enabledSubscription != null) %7B%0A      enabledSubscription.dispose();%0A      enabledSubscription = null;%0A    %7D%0A
   %7D%0A%0A  @Override

fix an issue with leaking subscriptions (#5115)