@Override
  protected void finish() {
    multiCollector.finish();

    final MetricsFile<InsertSizeMetrics, Integer> file = getMetricsFile();
    multiCollector.addAllLevelsToFile(file);

    if (file.getNumHistograms() == 0) {
      // can happen if user sets MINIMUM_PCT = 0.5, etc.
      log.warn(
          "All data categories were discarded because they contained < "
              + MINIMUM_PCT
              + " of the total aligned paired data.");
      final InsertSizeMetricsCollector.PerUnitInsertSizeMetricsCollector allReadsCollector =
          (InsertSizeMetricsCollector.PerUnitInsertSizeMetricsCollector)
              multiCollector.getAllReadsCollector();
      log.warn(
          "Total mapped pairs in all categories: "
              + (allReadsCollector == null
                  ? allReadsCollector
                  : allReadsCollector.getTotalInserts()));
    } else {
      file.write(OUTPUT);

      final int rResult;
      if (HISTOGRAM_WIDTH == null) {
        rResult =
            RExecutor.executeFromClasspath(
                HISTOGRAM_R_SCRIPT,
                OUTPUT.getAbsolutePath(),
                HISTOGRAM_FILE.getAbsolutePath(),
                INPUT.getName());
      } else {
        rResult =
            RExecutor.executeFromClasspath(
                HISTOGRAM_R_SCRIPT,
                OUTPUT.getAbsolutePath(),
                HISTOGRAM_FILE.getAbsolutePath(),
                INPUT.getName(),
                String.valueOf(
                    HISTOGRAM_WIDTH)); // HISTOGRAM_WIDTH is passed because R automatically sets
                                       // histogram width to the last
        // bin that has data, which may be less than HISTOGRAM_WIDTH and confuse the user.
      }

      if (rResult != 0) {
        throw new PicardException(
            "R script " + HISTOGRAM_R_SCRIPT + " failed with return code " + rResult);
      }
    }
  }
  /** @throws IOException */
  private void readFileHeader() throws Exception {

    // fisrt four bytes are empty
    // it should be zero for new version of control file, backward compatibility
    int emptyBytes = this.readFourBytes(inputStream);
    if (emptyBytes != 0) {

      log.warn(
          "The first four bytes are not zero: "
              + emptyBytes
              + ". This is an old format control file.");
      this.totalClusters = emptyBytes;
      return;
    }

    // next four bytes should be version and greater or equal to the expected
    int version = this.readFourBytes(inputStream);
    if (version != this.EXPECTED_CONTROL_VERSION) {
      log.error("Unexpected version byte: " + version);
      throw new Exception("Unexpected version number in control file");
    }

    // next four bytes should be the total number of clusters
    this.totalClusters = this.readFourBytes(inputStream);
    log.info("The total number of clusters: " + this.getTotalClusters());
  }
  @Override
  public Object next() {

    try {
      int nextByte = this.inputStream.readUnsignedShort();

      if (nextByte == -1) {
        log.warn(
            "There is no more cluster in Control file after cluster "
                + this.getCurrentCluster()
                + " in file "
                + this.getFileName());
        return null;
      }

      this.currentCluster++;
      /*
      Bit0: always empty (0)
      Bit1: was the read identified as a control?
      Bit2: was the match ambiguous?
      Bit3: did the read match the phiX tag?
      Bit4: did the read align to match the phiX tag?
      Bit5: did the read match the control index sequence? (specified in controls.fata, TGTCACA)
      Bits6,7: reserved for future use
      Bits8..15: the report key for the matched record in the controls.fasta file (specified by the REPOControl FilesRT_ KEY metadata)
      */
      nextByte = nextByte & 0x2;
      if (nextByte != 0) {
        this.currentControlClusters++;
      }

      return new Integer(nextByte);

    } catch (IOException ex) {
      log.error(ex, "Problem to read control file");
    }

    return null;
  }