gt:         else if ("ImageSizeY".equals(currentName)) {
context: /*
   * #%L
   * OME Bio-Formats package for reading and converting biological file formats.
   * %%
   * Copyright (C) 2005 - 2012 Open Microscopy Environment:
   *   - Board of Regents of the University of Wisconsin-Madison
   *   - Glencoe Software, Inc.
   *   - University of Dundee
   * %%
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as
   * published by the Free Software Foundation, either version 2 of the 
   * License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public 
   * License along with this program.  If not, see
   * <http://www.gnu.org/licenses/gpl-2.0.html>.
   * #L%
   */
  
  package loci.formats.in;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Arrays;
  
  import loci.common.DataTools;
  import loci.common.Location;
  import loci.common.RandomAccessInputStream;
  import loci.common.xml.BaseHandler;
  import loci.common.xml.XMLTools;
  import loci.formats.CoreMetadata;
  import loci.formats.FormatException;
  import loci.formats.FormatReader;
  import loci.formats.FormatTools;
  import loci.formats.MetadataTools;
  import loci.formats.meta.MetadataStore;
  import loci.formats.tiff.IFD;
  import loci.formats.tiff.TiffParser;
  
  import ome.xml.model.primitives.NonNegativeInteger;
  import ome.xml.model.primitives.PositiveFloat;
  import ome.xml.model.primitives.PositiveInteger;
  
  import org.xml.sax.Attributes;
  
  /**
   * OperettaReader is the file format reader for PerkinElmer Operetta data.
   *
   * <dl><dt><b>Source code:</b></dt>
   * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/bio-formats/src/loci/formats/in/OperettaReader.java">Trac</a>,
   * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/bio-formats/src/loci/formats/in/OperettaReader.java;hb=HEAD">Gitweb</a></dd></dl>
   *
   * @author Melissa Linkert melissa at glencoesoftware.com
   */
  public class OperettaReader extends FormatReader {
  
    // -- Constants --
  
    private static final String XML_FILE = "Index.idx.xml";
    private static final int XML_TAG = 65500;
  
    // -- Fields --
  
    private Plane[][] planes;
    private MinimalTiffReader reader;
  
    // -- Constructor --
  
    /** Constructs a new Operetta reader. */
    public OperettaReader() {
      super("PerkinElmer Operetta", new String[] {"tif", "tiff", "xml"});
      domains = new String[] {FormatTools.HCS_DOMAIN};
      suffixSufficient = false;
      datasetDescription =
        "Directory with XML file and one .tif/.tiff file per plane";
    }
  
    // -- IFormatReader API methods --
  
    /* @see loci.formats.IFormatReader#isSingleFile(String) */
    public boolean isSingleFile(String id) throws FormatException, IOException {
      return false;
    }
  
    /* @see loci.formats.IFormatReader#fileGroupOption(String) */
    public int fileGroupOption(String id) throws FormatException, IOException {
      return FormatTools.MUST_GROUP;
    }
  
    /* @see loci.formats.IFormatReader#isThisType(String, boolean) */
    public boolean isThisType(String name, boolean open) {
      String localName = new Location(name).getName();
      if (localName.equals(XML_FILE)) {
        return true;
      }
      Location parent = new Location(name).getAbsoluteFile().getParentFile();
      Location xml = new Location(parent, XML_FILE);
      if (!xml.exists()) {
        return false;
      }
  
      return super.isThisType(name, open);
    }
  
    /* @see loci.formats.IFormatReader#isThisType(RandomAccessInputStream) */
    public boolean isThisType(RandomAccessInputStream stream) throws IOException {
      TiffParser p = new TiffParser(stream);
      IFD ifd = p.getFirstIFD();
      if (ifd == null) return false;
  
      Object s = ifd.getIFDValue(XML_TAG);
      if (s == null) return false;
      String xml = s instanceof String[] ? ((String[]) s)[0] : s.toString();
      return xml.indexOf("Operetta") < 1024;
    }
  
    /* @see loci.formats.IFormatReader#getSeriesUsedFiles(boolean) */
    public String[] getSeriesUsedFiles(boolean noPixels) {
      FormatTools.assertId(currentId, true, 1);
  
      ArrayList<String> files = new ArrayList<String>();
      files.add(currentId);
      for (Plane p : planes[getSeries()]) {
        files.add(p.filename);
      }
  
      return files.toArray(new String[files.size()]);
    }
  
    /* @see loci.formats.IFormatReader#close(boolean) */
    public void close(boolean fileOnly) throws IOException {
      super.close(fileOnly);
      if (!fileOnly) {
        if (reader != null) {
          reader.close();
        }
        reader = null;
        planes = null;
      }
    }
  
    /**
     * @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int)
     */
    public byte[] openBytes(int no, byte[] buf, int x, int y, int w, int h)
      throws FormatException, IOException
    {
      FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h);
  
      if (getSeries() < planes.length && no < planes[getSeries()].length) {
        Plane p = planes[getSeries()][no];
  
        if (new Location(p.filename).exists()) {
          if (reader == null) {
            reader = new MinimalTiffReader();
          }
          reader.setId(p.filename);
          reader.openBytes(0, buf, x, y, w, h);
          reader.close();
        }
      }
  
      return buf;
    }
  
    // -- Internal FormatReader API methods --
  
    /* @see loci.formats.FormatReader#initFile(String) */
    protected void initFile(String id) throws FormatException, IOException {
      // make sure that we have the XML file and not a TIFF file
  
      if (!checkSuffix(id, "xml")) {
        Location parent = new Location(id).getAbsoluteFile().getParentFile();
        Location xml = new Location(parent, XML_FILE);
        if (!xml.exists()) {
          throw new FormatException("Could not find XML file " +
            xml.getAbsolutePath());
        }
        initFile(xml.getAbsolutePath());
        return;
      }
      else {
        super.initFile(id);
      }
  
      // parse plate layout and image dimensions from the XML file
  
      String xmlData = DataTools.readFile(id);
      OperettaHandler handler = new OperettaHandler();
      XMLTools.parseXML(xmlData, handler);
  
      // sort the list of images by well and field indices
  
      ArrayList<Plane> planeList = handler.getPlanes();
  
      ArrayList<Integer> uniqueRows = new ArrayList<Integer>();
      ArrayList<Integer> uniqueCols = new ArrayList<Integer>();
      ArrayList<Integer> uniqueFields = new ArrayList<Integer>();
      ArrayList<Integer> uniqueZs = new ArrayList<Integer>();
      ArrayList<Integer> uniqueTs = new ArrayList<Integer>();
      ArrayList<Integer> uniqueCs = new ArrayList<Integer>();
  
      for (Plane p : planeList) {
        if (!uniqueRows.contains(p.row)) {
          uniqueRows.add(p.row);
        }
        if (!uniqueCols.contains(p.col)) {
          uniqueCols.add(p.col);
        }
        if (!uniqueFields.contains(p.field)) {
          uniqueFields.add(p.field);
        }
        if (!uniqueZs.contains(p.z)) {
          uniqueZs.add(p.z);
        }
        if (!uniqueCs.contains(p.c)) {
          uniqueCs.add(p.c);
        }
        if (!uniqueTs.contains(p.t)) {
          uniqueTs.add(p.t);
        }
      }
  
      Integer[] rows = uniqueRows.toArray(new Integer[uniqueRows.size()]);
      Integer[] cols = uniqueCols.toArray(new Integer[uniqueCols.size()]);
      Integer[] fields = uniqueFields.toArray(new Integer[uniqueFields.size()]);
      Integer[] zs = uniqueZs.toArray(new Integer[uniqueZs.size()]);
      Integer[] cs = uniqueCs.toArray(new Integer[uniqueCs.size()]);
      Integer[] ts = uniqueTs.toArray(new Integer[uniqueTs.size()]);
  
      Arrays.sort(rows);
      Arrays.sort(cols);
      Arrays.sort(fields);
      Arrays.sort(zs);
      Arrays.sort(ts);
      Arrays.sort(cs);
  
      int count = rows.length * cols.length * fields.length;
      core = new CoreMetadata[count];
  
      planes = new Plane[count][zs.length * cs.length * ts.length];
  
      int nextSeries = 0;
      for (int row=0; row<rows.length; row++) {
        for (int col=0; col<cols.length; col++) {
          for (int field=0; field<fields.length; field++) {
            int nextPlane = 0;
            for (int t=0; t<ts.length; t++) {
              for (int z=0; z<zs.length; z++) {
                for (int c=0; c<cs.length; c++) {
                  for (Plane p : planeList) {
                    if (p.row == rows[row] && p.col == cols[col] &&
                      p.field == fields[field] && p.t == ts[t] && p.z == zs[z] &&
                      p.c == cs[c])
                    {
                      planes[nextSeries][nextPlane] = p;
                      break;
                    }
                  }
                  nextPlane++;
                }
              }
            }
            nextSeries++;
          }
        }
      }
  
      for (int i=0; i<getSeriesCount(); i++) {
        core[i] = new CoreMetadata();
        core[i].sizeX = planes[i][0].x;
        core[i].sizeY = planes[i][0].y;
        core[i].sizeZ = uniqueZs.size();
        core[i].sizeC = uniqueCs.size();
        core[i].sizeT = uniqueTs.size();
        core[i].dimensionOrder = "XYCZT";
  
        if (reader == null) {
          reader = new MinimalTiffReader();
        }
        reader.setId(planes[i][0].filename);
        core[i].pixelType = reader.getPixelType();
        core[i].rgb = false;
        core[i].imageCount = getSizeZ() * getSizeC() * getSizeT();
        core[i].littleEndian = reader.isLittleEndian();
        reader.close();
      }
  
      // populate the MetadataStore
  
      MetadataStore store = makeFilterMetadata();
      MetadataTools.populatePixels(store, this, true);
  
      store.setPlateID(MetadataTools.createLSID("Plate", 0), 0);
      store.setPlateRows(new PositiveInteger(handler.getPlateRows()), 0);
      store.setPlateColumns(new PositiveInteger(handler.getPlateColumns()), 0);
  
      String plateAcqID = MetadataTools.createLSID("PlateAcquisition", 0, 0);
      store.setPlateAcquisitionID(plateAcqID, 0, 0);
      if (fields.length > 0) {
        store.setPlateAcquisitionMaximumFieldCount(
          new PositiveInteger(fields.length), 0, 0);
      }
      else {
        LOGGER.warn("Expected positive value for MaximumFieldCount; got {}",
          fields.length);
      }
  
      for (int row=0; row<rows.length; row++) {
        for (int col=0; col<cols.length; col++) {
          int well = row * cols.length + col;
          store.setWellID(MetadataTools.createLSID("Well", 0, well), 0, well);
          store.setWellRow(new NonNegativeInteger(rows[row]), 0, well);
          store.setWellColumn(new NonNegativeInteger(cols[col]), 0, well);
  
          for (int field=0; field<fields.length; field++) {
            int imageIndex = well * fields.length + field;
            String wellSampleID =
              MetadataTools.createLSID("WellSample", 0, well, field);
            store.setWellSampleID(wellSampleID, 0, well, field);
            store.setWellSampleIndex(
              new NonNegativeInteger(imageIndex), 0, well, field);
            String imageID = MetadataTools.createLSID("Image", imageIndex);
            store.setImageID(imageID, imageIndex);
            store.setWellSampleImageRef(imageID, 0, well, field);
  
            String name = "Well " + (well + 1) + ", Field " + (field + 1);
            store.setImageName(name, imageIndex);
            store.setPlateAcquisitionWellSampleRef(
              wellSampleID, 0, 0, imageIndex);
          }
        }
      }
  
      if (getMetadataOptions().getMetadataLevel() != MetadataLevel.MINIMUM) {
        store.setPlateName(handler.getPlateName(), 0);
        store.setPlateDescription(handler.getPlateDescription(), 0);
        store.setPlateExternalIdentifier(handler.getPlateIdentifier(), 0);
  
        String experimenterID = MetadataTools.createLSID("Experimenter", 0);
        store.setExperimenterID(experimenterID, 0);
        store.setExperimenterLastName(handler.getExperimenterName(), 0);
  
        for (int i=0; i<getSeriesCount(); i++) {
          store.setImageExperimenterRef(experimenterID, i);
  
          for (int c=0; c<getSizeC(); c++) {
            store.setChannelName(planes[i][c].channelName, i, c);
          }
  
          store.setPixelsPhysicalSizeX(
            new PositiveFloat(planes[i][0].resolutionX), i);
          store.setPixelsPhysicalSizeY(
            new PositiveFloat(planes[i][0].resolutionY), i);
  
          for (int p=0; p<getImageCount(); p++) {
            store.setPlanePositionX(planes[i][p].positionX, i, p);
            store.setPlanePositionY(planes[i][p].positionY, i, p);
            store.setPlanePositionZ(planes[i][p].positionZ, i, p);
          }
        }
  
      }
    }
  
    // -- Helper classes --
  
    class OperettaHandler extends BaseHandler {
      // -- Fields --
  
      private String currentName;
      private Plane activePlane;
  
      private String displayName;
      private String plateID;
      private String measurementTime;
      private String plateName;
      private String plateDescription;
      private int plateRows, plateCols;
      private ArrayList<Plane> planes = new ArrayList<Plane>();
  
      // -- OperettaHandler API methods --
  
      public ArrayList<Plane> getPlanes() {
        return planes;
      }
  
      public String getExperimenterName() {
        return displayName;
      }
  
      public String getPlateIdentifier() {
        return plateID;
      }
  
      public String getMeasurementTime() {
        return measurementTime;
      }
  
      public String getPlateName() {
        return plateName;
      }
  
      public String getPlateDescription() {
        return plateDescription;
      }
  
      public int getPlateRows() {
        return plateRows;
      }
  
      public int getPlateColumns() {
        return plateCols;
      }
  
      // -- DefaultHandler API methods --
  
      public void characters(char[] ch, int start, int length) {
        String value = new String(ch, start, length);
  
        if ("User".equals(currentName)) {
          displayName = value;
        }
        else if ("PlateID".equals(currentName)) {
          plateID = value;
        }
        else if ("MeasurementStartTime".equals(currentName)) {
          measurementTime = value;
        }
        else if ("Name".equals(currentName)) {
          plateName = value;
        }
        else if ("PlateTypeName".equals(currentName)) {
          plateDescription = value;
        }
        else if ("PlateRows".equals(currentName)) {
          plateRows = Integer.parseInt(value);
        }
        else if ("PlateColumns".equals(currentName)) {
          plateCols = Integer.parseInt(value);
        }
        else if (activePlane != null) {
          if ("URL".equals(currentName)) {
            Location parent =
              new Location(currentId).getAbsoluteFile().getParentFile();
            activePlane.filename = new Location(parent, value).getAbsolutePath();
          }
          else if ("Row".equals(currentName)) {
            activePlane.row = Integer.parseInt(value) - 1;
          }
          else if ("Col".equals(currentName)) {
            activePlane.col = Integer.parseInt(value) - 1;
          }
          else if ("FieldID".equals(currentName)) {
            activePlane.field = Integer.parseInt(value);
          }
          else if ("PlaneID".equals(currentName)) {
            activePlane.z = Integer.parseInt(value);
          }
          else if ("ImageSizeX".equals(currentName)) {
            activePlane.x = Integer.parseInt(value);
          }
  