/* (non-Javadoc)
   * @see loci.formats.NetCDFService#setFile(java.lang.String)
   */
  public void setFile(String file) throws IOException {
    this.currentFile = file;

    String currentId = Location.getMappedId(currentFile);
    netCDFFile = NetcdfFile.open(currentId);
    root = netCDFFile.getRootGroup();

    attributeList = new Vector<String>();
    variableList = new Vector<String>();
    List<Group> groups = new ArrayList<Group>();
    groups.add(root);
    parseAttributesAndVariables(groups);
  }
  public String uploadFile(
      final ImportProcessPrx proc,
      final String[] srcFiles,
      final int index,
      final ChecksumProviderFactory cpf,
      TimeEstimator estimator,
      final byte[] buf)
      throws ServerError, IOException {

    final ChecksumProvider cp =
        cpf.getProvider(
            ChecksumAlgorithmMapper.getChecksumType(proc.getImportSettings().checksumAlgorithm));

    final File file = new File(Location.getMappedId(srcFiles[index]));

    try {
      return transfer.transfer(
          new TransferState(file, index, srcFiles.length, proc, this, estimator, cp, buf));
    } catch (Exception e) {
      // Required to bump the error count
      notifyObservers(
          new ErrorHandler.FILE_EXCEPTION(file.getAbsolutePath(), e, srcFiles, "unknown"));
      // The state that we're entering, i.e. exiting upload via error
      notifyObservers(
          new ImportEvent.FILE_UPLOAD_ERROR(
              file.getAbsolutePath(), index, srcFiles.length, null, null, e));
      if (e instanceof RuntimeException) {
        throw (RuntimeException) e;
      } else if (e instanceof ServerError) {
        throw (ServerError) e;
      } else if (e instanceof IOException) {
        throw (IOException) e;
      } else {
        String msg = "Unexpected exception thrown!";
        log.error(msg, e);
        throw new RuntimeException(msg, e);
      }
    }
  }
  /**
   * Attempts to import the given file IDs using Bio-Formats, as a single group. Pixels are saved to
   * the pixels file designated by OMEIS, and an OME-XML metadata block describing the successfully
   * imported data is dumped to standard output.
   */
  public void importIds(int[] fileIds) throws OmeisException, FormatException, IOException {
    boolean doLittle = isLittleEndian();

    Arrays.sort(fileIds);

    // set up file path mappings
    String[] ids = new String[fileIds.length];
    for (int i = 0; i < fileIds.length; i++) {
      Hashtable fileInfo = getFileInfo(fileIds[i]);
      ids[i] = (String) fileInfo.get("Name");
      String path = getLocalFilePath(fileIds[i]);
      Location.mapId(ids[i], path);
    }

    // read file group
    String id = ids[0];
    String path = Location.getMappedId(id);
    if (DEBUG) log("Reading file '" + id + "' --> " + path);

    // verify that all given file IDs were grouped by the reader
    reader.setId(id);
    String[] used = reader.getUsedFiles();
    if (used == null) {
      throw new FormatException("Invalid file list for " + path);
    }
    if (used.length != ids.length) {
      throw new FormatException(
          "File list length mismatch for " + path + ": used=" + a2s(used) + "; ids=" + a2s(ids));
    }

    boolean[] done = new boolean[ids.length];
    int numLeft = ids.length;
    for (int i = 0; i < used.length; i++) {
      for (int j = 0; j < ids.length; j++) {
        if (done[j]) continue;
        if (used[i].equals(ids[j])) {
          done[j] = true;
          numLeft--;
          break;
        }
      }
    }
    if (numLeft > 0) {
      throw new FormatException("File list does not correspond to ID list for " + path);
    }

    int seriesCount = reader.getSeriesCount();

    // get DOM and Pixels elements for the file's OME-XML metadata
    OMENode ome = (OMENode) omexmlMeta.getRoot();
    Document omeDoc = ome.getDOMElement().getOwnerDocument();
    Vector pix = DOMUtil.findElementList("Pixels", omeDoc);
    if (pix.size() != seriesCount) {
      throw new FormatException(
          "Pixels element count ("
              + pix.size()
              + ") does not match series count ("
              + seriesCount
              + ") for '"
              + id
              + "'");
    }
    if (DEBUG) log(seriesCount + " series detected.");

    for (int s = 0; s < seriesCount; s++) {
      reader.setSeries(s);

      // gather pixels information for this series
      int sizeX = reader.getSizeX();
      int sizeY = reader.getSizeY();
      int sizeZ = reader.getSizeZ();
      int sizeC = reader.getSizeC();
      int sizeT = reader.getSizeT();
      int pixelType = reader.getPixelType();
      int bytesPerPixel;
      boolean isSigned, isFloat;
      switch (pixelType) {
        case FormatTools.INT8:
          bytesPerPixel = 1;
          isSigned = true;
          isFloat = false;
          break;
        case FormatTools.UINT8:
          bytesPerPixel = 1;
          isSigned = false;
          isFloat = false;
          break;
        case FormatTools.INT16:
          bytesPerPixel = 2;
          isSigned = true;
          isFloat = false;
          break;
        case FormatTools.UINT16:
          bytesPerPixel = 2;
          isSigned = false;
          isFloat = false;
          break;
        case FormatTools.INT32:
          bytesPerPixel = 4;
          isSigned = true;
          isFloat = false;
          break;
        case FormatTools.UINT32:
          bytesPerPixel = 4;
          isSigned = false;
          isFloat = false;
          break;
        case FormatTools.FLOAT:
          bytesPerPixel = 4;
          isSigned = true;
          isFloat = true;
          break;
        case FormatTools.DOUBLE:
          bytesPerPixel = 8;
          isSigned = true;
          isFloat = true;
          break;
        default:
          throw new FormatException(
              "Unknown pixel type for '" + id + "' series #" + s + ": " + pixelType);
      }
      boolean little = reader.isLittleEndian();
      boolean swap = doLittle != little && bytesPerPixel > 1 && !isFloat;

      // ask OMEIS to allocate new pixels file
      int pixelsId = newPixels(sizeX, sizeY, sizeZ, sizeC, sizeT, bytesPerPixel, isSigned, isFloat);
      String pixelsPath = getLocalPixelsPath(pixelsId);
      if (DEBUG) {
        log("Series #" + s + ": id=" + pixelsId + ", path=" + pixelsPath);
      }

      // write pixels to file
      FileOutputStream out = new FileOutputStream(pixelsPath);
      int imageCount = reader.getImageCount();
      if (DEBUG) {
        log(
            "Processing "
                + imageCount
                + " planes (sizeZ="
                + sizeZ
                + ", sizeC="
                + sizeC
                + ", sizeT="
                + sizeT
                + "): ");
      }
      // OMEIS expects XYZCT order --
      // interleaved RGB files will be handled a bit more slowly due to this
      // ordering (ChannelSeparator must read each plane three times), but
      // caching performed by the OS helps some
      for (int t = 0; t < sizeT; t++) {
        for (int c = 0; c < sizeC; c++) {
          for (int z = 0; z < sizeZ; z++) {
            int ndx = reader.getIndex(z, c, t);
            if (DEBUG) {
              log("Reading plane #" + ndx + ": z=" + z + ", c=" + c + ", t=" + t);
            }
            byte[] plane = reader.openBytes(ndx);
            if (swap) { // swap endianness
              for (int b = 0; b < plane.length; b += bytesPerPixel) {
                for (int k = 0; k < bytesPerPixel / 2; k++) {
                  int i1 = b + k;
                  int i2 = b + bytesPerPixel - k - 1;
                  byte b1 = plane[i1];
                  byte b2 = plane[i2];
                  plane[i1] = b2;
                  plane[i2] = b1;
                }
              }
            }
            out.write(plane);
          }
        }
      }
      out.close();
      if (DEBUG) log("[done]");

      // tell OMEIS we're done
      pixelsId = finishPixels(pixelsId);
      if (DEBUG) log("finishPixels called (new id=" + pixelsId + ")");

      // get SHA1 hash for finished pixels
      String sha1 = getPixelsSHA1(pixelsId);
      if (DEBUG) log("SHA1=" + sha1);

      // inject important extra attributes into proper Pixels element
      Element pixels = (Element) pix.elementAt(s);
      pixels.setAttribute("FileSHA1", sha1);
      pixels.setAttribute("ImageServerID", "" + pixelsId);
      pixels.setAttribute("DimensionOrder", "XYZCT"); // ignored anyway
      String pType = pixels.getAttribute("PixelType");
      if (pType.startsWith("u")) {
        pixels.setAttribute("PixelType", pType.replace('u', 'U'));
      }
      if (DEBUG) log("Pixel attributes injected.");
    }

    reader.close();

    // accumulate XML into buffer
    ByteArrayOutputStream xml = new ByteArrayOutputStream();
    try {
      DOMUtil.writeXML(xml, omeDoc);
    } catch (javax.xml.transform.TransformerException exc) {
      throw new FormatException(exc);
    }

    // output OME-XML to standard output
    xml.close();
    String xmlString = new String(xml.toByteArray());
    if (DEBUG) log(xmlString);
    if (http) printHttpResponseHeader();
    System.out.println(xmlString);
  }