package com.insightfullogic.honest_profiler.ports.javafx.model;
import static com.insightfullogic.honest_profiler.ports.javafx.util.ResourceUtil.format;
import static com.insightfullogic.honest_profiler.ports.javafx.util.ResourceUtil.getDefaultBundle;
import static com.insightfullogic.honest_profiler.ports.javafx.util.ResourceUtil.getDefaultLocale;
import static java.util.concurrent.Executors.newCachedThreadPool;
import static java.util.stream.Collectors.toList;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import com.insightfullogic.honest_profiler.ports.javafx.controller.RootController;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableStringValue;
import javafx.concurrent.Task;
import javafx.scene.control.Tab;
/**
* The ApplicationContext contains state which needs to be shared by all controllers in the application, and methods to
* access and change that state.
*/
public final class ApplicationContext
{
// Instance Properties
// - I18N
private Locale currentLocale;
private ResourceBundle currentBundle;
// - InfoBar current text
private SimpleStringProperty info;
// - Profile Context mappings
private Map<String, ProfileContext> nameToContextMap;
private Map<String, ProfileContext> pathToContextMap;
// - Root Controller
private RootController rootController;
// - Task Execution
private ExecutorService executorService = newCachedThreadPool();
// Instance Constructors
/**
* Create the ApplicationContext with teh specified {@link RootController}.
* <p>
*
* @param rootController the {@link RootController} for the application
*/
public ApplicationContext(RootController rootController)
{
currentLocale = getDefaultLocale();
currentBundle = getDefaultBundle();
info = new SimpleStringProperty();
this.rootController = rootController;
nameToContextMap = new HashMap<String, ProfileContext>();
pathToContextMap = new HashMap<String, ProfileContext>();
}
// Instance Accessors
/**
* Returns the id of the {@link ProfileContext} which tracks the profile based on the specified {@link File}.
* <p>
*
* @param file the {@link File} containing the Profiling Agent output
* @return the id of the {@link ProfileContext} which tracks the profile based on the specified {@link File}
*/
public Integer getContextIdByPath(File file)
{
ProfileContext ctx = pathToContextMap.get(file.getAbsolutePath());
return ctx == null ? null : ctx.getId();
}
/**
* Returns the internationalized String stored in the application {@link ResourceBundle} for the specified key based
* on the current {@link Locale}.
* <p>
*
* @param key the key for the internationalized String in the application {@link ResourceBundle}
* @return the internationalized String for the specified key
*/
public String textFor(String key)
{
return currentBundle.getString(key);
}
/**
* Returns the internationalized String constructed by looking up the specified key in the application
* {@link ResourceBundle} based on the current {@link Locale}, interpreting it as a format and formatting it using
* the specified argument.
* <p>
*
* @param key the key for the pattern in the application {@link ResourceBundle}
* @param args the arguments for formatting the pattern
* @return the constructed internationalized String
*/
public String textFor(String key, Object... args)
{
return format(currentLocale, currentBundle, key, args);
}
/**
* Set the text in the InfoBar as per {@link #textFor(String)}.
* <p>
*
* @param key the key for the internationalized String in the application {@link ResourceBundle}
*/
public void setInfoFromBundle(String key)
{
info.set(textFor(key));
}
/**
* Set the text in the InfoBar as per {@link #textFor(String, Object...)}.
* <p>
*
* @param key the key for the pattern in the application {@link ResourceBundle}
* @param args the arguments for formatting the pattern
*/
public void setInfoFromBundle(String key, Object... args)
{
info.set(textFor(key, args));
}
/**
* Clears the text in the InfoBar.
*/
public void clearInfo()
{
info.set("");
}
/**
* Returns the InfoBar {@link ObservableStringValue}.
* <p>
*
* @return the InfoBar {@link ObservableStringValue}.
*/
public ObservableStringValue getInfo()
{
return info;
}
/**
* Returns the {@link ProfileContext} with the specified name.
* <p>
*
* @param name the name of the {@link ProfileContext}
* @return the corresponding {@link ProfileContext}
*/
public ProfileContext getProfileContext(String name)
{
return nameToContextMap.get(name);
}
/**
* Registers a {@link ProfileContext} with this ApplicationContext, making it available as shared state.
* <p>
*
* @param context the {@link ProfileContext} to be registered
*/
public void registerProfileContext(ProfileContext context)
{
nameToContextMap.put(context.getName(), context);
pathToContextMap.put(context.getFile().getAbsolutePath(), context);
}
/**
* Returns a list of the names of all known {@link ProfileContext}s.
* <p>
*
* @return a list of the names of all known {@link ProfileContext}s
*/
public List<String> getOpenProfileNames()
{
return nameToContextMap.keySet().stream().sorted().collect(toList());
}
/**
* Executes a task on a background worker thread.
* <p>
*
* @param task the task to be executed
*/
public void execute(Task<?> task)
{
executorService.execute(task);
}
/**
* Stop the executorService. If this isn't called on application shutdown, the application shutdown will be held up
* for a while.
*/
public void stop()
{
this.executorService.shutdown();
}
/**
* Create a {@link Tab} containing the Diff Views for the specified profiles.
* <p>
*
* @param baseName the name of the {@link ProfileContext} for the Base profile
* @param newName the name of the {@link ProfileContext} for the New profile
*/
public void createDiffView(String baseName, String newName)
{
rootController.createDiffTab(baseName, newName);
}
}