/**
   * Moves temporary files out of the build directory, if applicable. A file is considered a
   * temporary file, if
   *
   * <ul>
   *   <li>it had been in the temporary files folder before the build process
   *       <p><b>or</b>
   *   <li>it was created or modified during the build process, and has a temporary file extension
   *       as specified in the preferences
   * </ul>
   *
   * @param excludes set of paths to exclude from moving, e.g. because they are the main output
   *     files
   * @param monitor progress monitor
   * @throws CoreException if an error occurs
   */
  private void moveTempFiles(final Set<IPath> excludes, IProgressMonitor monitor)
      throws CoreException {
    final IContainer aSourceContainer = getActualSourceContainer();
    if (tracking.isInitial() || aSourceContainer == null || !aSourceContainer.exists()) {
      return;
    }

    final boolean markAsDerived =
        "true"
            .equals(
                TexlipseProperties.getProjectProperty(
                    project, TexlipseProperties.MARK_TEMP_DERIVED_PROPERTY));
    final String[] tempExts = TexlipsePlugin.getPreferenceArray(TexlipseProperties.TEMP_FILE_EXTS);

    // Check if there is anything to do
    if (markAsDerived || tempDir != null) {
      // First move temporary files, which had been placed into the source folder
      // just prior to the build;
      // then check for new temporary files, which need to be moved
      project
          .getWorkspace()
          .run(
              new IWorkspaceRunnable() {
                public void run(IProgressMonitor monitor) throws CoreException {
                  if (movedFiles != null) {
                    if (excludes != null) {
                      movedFiles.removeAll(excludes);
                    }
                    moveFiles(sourceDir, tempDir, movedFiles, markAsDerived, true, monitor);
                  }
                  final Set<IPath> newTempNames =
                      tracking.getNewTempNames(aSourceContainer, tempExts, format, monitor);
                  if (excludes != null) {
                    newTempNames.removeAll(excludes);
                  }
                  moveFiles(sourceDir, tempDir, newTempNames, markAsDerived, true, monitor);
                }
              },
              monitor);
    }
  }
  /**
   * Renames output files and/or moves them if necessary. A file is considered an output file, if
   *
   * <ul>
   *   <li>it is the current output file (which can also be from a temporary build)
   *       <p><b>or</b>
   *   <li>it has the same file name as the current input file, apart from its file extension, and
   *       one of the derived file extensions as specified in the preferences
   * </ul>
   *
   * @param monitor progress monitor
   * @return set of paths to the (possibly moved) files
   * @throws CoreException if an error occurs
   */
  private Set<IPath> moveOutputFiles(IProgressMonitor monitor) throws CoreException {
    final boolean markAsDerived =
        "true"
            .equals(
                TexlipseProperties.getProjectProperty(
                    project, TexlipseProperties.MARK_OUTPUT_DERIVED_PROPERTY));
    final String[] derivedExts =
        TexlipsePlugin.getPreferenceArray(TexlipseProperties.DERIVED_FILES);

    final IFile aSourceFile = getActualSourceFile();
    final IContainer aSourceContainer = getActualSourceContainer();
    final IFile sOutputFile = getSelectedOutputFile();
    final IContainer sOutputContainer = getSelectedOutputContainer(markAsDerived, monitor);
    if (aSourceFile == null
        || aSourceContainer == null
        || sOutputFile == null
        || sOutputContainer == null) {
      // Something is wrong with the settings
      return null;
    }

    // Get name without extension from main files for renaming
    final String dotFormat = '.' + format;
    final String sourceBaseName = stripFileExt(aSourceFile.getName(), null);
    final String outputBaseName = stripFileExt(sOutputFile.getName(), dotFormat);

    // Check if files are to be moved or renamed
    final boolean moveFiles =
        !sourceBaseName.equals(outputBaseName) || !sOutputContainer.equals(aSourceContainer);
    // Retrieve output and other derived files along with their extensions
    final Map<IPath, String> outputFiles =
        ProjectFileTracking.getOutputNames(
            aSourceContainer, sourceBaseName, derivedExts, format, monitor);

    // Check if there is anything to do
    if ((moveFiles || markAsDerived) && !outputFiles.isEmpty()) {
      final Set<IPath> movedFiles = new HashSet<IPath>(outputFiles.size());

      project
          .getWorkspace()
          .run(
              new IWorkspaceRunnable() {
                public void run(IProgressMonitor monitor) throws CoreException {
                  // Move files to destination folder and rename
                  for (Entry<IPath, String> entry : outputFiles.entrySet()) {
                    IFile currentFile = project.getFile(entry.getKey());
                    if (moveFiles) {
                      // Determine new file name
                      String destName = outputBaseName + entry.getValue();
                      // Move file
                      IFile dest =
                          moveFile(project, currentFile, sOutputContainer, destName, monitor);
                      if (dest != null && markAsDerived) {
                        dest.setDerived(true);
                      }
                      movedFiles.add(dest.getProjectRelativePath());
                    } else {
                      // Possibly mark as derived
                      if (markAsDerived) {
                        currentFile.setDerived(true);
                      }
                      movedFiles.add(entry.getKey());
                    }
                  }
                }
              },
              monitor);

      return movedFiles;
    } else {
      return outputFiles.keySet();
    }
  }