package com.kodcu.service.extension;
import com.kodcu.config.ExtensionConfigBean;
import com.kodcu.controller.ApplicationController;
import com.kodcu.other.Current;
import com.kodcu.other.IOHelper;
import com.kodcu.other.TrimWhite;
import com.kodcu.service.ThreadService;
import com.kodcu.service.cache.BinaryCacheService;
import javafx.concurrent.Worker;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.SnapshotParameters;
import javafx.scene.image.WritableImage;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
import java.util.Objects;
/**
* Created by usta on 25.12.2014.
*/
@Component
public class MathJaxService {
private final Logger logger = LoggerFactory.getLogger(MathJaxService.class);
private final ApplicationController controller;
private final Current current;
private final ThreadService threadService;
private final BinaryCacheService binaryCacheService;
private final ExtensionConfigBean extensionConfigBean;
private WebView webView;
private boolean initialized;
@Value("${application.mathjax.url}")
private String mathjaxUrl;
@Autowired
public MathJaxService(final ApplicationController controller, final Current current, ThreadService threadService, BinaryCacheService binaryCacheService, ExtensionConfigBean extensionConfigBean) {
this.controller = controller;
this.current = current;
this.threadService = threadService;
this.binaryCacheService = binaryCacheService;
this.extensionConfigBean = extensionConfigBean;
}
private void initialize(Runnable... runnable) {
webEngine().getLoadWorker().stateProperty().addListener((observableValue1, state, state2) -> {
if (state2 == Worker.State.SUCCEEDED) {
JSObject window = getWindow();
if (window.getMember("afx").equals("undefined"))
window.setMember("afx", controller);
if (!initialized) {
for (Runnable run : runnable) {
run.run();
}
}
initialized = true;
}
});
this.load();
}
private void load() {
threadService.runActionLater(() -> {
webEngine().load(String.format(mathjaxUrl, controller.getPort()));
});
}
public void reload() {
this.load();
}
private WebEngine webEngine() {
return getWebView().getEngine();
}
public void processFormula(String formula, String imagesDir, String imageTarget) {
threadService.runActionLater(() -> {
if (initialized) {
getWindow().call("processFormula", formula, imagesDir, imageTarget);
} else {
initialize(() -> {
getWindow().call("processFormula", formula, imagesDir, imageTarget);
});
}
});
}
public JSObject getWindow() {
return (JSObject) webEngine().executeScript("window");
}
public WebView getWebView() {
if (Objects.isNull(webView)) {
webView = new WebView();
webView.setMaxHeight(1000);
webView.setPrefHeight(1000);
webView.setMaxWidth(1000);
webView.setPrefWidth(1000);
webView.setLayoutX(-22000);
webView.setLayoutY(-22000);
webView.setZoom(extensionConfigBean.getDefaultImageZoom());
controller.getRootAnchor().getChildren().add(webView);
}
return webView;
}
public void snapshotFormula(String formula, String imagesDir, String imageTarget) {
try {
Objects.requireNonNull(imageTarget);
boolean cachedResource = imageTarget.contains("/afx/cache");
if (!imageTarget.endsWith(".png") && !cachedResource)
return;
Integer cacheHit = current.getCache().get(imageTarget);
int hashCode = (imageTarget + imagesDir + formula).hashCode();
if (Objects.isNull(cacheHit) || hashCode != cacheHit) {
WritableImage writableImage = getWebView().snapshot(new SnapshotParameters(), null);
BufferedImage bufferedImage = SwingFXUtils.fromFXImage(writableImage, null);
Path path = current.currentTab().getParentOrWorkdir();
threadService.runTaskLater(() -> {
try {
TrimWhite trimWhite = new TrimWhite();
BufferedImage trimmed = trimWhite.trim(bufferedImage);
if (!cachedResource) {
Path imagePath = path.resolve(imageTarget);
IOHelper.createDirectories(imagePath.getParent());
IOHelper.imageWrite(trimmed, "png", imagePath.toFile());
threadService.runActionLater(() -> {
controller.clearImageCache(imagePath);
});
} else {
binaryCacheService.putBinary(imageTarget, trimmed);
threadService.runActionLater(() -> {
controller.clearImageCache(imageTarget);
});
}
current.getCache().put(imageTarget, hashCode);
logger.debug("MathJax extension is ended for {}", imageTarget);
} catch (Exception e) {
logger.error("Problem occured while generating MathJax png", e);
throw new RuntimeException(e);
}
});
}
} catch (Exception e) {
logger.error("Problem occured while generating MathJax png", e);
throw e;
}
}
}