package fr.adrienbrault.idea.symfony2plugin.profiler.widget;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.openapi.wm.impl.status.EditorBasedWidget;
import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.util.Consumer;
import fr.adrienbrault.idea.symfony2plugin.profiler.ProfilerIndexInterface;
import fr.adrienbrault.idea.symfony2plugin.profiler.collector.DefaultDataCollectorInterface;
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequestInterface;
import fr.adrienbrault.idea.symfony2plugin.profiler.factory.ProfilerFactoryUtil;
import fr.adrienbrault.idea.symfony2plugin.profiler.widget.action.SymfonyProfilerWidgetActions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.event.MouseEvent;
import java.util.*;
/**
* @author Daniel Espendiller <daniel@espendiller.net>
*/
public class SymfonyProfilerWidget extends EditorBasedWidget implements StatusBarWidget.MultipleTextValuesPresentation, StatusBarWidget.Multiframe {
public static String ID = "symfony2.profiler";
public SymfonyProfilerWidget(@NotNull Project project) {
super(project);
}
@Override
public StatusBarWidget copy() {
return new SymfonyProfilerWidget(getProject());
}
private enum ProfilerTarget {
TEMPLATE, ROUTE, CONTROLLER
}
//constructs the actions for the widget popup
public DefaultActionGroup getActions(){
DefaultActionGroup actionGroup = new DefaultActionGroup(null, false);
ProfilerIndexInterface index = ProfilerFactoryUtil.createIndex(getProject());
if(index == null) {
return actionGroup;
}
List<ProfilerRequestInterface> requests = index.getRequests();
Collection<AnAction> templateActions = new ArrayList<>();
Map<String, Integer> templateActionsMap = new HashMap<>();
Collection<AnAction> routeActions = new ArrayList<>();
Map<String, Integer> routeActionsMap = new HashMap<>();
Collection<AnAction> controllerActions = new ArrayList<>();
Map<String, Integer> controllerActionsMap = new HashMap<>();
Collection<AnAction> urlActions = new ArrayList<>();
Collection<AnAction> mailActions = new ArrayList<>();
for(ProfilerRequestInterface profilerRequest : requests) {
urlActions.add(new SymfonyProfilerWidgetActions.UrlAction(index, profilerRequest));
DefaultDataCollectorInterface collector = profilerRequest.getCollector(DefaultDataCollectorInterface.class);
if(collector != null) {
attachProfileItem(templateActions, templateActionsMap, collector.getTemplate(), ProfilerTarget.TEMPLATE);
attachProfileItem(routeActions, routeActionsMap, collector.getRoute(), ProfilerTarget.ROUTE);
attachProfileItem(controllerActions, controllerActionsMap, collector.getController(), ProfilerTarget.CONTROLLER);
}
// @TODO: use collector
//String content = profilerRequest.getContent();
//if(content != null && content.contains("Swift_Mime_Headers_MailboxHeader")) {
// mailActions.add(new SymfonyProfilerWidgetActions.UrlAction(getProject(), profilerRequest, statusCode).withPanel("swiftmailer").withIcon(Symfony2Icons.MAIL));
//}
}
// routes
if(urlActions.size() > 0) {
actionGroup.addSeparator("Debug-Url");
actionGroup.addAll(urlActions);
}
// mails send by request
if(mailActions.size() > 0) {
actionGroup.addSeparator("E-Mail");
actionGroup.addAll(mailActions);
}
// routes
if(routeActions.size() > 0) {
actionGroup.addSeparator("Routes");
actionGroup.addAll(routeActions);
}
// controller methods
if(controllerActions.size() > 0) {
actionGroup.addSeparator("Controller");
actionGroup.addAll(controllerActions);
}
// template should be most use case; so keep it in cursor range
if(templateActions.size() > 0) {
actionGroup.addSeparator("Template");
actionGroup.addAll(templateActions);
}
return actionGroup;
}
private void attachProfileItem(Collection<AnAction> controllerActions, Map<String, Integer> controllerActionsMap, @Nullable String collectString, ProfilerTarget profilerTarget) {
if(collectString == null) {
return;
}
if(controllerActionsMap.containsKey(collectString)) {
controllerActionsMap.put(collectString, controllerActionsMap.get(collectString));
} else {
controllerActionsMap.put(collectString, 0);
if(profilerTarget == ProfilerTarget.CONTROLLER) {
controllerActions.add(new SymfonyProfilerWidgetActions.MethodAction(getProject(), collectString));
}
if(profilerTarget == ProfilerTarget.ROUTE) {
controllerActions.add(new SymfonyProfilerWidgetActions.RouteAction(getProject(), collectString));
}
if(profilerTarget == ProfilerTarget.TEMPLATE) {
controllerActions.add(new SymfonyProfilerWidgetActions.TemplateAction(getProject(), collectString));
}
}
}
@Nullable
@Override
public ListPopup getPopupStep() {
ActionGroup popupGroup = getActions();
return new PopupFactoryImpl.ActionGroupPopup("Symfony Profiler", popupGroup, SimpleDataContext.getProjectContext(getProject()), false, false, false, true, null, -1, null, null);
}
@Nullable
@Override
public String getSelectedValue() {
return "Symfony";
}
@NotNull
@Override
public String getMaxValue() {
return "";
}
@NotNull
@Override
public String ID() {
return ID;
}
@Nullable
@Override
public WidgetPresentation getPresentation(@NotNull PlatformType platformType) {
return this;
}
@Nullable
@Override
public String getTooltipText() {
return "Symfony Profiler";
}
@Nullable
@Override
public Consumer<MouseEvent> getClickConsumer() {
return null;
}
@Override
public void selectionChanged(@NotNull FileEditorManagerEvent event) {
update(event.getManager().getProject());
}
@Override
public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
update(source.getProject());
}
@Override
public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
update(source.getProject());
}
public void update(final Project project) {
ApplicationManager.getApplication().invokeLater(() -> {
if ((getProject() == null) || getProject().isDisposed()) {
return;
}
if (!isDisposed() && myStatusBar != null) {
myStatusBar.updateWidget(ID());
}
});
}
}