package org.smartly.application.desktopgap.impl.app;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import org.json.JSONObject;
import org.smartly.Smartly;
import org.smartly.application.desktopgap.DesktopGap;
import org.smartly.application.desktopgap.impl.app.applications.DesktopControllerApps;
import org.smartly.application.desktopgap.impl.app.applications.autorun.AppAutorunManager;
import org.smartly.application.desktopgap.impl.app.applications.window.AppManifest;
import org.smartly.application.desktopgap.impl.app.applications.window.frame.AppFrame;
import org.smartly.application.desktopgap.impl.app.server.WebServer;
import org.smartly.application.desktopgap.impl.app.utils.Utils;
import org.smartly.commons.io.FileObserver;
import org.smartly.commons.io.IFileObserverListener;
import org.smartly.commons.logging.Level;
import org.smartly.commons.util.FileUtils;
import org.smartly.commons.util.PathUtils;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Main Application Controller.
*/
public final class DesktopController
extends Application
implements IFileObserverListener {
private static final String INSTALLED_STORE_DIR = IDesktopConstants.INSTALLED_STORE_DIR;
private static final String INSTALLED_SYSTEM_DIR = IDesktopConstants.INSTALLED_SYSTEM_DIR;
private static final String INSTALL_DIR = IDesktopConstants.INSTALL_DIR;
private static final String TEMP_DIR = IDesktopConstants.TEMP_DIR;
private final AppAutorunManager _autorun;
private final String _root_install; // auto-install root
private final String _root_installed_store; // installed apps
private final String _root_installed_system;
private final String _root_temp; // temp
private final DesktopControllerApps _applications;
private FileObserver _installObserver;
private boolean _closed;
private Stage _stage;
private Text _text;
public DesktopController() throws IOException {
_root_install = Smartly.getAbsolutePath(INSTALL_DIR);
_root_installed_store = Smartly.getAbsolutePath(INSTALLED_STORE_DIR);
_root_installed_system = Smartly.getAbsolutePath(INSTALLED_SYSTEM_DIR);
_root_temp = Smartly.getAbsolutePath(TEMP_DIR);
_applications = new DesktopControllerApps(this);
_autorun = new AppAutorunManager(_applications);
_closed = false;
// inject controller into webserver
_webserver.setDesktop(this);
}
@Override
public void start(final Stage primaryStage) throws Exception {
_stage = primaryStage;
//primaryStage.initStyle(StageStyle.TRANSPARENT);
/*
_text = new Text("Transparent!");
_text.setFont(new Font(40));
StackPane root = new StackPane();
//VBox box = new VBox();
root.getChildren().add(_text);
final Scene scene = new Scene(root, 400, 400);
scene.setFill(null);
primaryStage.setScene(scene);
primaryStage.show();*/
this.startApplication();
}
/**
* Stop desktop and close all running applications.
*
* @throws Exception
*/
@Override
public void stop() throws Exception {
super.stop();
System.exit(0);
}
public void close() {
_closed = true;
// stop internal webserver
try {
WebServer.getInstance().stop();
} catch (Throwable ignored) {
}
try {
if (null != _installObserver) {
_installObserver.stopWatching();
}
} catch (Throwable ignored) {
}
// kill all running applications
try {
_applications.killRunning();
} catch (Throwable ignored) {
}
Platform.exit();
}
public boolean isClosed() {
return _closed;
}
/**
* Returns Application Primary Stage
* @return
*/
public Stage getStage() {
return _stage;
}
/**
* Install and Launch Application
*
* @param path Application file path. i.e. "c:\app\my_app.dga", or Application folder path.
*/
public AppFrame launch(final String path, final String winId) throws IOException {
if (this.isClosed()) {
return null;
}
if (Utils.isPackage(path)) {
return this.launchPackage(path, winId);
} else {
return this.launchApp(path, winId);
}
}
public Collection<String> getApplicationNames() {
return _applications.getAppNames();
}
public Map<String, List<AppManifest>> getApplicationManifests() {
return _applications.getAppManifests();
}
public JSONObject getApplicationManifestsAsJSON() {
return _applications.getAppManifestsAsJSON();
}
/**
* Returns Manifest of installed application
*
* @param appId AppId
* @return Manifest
*/
public AppManifest getApplicationManifest(final String appId) {
return _applications.getInstalled(appId);
}
// ------------------------------------------------------------------------
// IFileObserverListener (install dir)
// ------------------------------------------------------------------------
@Override
public void onEvent(final int event, final String path) {
if (this.isClosed()) {
return;
}
Platform.runLater(new Runnable() {
@Override
public void run() {
try {
final String clean_path = PathUtils.toUnixPath(path);
if (null != launchPackage(clean_path, null)) {
// remove package
FileUtils.delete(clean_path);
}
} catch (Throwable t) {
log(Level.SEVERE, null, t);
}
}
});
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private void log(final Level level, final String msg, final Throwable t) {
if (null != _text) {
_text.setText(msg);
}
}
private void startApplication() throws IOException {
//-- ensure for program files folder --//
FileUtils.mkdirs(_root_install);
FileUtils.mkdirs(_root_installed_store);
FileUtils.mkdirs(_root_installed_system);
FileUtils.mkdirs(_root_temp);
//-- init fonts--//
DesktopFonts.init();
//-- observer --//
_installObserver = new FileObserver(_root_install, false, false, FileObserver.EVENT_CREATE, this);
_installObserver.startWatching();
//-- scan install folder for existing files --//
final Set<String> to_install = Utils.getFiles(_root_install);
for (final String file : to_install) {
this.installPackage(file);
}
//-- STORE: scan installed folder and creates registry --//
final Set<String> installed = Utils.getDirectories(_root_installed_store);
for (final String file : installed) {
_applications.addInstalled(file, false);
}
//-- SYSTEM: scan installed folder and creates registry --//
final Set<String> installed_sys = Utils.getDirectories(_root_installed_system);
for (final String file : installed_sys) {
_applications.addInstalled(file, true);
}
//-- autorun --//
this.initAutorun();
//-- launch args file --//
launchArgFiles();
}
private void initAutorun() {
_autorun.onAutorun(new AppAutorunManager.OnAutorun() {
@Override
public void handle(final String appId) {
launchAppLater(appId);
}
});
_autorun.run();
}
private AppManifest installPackage(final String packagePath) throws IOException {
synchronized (_applications) {
final AppManifest manifest = new AppManifest(packagePath);
final String appId = manifest.getAppId();
// check if installed and update or install from scratch
if (_applications.isInstalled(appId)) {
//-- update --//
final AppManifest old_manifest = new AppManifest(manifest.getInstallDir());
if (manifest.isGreaterThan(old_manifest)) {
// close existing instance
_applications.closeApplication(appId);
// overwrite
Utils.install(packagePath, manifest.getInstallDir());
_applications.addInstalled(manifest); // REGISTER NEW
} else {
// returns existing app instance
return _applications.getInstalled(appId);
}
} else {
//-- install --//
Utils.install(packagePath, manifest.getInstallDir());
_applications.addInstalled(manifest); // REGISTER NEW
}
return _applications.getInstalled(appId);
}
}
/**
* Apps can be singleton or multiple instance depends on MANIFEST.json file
*
* @param packagePath Application Package Path. i.e. "c:/myapp/app.dga"
*/
private AppFrame launchPackage(final String packagePath,
final String winId) throws IOException {
if (this.isClosed()) {
return null;
}
final AppManifest manifest = this.installPackage(packagePath);
//-- ready to run app --//
return this.launchApp(manifest.getAppId(), winId);
}
private void launchAppLater(final String appId) {
if (this.isClosed()) {
return;
}
Platform.runLater(new Runnable() {
@Override
public void run() {
try {
launchApp(appId, null);
} catch (Throwable t) {
log(Level.SEVERE, null, t);
}
}
});
}
private AppFrame launchApp(final String appId,
final String winId) throws IOException {
if (this.isClosed()) {
return null;
}
if (_applications.isInstalled(appId)) {
return _applications.getApplication(appId).open(winId);
}
return null;
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
// --------------------------------------------------------------------
// S T A T I C
// --------------------------------------------------------------------
private static final DesktopControllerArgs s_app_args = new DesktopControllerArgs();
private static WebServer _webserver;
private static boolean isAlreadyRunning() {
if (null == _webserver) {
_webserver = WebServer.getInstance();
try {
_webserver.start();
return false;
} catch (Throwable ignored) {
}
}
return true;
}
private static void launchArgFiles() throws IOException {
//-- parse launch args --//
s_app_args.parse(DesktopGap.getLauncherRemainArgs());
final Set<String> files = s_app_args.getFiles();
if (!files.isEmpty()) {
for (final String file : files) {
Utils.copyToInstallFolder(PathUtils.toUnixPath(file), s_app_args.isInstall());
}
}
// LoggingUtils.getLogger(AppController.class).info("FILES: " + files.toString());
}
public static void open() throws Exception {
// LoggingUtils.getLogger(AppController.class).info("OPENING");
//-- check if abother instance is already running and start main --//
if (!isAlreadyRunning()) {
DesktopController.launch(DesktopController.class);
} else {
launchArgFiles();
}
}
public static void open(final boolean allowMultiple) throws Exception {
if (!allowMultiple) {
open();
} else {
_webserver = WebServer.getInstance(true);
_webserver.start();
DesktopController.launch(DesktopController.class);
}
}
}