/**
   * Perform an image import uploading files if necessary.
   *
   * @param container The import container which houses all the configuration values and target for
   *     the import.
   * @param index Index of the import in a set. <code>0</code> is safe if this is a singular import.
   * @param numDone Number of imports completed in a set. <code>0</code> is safe if this is a
   *     singular import.
   * @param total Total number of imports in a set. <code>1</code> is safe if this is a singular
   *     import.
   * @return List of Pixels that have been imported.
   * @throws FormatException If there is a Bio-Formats image file format error during import.
   * @throws IOException If there is an I/O error.
   * @throws ServerError If there is an error communicating with the OMERO server we're importing
   *     into.
   * @since OMERO Beta 4.2.1.
   */
  public List<Pixels> importImage(
      final ImportContainer container, int index, int numDone, int total)
      throws FormatException, IOException, Throwable {
    HandlePrx handle;
    for (FileExclusion exclusion : exclusions) {
      Boolean veto = exclusion.suggestExclusion(store.getServiceFactory(), container);
      if (Boolean.TRUE.equals(veto)) {
        notifyObservers(
            new ImportEvent.FILESET_EXCLUSION(
                container.getFile().getAbsolutePath(), 0, container.getUsedFiles().length));
        return Collections.emptyList();
      }
    }
    final ImportProcessPrx proc = createImport(container);
    final String[] srcFiles = container.getUsedFiles();
    final List<String> checksums = new ArrayList<String>();
    final byte[] buf = new byte[store.getDefaultBlockSize()];
    final TimeEstimator estimator =
        new ProportionalTimeEstimatorImpl(container.getUsedFilesTotalSize());
    Map<Integer, String> failingChecksums = new HashMap<Integer, String>();

    notifyObservers(
        new ImportEvent.FILESET_UPLOAD_START(null, index, srcFiles.length, null, null, null));

    for (int i = 0; i < srcFiles.length; i++) {
      checksums.add(uploadFile(proc, srcFiles, i, checksumProviderFactory, estimator, buf));
    }

    try {
      handle = proc.verifyUpload(checksums);
    } catch (ChecksumValidationException cve) {
      failingChecksums = cve.failingChecksums;
      throw cve;
    } finally {

      try {
        proc.close();
      } catch (Exception e) {
        log.warn("Exception while closing proc", e);
      }

      notifyObservers(
          new ImportEvent.FILESET_UPLOAD_END(
              null,
              index,
              srcFiles.length,
              null,
              null,
              srcFiles,
              checksums,
              failingChecksums,
              null));
    }

    // At this point the import is running, check handle for number of
    // steps.
    ImportCallback cb = null;
    try {
      cb = createCallback(proc, handle, container);

      if (minutesToWait == 0) {
        log.info("Disconnecting from import process...");
        cb.close(false);
        cb = null;
        handle = null;
        return Collections.emptyList(); // EARLY EXIT
      }

      if (minutesToWait < 0) {
        while (true) {
          if (cb.block(5000)) {
            break;
          }
        }
      } else {
        cb.loop(minutesToWait * 30, 2000);
      }

      final ImportResponse rsp = cb.getImportResponse();
      if (rsp == null) {
        throw new Exception("Import failure");
      }
      return rsp.pixels;
    } finally {
      if (cb != null) {
        cb.close(true); // Allow cb to close handle
      } else if (handle != null) {
        handle.close();
      }
    }
  }