// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ui.javafx;

import com.intellij.ide.IdeEventQueue;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.JBUI;
import com.sun.javafx.application.PlatformImpl;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;

public class JavaFxHtmlPanel implements Disposable {
  @NotNull
  private final JPanel myPanelWrapper;
  @NotNull
  private final List<Runnable> myInitActions = new ArrayList<>();
  @Nullable
  private JFXPanel myPanel;
  @Nullable protected WebView myWebView;

  public JavaFxHtmlPanel() {
    Color background = JBColor.background();
    myPanelWrapper = new JPanel(new BorderLayout());
    myPanelWrapper.setBackground(background);

    ApplicationManager.getApplication().invokeLater(() -> runFX(() -> PlatformImpl.startup(() -> {
      myWebView = new WebView();
      myWebView.setContextMenuEnabled(false);
      myWebView.setZoom(JBUI.scale(1.f));

      final WebEngine engine = myWebView.getEngine();
      registerListeners(engine);

      javafx.scene.paint.Color fxColor = toFxColor(background);
      final Scene scene = new Scene(myWebView, fxColor);

      ApplicationManager.getApplication().invokeLater(() -> runFX(() -> {
        myPanel = new JFXPanelWrapper();

        Platform.runLater(() -> myPanel.setScene(scene));

        setHtml("");
        for (Runnable action : myInitActions) {
          Platform.runLater(action);
        }
        myInitActions.clear();

        myPanelWrapper.add(myPanel, BorderLayout.CENTER);
        myPanelWrapper.repaint();
      }));
    })));
  }

  @NotNull
  public static javafx.scene.paint.Color toFxColor(Color background) {
    double r = background.getRed() / 255.0;
    double g = background.getGreen() / 255.0;
    double b = background.getBlue() / 255.0;
    double a = background.getAlpha() / 255.0;
    return javafx.scene.paint.Color.color(r, g, b, a);
  }

  public void setBackground(Color background) {
    myPanelWrapper.setBackground(background);
    ApplicationManager.getApplication().invokeLater(() -> runFX(() -> {
      myPanel.getScene().setFill(toFxColor(background));
    }));
  }

  protected void registerListeners(@NotNull WebEngine engine) {
  }

  private static void runFX(@NotNull Runnable r) {
    IdeEventQueue.unsafeNonblockingExecute(r);
  }

  protected void runInPlatformWhenAvailable(@NotNull Runnable runnable) {
    ApplicationManager.getApplication().assertIsDispatchThread();
    if (myPanel == null) {
      myInitActions.add(runnable);
    }
    else {
      Platform.runLater(runnable);
    }
  }

  @NotNull
  public JComponent getComponent() {
    return myPanelWrapper;
  }

  public void setHtml(@NotNull String html) {
    final String htmlToRender = prepareHtml(html);
    runInPlatformWhenAvailable(() -> getWebViewGuaranteed().getEngine().loadContent(htmlToRender));
  }

  @NotNull
  protected String prepareHtml(@NotNull String html) {
    return html;
  }

  public void render() {
    runInPlatformWhenAvailable(() -> {
      getWebViewGuaranteed().getEngine().reload();
      ApplicationManager.getApplication().invokeLater(myPanelWrapper::repaint);
    });
  }

  @Override
  public void dispose() {
  }

  public void addKeyListener(KeyListener l) {
    runInPlatformWhenAvailable(() -> myPanel.addKeyListener(l));
  }


  @NotNull
  protected WebView getWebViewGuaranteed() {
    if (myWebView == null) {
      throw new IllegalStateException("WebView should be initialized by now. Check the caller thread");
    }
    return myWebView;
  }
}

@@ -431,35 +431,138 @@
 ort 
-javafx.application.Platform
+com.sun.javafx.webkit.Accessor;%0Aimport com.sun.webkit.WebPage;%0Aimport javafx.application.Platform;%0Aimport javafx.concurrent.Worker
 ;%0Aim
@@ -1164,16 +1164,44 @@
 WebView;
+%0A  private Color background;
 %0A%0A  publ
@@ -1227,22 +1227,16 @@
 ) %7B%0A    
-Color 
 backgrou
@@ -1669,16 +1669,304 @@
 engine);
+%0A      engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -%3E %7B%0A        if (newValue == Worker.State.RUNNING) %7B%0A            WebPage page = Accessor.getPageFor(engine);%0A            page.setBackgroundColor(background.getRGB());%0A          %7D%0A        %7D%0A      );
 %0A%0A      
@@ -2889,24 +2889,58 @@
 ckground) %7B%0A
+    this.background = background;%0A
     myPanelW
@@ -3037,32 +3037,63 @@
 %3E runFX(() -%3E %7B%0A
+      if (myPanel != null) %7B%0A  
       myPanel.ge
@@ -3129,24 +3129,32 @@
 ckground));%0A
+      %7D%0A
     %7D));%0A  %7D

fix blinking during WebView loading