/*
 * Copyright 2018 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
package io.flutter.editor;

import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.EditorNotificationPanel;
import com.intellij.ui.EditorNotifications;
import icons.FlutterIcons;
import io.flutter.actions.ActionWithAnalytics;
import io.flutter.actions.OpenInXcodeAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class NativeEditorNotificationProvider extends EditorNotifications.Provider<EditorNotificationPanel> implements DumbAware {
  private static final Key<EditorNotificationPanel> KEY = Key.create("flutter.native.editor.notification");

  private static final ActionWithAnalytics OPEN_IN_XCODE_ACTION = new OpenInXcodeAction() {
    @NotNull
    @Override
    public String getAnalyticsId() {
      return "OpenInXcode.banner";
    }
  };

  private static final ActionWithAnalytics OPEN_IN_ANDROID_STUDIO_ACTION = new OpenInXcodeAction() {
    @NotNull
    @Override
    public String getAnalyticsId() {
      return "OpenInAndroidStudio.banner";
    }
  };

  private final Project myProject;

  public NativeEditorNotificationProvider(@NotNull Project project) {
    myProject = project;
  }

  @NotNull
  @Override
  public Key<EditorNotificationPanel> getKey() {
    return KEY;
  }

  @Nullable
  @Override
  public EditorNotificationPanel createNotificationPanel(@NotNull VirtualFile file, @NotNull FileEditor fileEditor) {
    if (!file.isInLocalFileSystem()) {
      return null;
    }
    return createPanelForFile(file, findRootDir(file, myProject.getBaseDir()));
  }

  private EditorNotificationPanel createPanelForFile(VirtualFile file, VirtualFile root) {
    if (root == null) {
      return null;
    }
    return createPanelForAction(file, root, getAction(root));
  }

  private EditorNotificationPanel createPanelForAction(VirtualFile file, VirtualFile root, AnAction action) {
    if (action == null) {
      return null;
    }
    NativeEditorActionsPanel panel = new NativeEditorActionsPanel(file, root, action);
    return panel.isValidForFile() ? panel : null;
  }

  private static AnAction getAction(VirtualFile root) {
    if (root == null) {
      return null;
    }
    if (root.getName().equals("android")) {
      return OPEN_IN_ANDROID_STUDIO_ACTION;
    }
    else if (root.getName().equals("ios")) {
      return OPEN_IN_XCODE_ACTION;
    }
    else {
      return null;
    }
  }

  private static VirtualFile findRootDir(@NotNull VirtualFile file, VirtualFile projectDir) {
    // Return the top-most parent of file that is a child of the project directory.
    VirtualFile parent = file.getParent();
    if (projectDir.equals(parent)) {
      return null;
    }
    VirtualFile root = parent;
    while (parent != null) {
      parent = parent.getParent();
      if (projectDir.equals(parent)) {
        return root;
      }
      root = parent;
    }
    return null;
  }

  class NativeEditorActionsPanel extends EditorNotificationPanel {
    final VirtualFile myFile;
    final VirtualFile myRoot;
    final AnAction myAction;
    final boolean isVisible;

    NativeEditorActionsPanel(VirtualFile file, VirtualFile root, AnAction openAction) {
      super(EditorColors.GUTTER_BACKGROUND);
      myFile = file;
      myRoot = root;
      myAction = openAction;

      icon(FlutterIcons.Flutter);
      text("Flutter commands");

      // Ensure this project is a Flutter project by updating the menu action. It will only be visible for Flutter projects.
      myAction.update(AnActionEvent.createFromDataContext(ActionPlaces.EDITOR_TOOLBAR, myAction.getTemplatePresentation(), makeContext()));
      isVisible = myAction.getTemplatePresentation().isVisible();
      createActionLabel(myAction.getTemplatePresentation().getText(), this::performAction)
        .setToolTipText(myAction.getTemplatePresentation().getDescription());
    }

    private boolean isValidForFile() {
      if (isVisible) {
        // The menu items are visible for certain elements outside the module directories.
        return FileUtil.isAncestor(myRoot.getPath(), myFile.getPath(), true);
      }
      return false;
    }

    private void performAction() {
      // Open Xcode or Android Studio. If already running AS then just open a new window.
      myAction.actionPerformed(
        AnActionEvent.createFromDataContext(ActionPlaces.EDITOR_TOOLBAR, myAction.getTemplatePresentation(), makeContext()));
    }

    private DataContext makeContext() {
      return dataId -> {
        if (CommonDataKeys.VIRTUAL_FILE.is(dataId)) {
          return myFile;
        }
        if (CommonDataKeys.PROJECT.is(dataId)) {
          return myProject;
        }
        return null;
      };
    }
  }
}

@@ -731,16 +731,69 @@
 lytics;%0A
+import io.flutter.actions.OpenInAndroidStudioAction;%0A
 import i
@@ -1176,60 +1176,69 @@
 tic 
-final ActionWithAnalytics OPEN_IN_XCODE_ACTION = new
+class OpenInXcodeBannerAction extends OpenInXcodeAction %7B%0A   
  Ope
@@ -1237,32 +1237,38 @@
 %0A    OpenInXcode
+Banner
 Action() %7B%0A    @
@@ -1254,32 +1254,205 @@
 annerAction() %7B%0A
+      getTemplatePresentation().setText(%22Open for Editing in Xcode%22);%0A      getTemplatePresentation().setDescription(%22Open Xcode in a new window to edit this file%22);%0A    %7D%0A%0A
     @NotNull%0A   
@@ -1535,33 +1535,32 @@
 nner%22;%0A    %7D%0A  %7D
-;
 %0A%0A  private stat
@@ -1566,208 +1566,589 @@
 tic 
-final ActionWithAnalytics OPEN_IN_ANDROID_STUDIO_ACTION = new OpenInXcodeAction() %7B%0A    @NotNull%0A    @Override%0A    public String getAnalyticsId() %7B%0A      return %22OpenInAndroidStudio.banner%22;%0A    %7D%0A  %7D
+class OpenInAndroidStudioBannerAction extends OpenInAndroidStudioAction %7B%0A    OpenInAndroidStudioBannerAction() %7B%0A      // Template presentation set up in super.update()%0A      // TODO(pq): consider migrating OpenInXcodeBannerAction to do the same.%0A    %7D%0A    @NotNull%0A    @Override%0A    public String getAnalyticsId() %7B%0A      return %22OpenInAndroidStudio.banner%22;%0A    %7D%0A  %7D%0A%0A  private static final ActionWithAnalytics OPEN_IN_XCODE_ACTION = new OpenInXcodeBannerAction();%0A  private static final ActionWithAnalytics OPEN_IN_ANDROID_STUDIO_ACTION = new OpenInAndroidStudioBannerAction()
 ;%0A%0A 

Fix native editor banner presentation (#2291). (#2295)