/*
   * Expands and returns the location attribute of the given launch configuration. The location is verified to point
   * to an existing file, in the local file system.
   *
   * @param configuration launch configuration
   *
   * @return an absolute path to a file in the local file system
   *
   * @throws CoreException if unable to retrieve the associated launch configuration attribute, if unable to resolve
   * any variables, or if the resolved location does not point to an existing file in the local file system
   */
  public static IPath[] getLocation(ILaunchConfiguration configuration, IPythonNature nature)
      throws CoreException {
    String locationsStr =
        configuration.getAttribute(Constants.ATTR_ALTERNATE_LOCATION, (String) null);
    if (locationsStr == null) {
      locationsStr = configuration.getAttribute(Constants.ATTR_LOCATION, (String) null);
    }
    if (locationsStr == null) {
      throw new CoreException(
          PydevDebugPlugin.makeStatus(IStatus.ERROR, "Unable to get location for run", null));
    }

    List<String> locations = StringUtils.splitAndRemoveEmptyTrimmed(locationsStr, '|');
    Path[] ret = new Path[locations.size()];
    int i = 0;
    for (String location : locations) {
      String expandedLocation = getStringSubstitution(nature).performStringSubstitution(location);
      if (expandedLocation == null || expandedLocation.length() == 0) {
        throw new CoreException(
            PydevDebugPlugin.makeStatus(
                IStatus.ERROR, "Unable to get expanded location for run", null));
      } else {
        ret[i] = new Path(expandedLocation);
      }
      i++;
    }
    return ret;
  }
  /**
   * Gets the project that should be used for a launch configuration
   *
   * @param conf the launch configuration from where the project should be gotten
   * @return the related IProject
   * @throws CoreException
   */
  public static IProject getProjectFromConfiguration(ILaunchConfiguration conf)
      throws CoreException {
    String projName = conf.getAttribute(Constants.ATTR_PROJECT, "");
    if (projName == null || projName.length() == 0) {
      throw new CoreException(
          PydevDebugPlugin.makeStatus(IStatus.ERROR, "Unable to get project for the run", null));
    }

    IWorkspace w = ResourcesPlugin.getWorkspace();
    IProject p = w.getRoot().getProject(projName);
    if (p == null || !p.exists()) { // Ok, we could not find it out
      throw new CoreException(
          PydevDebugPlugin.makeStatus(IStatus.ERROR, "Could not get project: " + projName, null));
    }
    return p;
  }
  /**
   * Launches the python process.
   *
   * <p>Modelled after Ant & Java runners see WorkbenchLaunchConfigurationDelegate::launch
   */
  public void launch(
      ILaunchConfiguration conf, String mode, ILaunch launch, IProgressMonitor monitor)
      throws CoreException {

    if (monitor == null) {
      monitor = new NullProgressMonitor();
    }

    monitor.beginTask("Preparing configuration", 3);

    try {
      PythonRunnerConfig runConfig =
          new PythonRunnerConfig(conf, mode, getRunnerConfigRun(conf, mode, launch));

      monitor.worked(1);
      try {
        PythonRunner.run(runConfig, launch, monitor);
      } catch (IOException e) {
        Log.log(e);
        finishLaunchWithError(launch);
        throw new CoreException(
            PydevDebugPlugin.makeStatus(
                IStatus.ERROR, "Unexpected IO Exception in Pydev debugger", null));
      }
    } catch (final InvalidRunException e) {
      handleError(launch, e);
    } catch (final MisconfigurationException e) {
      handleError(launch, e);
    }
  }
 /**
  * @param payload a string in the format: thread_id\tresume_reason E.g.: pid3720_zad_seq1\t108
  * @return a tuple with the thread id and the reason it stopped.
  * @throws CoreException
  */
 public static Tuple<String, String> getThreadIdAndReason(String payload) throws CoreException {
   List<String> split = StringUtils.split(payload.trim(), '\t');
   if (split.size() != 2) {
     String msg = "Unexpected threadRun payload " + payload + "(unable to match)";
     throw new CoreException(
         PydevDebugPlugin.makeStatus(IStatus.ERROR, msg, new RuntimeException(msg)));
   }
   return new Tuple<String, String>(split.get(0), split.get(1));
 }
 /**
  * Expands and returns the python interpreter attribute of the given launch configuration. The
  * interpreter path is verified to point to an existing file in the local file system.
  *
  * @param configuration launch configuration
  * @return an absolute path to the interpreter in the local file system
  * @throws CoreException if unable to retrieve the associated launch configuration attribute, if
  *     unable to resolve any variables, or if the resolved location does not point to an existing
  *     directory in the local file system
  * @throws InvalidRunException
  */
 private IPath getInterpreter(
     IInterpreterInfo location, ILaunchConfiguration configuration, IPythonNature nature)
     throws CoreException, InvalidRunException {
   if (location == null) {
     throw new CoreException(
         PydevDebugPlugin.makeStatus(
             IStatus.ERROR, "Unable to get python interpreter for run", null));
   } else {
     String expandedLocation =
         getStringSubstitution(nature).performStringSubstitution(location.getExecutableOrJar());
     if (expandedLocation == null || expandedLocation.length() == 0) {
       throw new CoreException(
           PydevDebugPlugin.makeStatus(
               IStatus.ERROR, "Unable to get expanded interpreter for run", null));
     } else {
       return new Path(expandedLocation);
     }
   }
 }
 /**
  * Can be used to extract the pythonpath used from a given configuration.
  *
  * @param conf the configuration from where we want to get the pythonpath
  * @return a string with the pythonpath used (with | as a separator)
  * @throws CoreException
  * @throws InvalidRunException
  * @throws MisconfigurationException
  */
 public static String getPythonpathFromConfiguration(
     ILaunchConfiguration conf, IInterpreterManager manager)
     throws CoreException, InvalidRunException, MisconfigurationException {
   IProject p = getProjectFromConfiguration(conf);
   PythonNature pythonNature = PythonNature.getPythonNature(p);
   if (pythonNature == null) {
     throw new CoreException(
         PydevDebugPlugin.makeStatus(
             IStatus.ERROR, "Project should have a python nature: " + p.getName(), null));
   }
   IInterpreterInfo l = getInterpreterLocation(conf, pythonNature, manager);
   return SimpleRunner.makePythonPathEnvString(pythonNature, l, manager);
 }
 /**
  * Request that pydevconsole connect (with pydevd) to the specified port
  *
  * @param localPort port for pydevd to connect to.
  * @throws Exception if connection fails
  */
 public void connectToDebugger(int localPort) throws Exception {
   if (waitingForInput) {
     throw new Exception("Can't connect debugger now, waiting for input");
   }
   Object result = client.execute("connectToDebugger", new Object[] {localPort});
   Exception exception = null;
   if (result instanceof Object[]) {
     Object[] resultarray = (Object[]) result;
     if (resultarray.length == 1) {
       if ("connect complete".equals(resultarray[0])) {
         return;
       }
       if (resultarray[0] instanceof String) {
         exception = new Exception((String) resultarray[0]);
       }
       if (resultarray[0] instanceof Exception) {
         exception = (Exception) resultarray[0];
       }
     }
   }
   throw new CoreException(
       PydevDebugPlugin.makeStatus(
           IStatus.ERROR, "pydevconsole failed to execute connectToDebugger", exception));
 }
 /**
  * Expands and returns the working directory attribute of the given launch configuration. Returns
  * <code>null</code> if a working directory is not specified. If specified, the working is
  * verified to point to an existing directory in the local file system.
  *
  * @param configuration launch configuration
  * @return an absolute path to a directory in the local file system, or <code>null</code> if
  *     unspecified
  * @throws CoreException if unable to retrieve the associated launch configuration attribute, if
  *     unable to resolve any variables, or if the resolved location does not point to an existing
  *     directory in the local file system
  */
 public static IPath getWorkingDirectory(ILaunchConfiguration configuration, IPythonNature nature)
     throws CoreException {
   IProject project = nature.getProject();
   String location =
       configuration.getAttribute(
           Constants.ATTR_WORKING_DIRECTORY, "${project_loc:/" + project.getName() + "}");
   if (location != null) {
     String expandedLocation = getStringSubstitution(nature).performStringSubstitution(location);
     if (expandedLocation.length() > 0) {
       File path = new File(expandedLocation);
       if (path.isDirectory()) {
         return new Path(expandedLocation);
       }
       throw new CoreException(
           PydevDebugPlugin.makeStatus(
               IStatus.ERROR,
               "Unable to get working location for the run \n(the location: '"
                   + expandedLocation
                   + "' is not a valid directory).",
               null));
     }
   }
   return null;
 }