package com.intellij.openapi.vcs.actions;

import com.intellij.ide.actions.QuickSwitchSchemeAction;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsBundle;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Roman.Chernyatchik
 *
 * Context aware VCS actions quick list.
 * May be customized using com.intellij.openapi.vcs.actions.VcsQuickListContentProvider extension point.
 */
public class VcsQuickListPopupAction extends QuickSwitchSchemeAction implements DumbAware {

  protected void fillActions(@Nullable final Project project,
                             final DefaultActionGroup group,
                             @Nullable final DataContext dataContext) {

    if (project == null) {
      return;
    }

    final Pair<SupportedVCS, AbstractVcs> typeAndVcs = getActiveVCS(project, dataContext);
    final AbstractVcs vcs = typeAndVcs.getSecond();
    final SupportedVCS popupType = typeAndVcs.getFirst();

    switch (popupType) {
      case VCS:
        fillVcsPopup(project, group, dataContext, vcs);
        break;

      case NOT_IN_VCS:
        fillNonInVcsActions(project, group, dataContext);
        break;
    }
  }

  protected boolean isEnabled() {
    return true;
  }

  private void fillVcsPopup(@NotNull final Project project,
                                    @NotNull final DefaultActionGroup group,
                                    @Nullable final DataContext dataContext,
                                    @Nullable final AbstractVcs vcs) {

    if (vcs != null) {
      // replace general vcs actions if necessary

      for (VcsQuickListContentProvider provider : VcsQuickListContentProvider.EP_NAME.getExtensions()) {
        if (provider.replaceVcsActionsFor(vcs, dataContext)) {
          final List<AnAction> actionsToReplace = provider.getVcsActions(project, vcs, dataContext);
          if (actionsToReplace != null) {
            // replace general actions with custom ones:
            addActions(actionsToReplace, group);
            // local history
            addLocalHistoryActions(group);
            return;
          }
        }
      }
    }

    // general list
    fillGeneralVcsPopup(project, group, dataContext, vcs);
  }

  private void fillGeneralVcsPopup(@NotNull final Project project,
                                   @NotNull final DefaultActionGroup group,
                                   @Nullable final DataContext dataContext,
                                   @Nullable final AbstractVcs vcs) {

    // include all custom actions in general popup
    final List<AnAction> actions = new ArrayList<AnAction>();
    for (VcsQuickListContentProvider provider : VcsQuickListContentProvider.EP_NAME.getExtensions()) {
      final List<AnAction> providerActions = provider.getVcsActions(project, vcs, dataContext);
      if (providerActions != null) {
        actions.addAll(providerActions);
      }
    }

    // basic operations
    addSeparator(group, vcs != null ? vcs.getDisplayName() : null);
    addAction("ChangesView.AddUnversioned", group);
    addAction("CheckinProject", group);
    addAction("CheckinFiles", group);
    addAction("ChangesView.Rollback", group);

    // history and compare
    addSeparator(group);
    addAction("Vcs.ShowTabbedFileHistory", group);
    addAction("Annotate", group);
    addAction("Compare.SameVersion", group);

    // custom actions
    addSeparator(group);
    addActions(actions, group);

    // additional stuff
    addSeparator(group);
    addAction("MoveToChangeList", group);

    // local history
    addLocalHistoryActions(group);
  }

  private void fillNonInVcsActions(@NotNull final Project project,
                                   @NotNull final DefaultActionGroup group,
                                   @Nullable final DataContext dataContext) {
    // add custom vcs actions
    for (VcsQuickListContentProvider provider : VcsQuickListContentProvider.EP_NAME.getExtensions()) {
      final List<AnAction> actions = provider.getNotInVcsActions(project, dataContext);
      if (actions != null) {
        addActions(actions, group);
      }
    }
    addSeparator(group);
    addAction("Start.Use.Vcs", group);
    addAction("Vcs.Checkout", group);
  }

  private void addLocalHistoryActions(DefaultActionGroup group) {
    addSeparator(group, VcsBundle.message("vcs.quicklist.pupup.section.local.history"));

    addAction("LocalHistory.ShowHistory", group);
    addAction("LocalHistory.PutLabel", group);
  }

  private void addActions(@NotNull final List<AnAction> actions,
                             @NotNull final DefaultActionGroup toGroup) {
    for (AnAction action : actions) {
      toGroup.addAction(action);
    }
  }

  private Pair<SupportedVCS, AbstractVcs> getActiveVCS(@NotNull final Project project, @Nullable final DataContext dataContext) {
    final AbstractVcs[] activeVcss = getActiveVCSs(project);
    if (activeVcss.length == 0) {
      // no vcs
      return new Pair<SupportedVCS, AbstractVcs>(SupportedVCS.NOT_IN_VCS, null);
    } else if (activeVcss.length == 1) {
      // get by name
      return new Pair<SupportedVCS, AbstractVcs>(SupportedVCS.VCS, activeVcss[0]);
    }

    // by current file
    final VirtualFile file =  dataContext != null ? PlatformDataKeys.VIRTUAL_FILE.getData(dataContext) : null;
    if (file != null) {
      final AbstractVcs vscForFile = ProjectLevelVcsManager.getInstance(project).getVcsFor(file);
      if (vscForFile != null) {
        return new Pair<SupportedVCS, AbstractVcs>(SupportedVCS.VCS, vscForFile);
      }
    }

    return new Pair<SupportedVCS, AbstractVcs>(SupportedVCS.VCS, null);
  }

  private AbstractVcs[] getActiveVCSs(final Project project) {
    final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project);
    return vcsManager.getAllActiveVcss();
  }

  private void addAction(final String actionId, final DefaultActionGroup toGroup) {
    final AnAction action = ActionManager.getInstance().getAction(actionId);

    // add action to group if it is available
    if (action != null) {
      toGroup.add(action);
    }
  }

  private void addSeparator(final DefaultActionGroup toGroup) {
    addSeparator(toGroup, null);
  }

  private void addSeparator(final DefaultActionGroup toGroup, @Nullable final String title) {
    final Separator separator = title == null ? new Separator() : new Separator(title);
    toGroup.add(separator);
  }

  protected String getPopupTitle(AnActionEvent e) {
    return VcsBundle.message("vcs.quicklist.pupup.title");
  }

  public enum SupportedVCS {
    VCS,
    NOT_IN_VCS
  }
}

@@ -4581,32 +4581,89 @@
 eckout%22, group);
+%0A%0A    // local history%0A    addLocalHistoryActions(group);
 %0A  %7D%0A%0A  private 

add "Local History" actions to VCS Popup even if VCS isn't configured