package org.smartly.application.desktopgap.impl.app.applications;
import org.json.JSONArray;
import org.json.JSONObject;
import org.smartly.application.desktopgap.impl.app.DesktopController;
import org.smartly.application.desktopgap.impl.app.applications.events.AppCloseEvent;
import org.smartly.application.desktopgap.impl.app.applications.events.AppOpenEvent;
import org.smartly.application.desktopgap.impl.app.applications.window.AppInstance;
import org.smartly.application.desktopgap.impl.app.applications.window.AppManifest;
import org.smartly.commons.event.Event;
import org.smartly.commons.event.IEventListener;
import org.smartly.commons.util.CollectionUtils;
import org.smartly.commons.util.JsonWrapper;
import java.io.IOException;
import java.util.*;
/**
*
*/
public final class DesktopControllerApps
implements IEventListener {
// ------------------------------------------------------------------------
// f i e l d s
// ------------------------------------------------------------------------
private final DesktopController _desktop;
private final Map<String, AppInstance> _registry_running;
private final Map<String, AppManifest> _registry_installed;
private final Map<String, String> _registry_invalid; // invalid applications paths and errors
private final Set<String> _system_apps; // system apps
// ------------------------------------------------------------------------
// c o n s t r u c t o r
// ------------------------------------------------------------------------
public DesktopControllerApps(final DesktopController desktop) {
_desktop = desktop;
_registry_running = Collections.synchronizedMap(new HashMap<String, AppInstance>());
_registry_installed = Collections.synchronizedMap(new HashMap<String, AppManifest>());
_registry_invalid = Collections.synchronizedMap(new HashMap<String, String>());
_system_apps = Collections.synchronizedSet(new HashSet<String>());
}
// ------------------------------------------------------------------------
// p u b l i c
// ------------------------------------------------------------------------
public Collection<String> getAppIdByName(final String appName) {
final Collection<String> result = new ArrayList<String>();
synchronized (_registry_installed) {
final Collection<AppManifest> manifests = _registry_installed.values();
for (final AppManifest manifest : manifests) {
if (manifest.getAppName().equalsIgnoreCase(appName)) {
result.add(manifest.getAppId());
}
}
}
return result;
}
public AppInstance getApplication(final String appId) throws IOException {
// lookup using app_id
AppInstance result = this.getApplicationById(appId);
if(null==result){
// lookup using app_name
result = getApplicationById(CollectionUtils.getFirst(this.getAppIdByName(appId)));
}
return result;
}
public void closeApplication(final String appId) throws IOException {
if (this.isRunning(appId)) {
this.getRunning(appId).close();
}
}
public Collection<String> getSystemAppNames() {
synchronized (_system_apps) {
return new ArrayList<String>(_system_apps);
}
}
/**
* Returns App names, excluding system apps
*
* @return collection of app names.
*/
public Collection<String> getAppNames() {
synchronized (_registry_installed) {
final Collection<String> result = new ArrayList<String>();
final Set<String> keys = _registry_installed.keySet();
for (final String appId : keys) {
if (!_system_apps.contains(appId)) {
result.add(appId);
}
}
return result;
}
}
/**
* Returns Apps manifest grouped by category.
*
* @return A Map of App manifests grouped by category.
*/
public Map<String, List<AppManifest>> getAppManifests() {
synchronized (_registry_installed) {
final Map<String, List<AppManifest>> result = new LinkedHashMap<String, List<AppManifest>>();
final Set<String> keys = _registry_installed.keySet();
for (final String appId : keys) {
if (!_system_apps.contains(appId)) {
final AppManifest manifest = _registry_installed.get(appId);
final String category = manifest.getCategory();
if (!result.containsKey(category)) {
result.put(category, new LinkedList<AppManifest>());
}
result.get(category).add(manifest);
}
}
return result;
}
}
public JSONObject getAppManifestsAsJSON() {
synchronized (_registry_installed) {
final JsonWrapper result = new JsonWrapper(new JSONObject());
final Set<String> keys = _registry_installed.keySet();
for (final String appId : keys) {
if (!_system_apps.contains(appId)) {
final AppManifest manifest = _registry_installed.get(appId);
final String category = manifest.getCategory();
if (!result.has(category)) {
result.putSilent(category, new JSONArray());
}
result.optJSONArray(category).put(manifest.getJson().getJSONObject());
}
}
return result.getJSONObject();
}
}
/**
* Return array of strings with a list of invalid applications paths
*
* @return Array of Strings in JSON format
*/
public JSONObject getInvalidApplications() {
final JSONObject result = new JSONObject();
if (!_registry_invalid.isEmpty()) {
final Set<String> keys = _registry_invalid.keySet();
for (final String path : keys) {
JsonWrapper.put(result, path, _registry_invalid.get(path));
}
}
return result;
}
// --------------------------------------------------------------------
// installed
// --------------------------------------------------------------------
public AppManifest getInstalled(final String appId) {
synchronized (_registry_installed) {
return _registry_installed.get(appId);
}
}
public AppManifest removeInstalled(final String appId) {
synchronized (_registry_installed) {
return _registry_installed.remove(appId);
}
}
public void addInstalled(final String file, final boolean system) throws IOException {
synchronized (_registry_installed) {
final AppManifest manifest = new AppManifest(file);
if (manifest.isValid()) {
_registry_installed.put(manifest.getAppId(), manifest);
if (system) {
this.addSystem(manifest.getAppId());
}
} else {
//-- found invalid manifest --//
_registry_invalid.put(file, manifest.getErrorMessage());
}
}
}
public void addInstalled(final AppManifest manifest) {
synchronized (_registry_installed) {
_registry_installed.put(manifest.getAppId(), manifest);
}
}
public boolean isInstalled(final String appId) {
synchronized (_registry_installed) {
return _registry_installed.containsKey(appId);
}
}
// --------------------------------------------------------------------
// running
// --------------------------------------------------------------------
public AppInstance getRunning(final String appId) {
synchronized (_registry_running) {
return _registry_running.get(appId);
}
}
public boolean isRunning(final String appId) {
synchronized (_registry_running) {
return _registry_running.containsKey(appId);
}
}
public void closeRunning() {
synchronized (_registry_running) {
final Collection<AppInstance> apps = _registry_running.values();
for (final AppInstance app : apps) {
try {
app.close();
} catch (Throwable ignored) {
}
}
_registry_running.clear();
}
}
public void killRunning() {
synchronized (_registry_running) {
final Collection<AppInstance> apps = _registry_running.values();
for (final AppInstance app : apps) {
try {
app.kill();
} catch (Throwable ignored) {
}
}
_registry_running.clear();
}
}
// ------------------------------------------------------------------------
// IEventListener
// ------------------------------------------------------------------------
@Override
public void on(final Event event) {
if (event instanceof AppCloseEvent) {
// FRAME CLOSE
this.handleCloseApp((AppInstance) event.getSender());
} else if (event instanceof AppOpenEvent) {
// FRAME OPEN
this.handleOpenApp((AppInstance) event.getSender());
}
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private void addSystem(final String appId) {
synchronized (_system_apps) {
_system_apps.add(appId);
}
}
private AppInstance createApp(final AppManifest manifest) throws IOException {
final AppInstance app = new AppInstance(_desktop, manifest);
app.addEventListener(this);
return app;
}
private void handleOpenApp(final AppInstance app) {
synchronized (_registry_running) {
if (!_registry_running.containsKey(app.getId())) {
// register new app instance
_registry_running.put(app.getId(), app);
}
}
}
private void handleCloseApp(final AppInstance app) {
synchronized (_registry_running) {
if (_registry_running.containsKey(app.getId())) {
// register new app instance
_registry_running.remove(app.getId());
}
}
}
public AppInstance getApplicationById(final String appId) throws IOException {
if (this.isRunning(appId)) {
return this.getRunning(appId);
} else {
final AppManifest manifest = this.getInstalled(appId);
return this.createApp(manifest);
}
}
}