/**
   * Convert a BAM file containing paried-end tags to the ascii "pair" format used for HiC.
   *
   * @param inputBam
   * @param outputFile
   * @throws IOException
   */
  public static void filterBam(String inputBam, String outputFile, List<Chromosome> chromosomes)
      throws IOException {

    CloseableIterator<Alignment> iter = null;
    AlignmentReader reader = null;
    PrintWriter pw = null;

    HashSet allChroms = new HashSet(chromosomes);

    try {
      pw = new PrintWriter(new FileWriter(outputFile));
      reader = AlignmentReaderFactory.getReader(inputBam, false);
      iter = reader.iterator();
      while (iter.hasNext()) {

        Alignment alignment = iter.next();
        ReadMate mate = alignment.getMate();

        // Filter unpaired and "normal" pairs.  Only interested in abnormals
        if (alignment.isPaired()
            && alignment.isMapped()
            && alignment.getMappingQuality() > 10
            && mate != null
            && mate.isMapped()
            && allChroms.contains(alignment.getChr())
            && allChroms.contains(mate.getChr())
            && (!alignment.getChr().equals(mate.getChr())
                || alignment.getInferredInsertSize() > 1000)) {

          // Each pair is represented twice in the file,  keep the record with the "leftmost"
          // coordinate
          if (alignment.getStart() < mate.getStart()) {
            String strand = alignment.isNegativeStrand() ? "-" : "+";
            String mateStrand = mate.isNegativeStrand() ? "-" : "+";
            pw.println(
                alignment.getReadName()
                    + "\t"
                    + alignment.getChr()
                    + "\t"
                    + alignment.getStart()
                    + "\t"
                    + strand
                    + "\t.\t"
                    + mate.getChr()
                    + "\t"
                    + mate.getStart()
                    + "\t"
                    + mateStrand);
          }
        }
      }
    } finally {
      pw.close();
      iter.close();
      reader.close();
    }
  }
  /**
   * Return the strand of the read marked "first-in-pair" for a paired alignment. This method can
   * return Strand.NONE if the end marked first is unmapped.
   *
   * @return strand of first-of-pair
   */
  public Strand getFirstOfPairStrand() {
    if (isPaired()) {
      if (isFirstOfPair()) {
        return isNegativeStrand() ? Strand.NEGATIVE : Strand.POSITIVE;
      } else {
        ReadMate mate = getMate();
        if (mate.isMapped() && isProperPair()) {
          return mate.isNegativeStrand() ? Strand.NEGATIVE : Strand.POSITIVE;
        } else {
          return Strand.NONE;
        }
      }

    } else {
      return isNegativeStrand() ? Strand.NEGATIVE : Strand.POSITIVE;
    }
  }
  /**
   * Return the strand of the read marked "second-in-pair" for a paired alignment. The strand is
   * undefined (Strand.NONE) for non-paired alignments
   *
   * @return strand of second-of-pair
   */
  public Strand getSecondOfPairStrand() {
    if (isPaired()) {
      if (isSecondOfPair()) {
        return isNegativeStrand() ? Strand.NEGATIVE : Strand.POSITIVE;
      } else {
        ReadMate mate = getMate();
        if (mate.isMapped() && isProperPair()) {
          return mate.isNegativeStrand() ? Strand.NEGATIVE : Strand.POSITIVE;
        } else {
          return Strand.NONE;
        }
      }

    } else {
      // Undefined for non-paired alignments
      return Strand.NONE;
    }
  }