/**
  * Writes the header information for the file, image, projects, dataset.
  *
  * @param writer The Excel writer.
  * @param rowIndex The selected row.
  * @param currentCoord The coord of the shape being written.
  * @throws IOException Thrown if the data cannot be written.
  */
 private void writeHeader(ExcelWriter writer, int rowIndex, Coord3D currentCoord) {
   writer.writeElement(rowIndex, 0, "Image ");
   writer.writeElement(rowIndex, 1, model.getImageName());
   rowIndex++;
   writer.writeElement(rowIndex, 0, "Z ");
   writer.writeElement(rowIndex, 1, (currentCoord.getZSection() + 1));
   rowIndex++;
   writer.writeElement(rowIndex, 0, "T ");
   writer.writeElement(rowIndex, 1, (currentCoord.getTimePoint() + 1));
   rowIndex++;
 }
  /**
   * Reacts to slider moves.
   *
   * @see ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
   */
  public void stateChanged(ChangeEvent e) {
    if (zSlider == null || tSlider == null || coord == null || state != State.READY) return;
    Coord3D thisCoord = new Coord3D(zSlider.getValue() - 1, tSlider.getValue() - 1);
    if (coord.equals(thisCoord)) return;
    if (!pixelStats.containsKey(thisCoord)) return;

    Object[] nameColour = (Object[]) channelSelection.getSelectedItem();
    String string = (String) nameColour[1];
    if (!nameMap.containsKey(string)) {
      state = State.READY;
      return;
    }
    selectedChannelName = string;
    int channel = nameMap.get(string);
    if (channel == -1) return;
    if (!pixelStats.get(thisCoord).containsKey(channel)) return;

    state = State.ANALYSING;
    populateData(thisCoord, channel);
    repaint();
    if (shape != null) view.selectFigure(shape.getFigure());
    state = State.READY;
  }
 /**
  * Outputs the summary information from the shape map.
  *
  * @param writer The Excel writer.
  * @param shapeMap see above.
  * @throws IOException
  */
 private void outputSummary(ExcelWriter writer, TreeMap<Coord3D, ROIShape> shapeMap) {
   int rowIndex = 0;
   printSummaryHeader(writer, rowIndex);
   rowIndex++;
   Coord3D start = shapeMap.firstKey();
   Coord3D end = shapeMap.lastKey();
   Coord3D coord;
   List<Integer> channels = new ArrayList<Integer>(channelName.keySet());
   for (Integer c : channels) {
     for (int z = start.getZSection(); z <= end.getZSection(); z++)
       for (int t = start.getTimePoint(); t <= end.getTimePoint(); t++) {
         coord = new Coord3D(z, t);
         populateData(coord, c);
         outputSummaryRow(writer, rowIndex, c, z, t);
         rowIndex++;
       }
   }
 }
  /**
   * Get the analysis results from the model and convert to the necessary array. data types using
   * the ROIStats wrapper then create the appropriate table data and summary statistics.
   */
  void displayAnalysisResults() {
    if (state == State.ANALYSING) return;
    this.ROIStats = model.getAnalysisResults();
    if (ROIStats == null || ROIStats.size() == 0) return;
    state = State.ANALYSING;
    channelSelection.setVisible(true);
    clearMaps();
    shapeStatsList = new TreeMap<Coord3D, Map<StatsType, Map>>(new Coord3D());
    pixelStats = new TreeMap<Coord3D, Map<Integer, Map<Point, Double>>>(new Coord3D());
    shapeMap = new TreeMap<Coord3D, ROIShape>(new Coord3D());
    minStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
    maxStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
    meanStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
    sumStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());
    stdDevStats = new TreeMap<Coord3D, Map<Integer, Double>>(new Coord3D());

    Entry entry;
    Iterator j = ROIStats.entrySet().iterator();
    channelName = new TreeMap<Integer, String>();
    nameMap = new LinkedHashMap<String, Integer>();

    int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE;
    int minT = Integer.MAX_VALUE, maxT = Integer.MIN_VALUE;
    clearAllValues();
    Coord3D c3D;
    Map<StatsType, Map> shapeStats;
    ChannelData channelData;
    int channel;
    Iterator<ChannelData> i;
    List<ChannelData> metadata = model.getMetadata();
    while (j.hasNext()) {
      entry = (Entry) j.next();
      shape = (ROIShape) entry.getKey();
      c3D = shape.getCoord3D();
      minT = Math.min(minT, c3D.getTimePoint());
      maxT = Math.max(maxT, c3D.getTimePoint());
      minZ = Math.min(minZ, c3D.getZSection());
      maxZ = Math.max(maxZ, c3D.getZSection());

      shapeMap.put(c3D, shape);
      if (shape.getFigure() instanceof MeasureTextFigure) {
        state = State.READY;
        return;
      }

      shapeStats = AnalysisStatsWrapper.convertStats((Map) entry.getValue());
      shapeStatsList.put(c3D, shapeStats);

      minStats.put(c3D, shapeStats.get(StatsType.MIN));
      maxStats.put(c3D, shapeStats.get(StatsType.MAX));
      meanStats.put(c3D, shapeStats.get(StatsType.MEAN));
      sumStats.put(c3D, shapeStats.get(StatsType.SUM));
      stdDevStats.put(c3D, shapeStats.get(StatsType.STDDEV));
      pixelStats.put(c3D, shapeStats.get(StatsType.PIXEL_PLANEPOINT2D));

      /* really inefficient but hey.... quick hack just now till refactor */
      channelName.clear();
      nameMap.clear();
      channelColour.clear();

      i = metadata.iterator();
      List<String> names = new ArrayList<String>();
      String name;
      while (i.hasNext()) {
        channelData = i.next();
        channel = channelData.getIndex();
        if (model.isChannelActive(channel)) {
          name = channelData.getChannelLabeling();
          if (names.contains(name)) name += " " + channel;
          channelName.put(channel, name);
          nameMap.put(channelName.get(channel), channel);
          channelColour.put(channel, (Color) model.getActiveChannels().get(channel));
        }
      }
    }
    if (channelName.size() != channelColour.size() || nameMap.size() == 0) {
      createComboBox();
      List<String> names = channelSummaryModel.getRowNames();
      List<String> channelNames = new ArrayList<String>();
      Double data[][] = new Double[channelName.size()][names.size()];
      channelSummaryModel = new ChannelSummaryModel(names, channelNames, data);
      channelSummaryTable.setModel(channelSummaryModel);
      saveButton.setEnabled(false);
      showIntensityTable.setEnabled(false);
      if (intensityDialog != null) intensityDialog.setVisible(false);
      state = State.READY;
      return;
    }
    saveButton.setEnabled(true);
    showIntensityTable.setEnabled(true);
    maxZ = maxZ + 1;
    minZ = minZ + 1;
    maxT = maxT + 1;
    minT = minT + 1;

    createComboBox();
    Object[] nameColour = (Object[]) channelSelection.getSelectedItem();
    String string = (String) nameColour[1];
    selectedChannel = nameMap.get(string);
    zSlider.setMaximum(maxZ);
    zSlider.setMinimum(minZ);
    tSlider.setMaximum(maxT);
    tSlider.setMinimum(minT);
    zSlider.setVisible((maxZ != minZ));
    tSlider.setVisible((maxT != minT));
    tSlider.setValue(model.getCurrentView().getTimePoint() + 1);
    zSlider.setValue(model.getCurrentView().getZSection() + 1);
    coord = new Coord3D(zSlider.getValue() - 1, tSlider.getValue() - 1);
    shape = shapeMap.get(coord);
    populateData(coord, selectedChannel);
    saveButton.setEnabled(tableModel.getRowCount() > 0);
    state = State.READY;
  }