package com.jetbrains.python.edu.debugger;

import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunnerLayoutUi;
import com.intellij.execution.ui.actions.CloseAction;
import com.intellij.ide.actions.ContextHelpAction;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerBundle;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
import com.jetbrains.python.debugger.PyDebugProcess;
import com.jetbrains.python.debugger.PyDebugRunner;
import com.jetbrains.python.debugger.PyLineBreakpointType;
import com.jetbrains.python.run.PythonCommandLineState;
import com.jetbrains.python.run.PythonRunConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.net.ServerSocket;

public class PyEduDebugRunner extends PyDebugRunner {
  private static final Logger LOG = Logger.getInstance(PyEduDebugRunner.class);
  public static final int NO_LINE = -1;

  @Override
  public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
    return executorId.equals(PyEduDebugExecutor.ID);
  }

  @NotNull
  @Override
  protected PyDebugProcess createDebugProcess(@NotNull XDebugSession session,
                                              ServerSocket serverSocket,
                                              ExecutionResult result,
                                              PythonCommandLineState pyState) {
    ExecutionConsole executionConsole = result.getExecutionConsole();
    ProcessHandler processHandler = result.getProcessHandler();
    boolean isMultiProcess = pyState.isMultiprocessDebug();
    String scriptName = getScriptName(pyState);
    if (scriptName != null) {
      VirtualFile file = VfsUtil.findFileByIoFile(new File(scriptName), true);
      if (file != null) {
        int line = getBreakpointLineNumber(file, session.getProject());
        if (line != NO_LINE) {
          return new PyEduDebugProcess(session, serverSocket,
                                       executionConsole, processHandler,
                                       isMultiProcess, scriptName, line + 1);
        }
      }
    }
    LOG.info("Failed to create PyEduDebugProcess. PyDebugProcess created instead.");
    return new PyDebugProcess(session, serverSocket, executionConsole,
                              processHandler, isMultiProcess);
  }

  @Nullable
  private static String getScriptName(PythonCommandLineState pyState) {
    ExecutionEnvironment environment = pyState.getEnvironment();
    if (environment == null) {
      return null;
    }
    RunProfile runProfile = environment.getRunProfile();
    if (runProfile instanceof PythonRunConfiguration) {
      String name = FileUtil.toSystemIndependentName(((PythonRunConfiguration)runProfile).getScriptName());
      return SystemInfo.isWindows ? name.toLowerCase() : name;
    }
    return null;
  }

  /**
   * @return the smallest line (from 0 to line number) suitable to set breakpoint on it, NO_LINE if there is no such line in the file
   */
  private static int getBreakpointLineNumber(@NotNull final VirtualFile file, @NotNull final Project project) {
    Document document = FileDocumentManager.getInstance().getDocument(file);
    if (document == null) {
      return NO_LINE;
    }
    PyLineBreakpointType lineBreakpointType = new PyLineBreakpointType();
    for (int line = 0; line < document.getLineCount(); line++) {
      if (lineBreakpointType.canPutAt(file, line, project)) {
        return line;
      }
    }
    return NO_LINE;
  }


  @Override
  protected void initSession(XDebugSession session, RunProfileState state, Executor executor) {
    XDebugSessionTab tab = ((XDebugSessionImpl)session).getSessionTab();
    if (tab != null) {
      RunnerLayoutUi ui = tab.getUi();
      ContentManager contentManager = ui.getContentManager();
      Content content = findContent(contentManager, XDebuggerBundle.message("debugger.session.tab.console.content.name"));
      if (content != null) {
        ExecutionConsole console = session.getDebugProcess().createConsole();
        PythonDebugLanguageConsoleView view = (PythonDebugLanguageConsoleView)console;
        Presentation presentation = view.getSwitchConsoleActionPresentation();
        ToggleAction action = new ToggleAction(presentation.getText(), presentation.getDescription(), presentation.getIcon()) {

          @Override
          public boolean isSelected(AnActionEvent e) {
            return !view.isPrimaryConsoleEnabled();
          }

          @Override
          public void setSelected(AnActionEvent e, boolean state) {
            view.enableConsole(!state);
          }
        };
        content.setActions(new DefaultActionGroup(action), ActionPlaces.DEBUGGER_TOOLBAR, view.getPreferredFocusableComponent());
      }
      patchLeftToolbar(session, ui);
    }
  }

  private static void patchLeftToolbar(@NotNull XDebugSession session, @NotNull RunnerLayoutUi ui) {
    DefaultActionGroup newLeftToolbar = new DefaultActionGroup();

    DefaultActionGroup firstGroup = new DefaultActionGroup();
    addActionToGroup(firstGroup, XDebuggerActions.RESUME);
    addActionToGroup(firstGroup, IdeActions.ACTION_STOP_PROGRAM);
    newLeftToolbar.addAll(firstGroup);

    newLeftToolbar.addSeparator();

    Executor executor = PyEduDebugExecutor.getInstance();
    newLeftToolbar.add(new CloseAction(executor, session.getRunContentDescriptor(), session.getProject()));
    //TODO: return proper helpID
    newLeftToolbar.add(new ContextHelpAction(executor.getHelpId()));

    ui.getOptions().setLeftToolbar(newLeftToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
  }

  private static void addActionToGroup(DefaultActionGroup group, String actionId) {
    AnAction action = ActionManager.getInstance().getAction(actionId);
    if (action != null) {
      action.getTemplatePresentation().setEnabled(true);
      group.add(action, Constraints.LAST);
    }
  }

  @Nullable
  private static Content findContent(ContentManager manager, String name) {
    for (Content content : manager.getContents()) {
      if (content.getDisplayName().equals(name)) {
        return content;
      }
    }
    return null;
  }
}
@@ -515,59 +515,8 @@
 on;%0A
-import com.intellij.ide.actions.ContextHelpAction;%0A
 impo
@@ -5771,24 +5771,110 @@
 mponent());%0A
+        //TODO: return proper helpID%0A        content.setHelpId(executor.getHelpId());%0A
       %7D%0A    
@@ -6517,110 +6517,8 @@
 )));
-%0A    //TODO: return proper helpID%0A    newLeftToolbar.add(new ContextHelpAction(executor.getHelpId()));
 %0A%0A  

remove help button from PyEdu debugger TW