public static float getQueryCoveragePercentFor(BlastResults protein, String sequence) {
   if (protein == null) {
     return 0;
   }
   return ((float) (protein.getEndQuery() - protein.getStartQuery() + 1))
       / (float) sequence.length()
       * 100;
 }
  private void writeBlastResults(
      Writer writer, BlastResults blastResult, FastaSequence fastaSequence) throws IOException {

    // candidate uniprot
    writer.write(NEW_COLUMN);
    writer.write(blastResult.getAccession());

    // write identity
    writer.write(NEW_COLUMN);
    writer.write(Float.toString(blastResult.getIdentity()));

    // write sequence coverages
    writer.write(NEW_COLUMN);
    writer.write(
        Float.toString(getQueryCoveragePercentFor(blastResult, fastaSequence.getSequence())));
    writer.write(NEW_COLUMN);
    writer.write(Float.toString(getMatchCoveragePercentFor(blastResult)));

    // write start/end
    writer.write(NEW_COLUMN);
    writer.write(Integer.toString(blastResult.getStartQuery()));
    writer.write("-");
    writer.write(Integer.toString(blastResult.getEndQuery()));
    writer.write(NEW_COLUMN);
    writer.write(Integer.toString(blastResult.getStartMatch()));
    writer.write("-");
    writer.write(Integer.toString(blastResult.getEndMatch()));

    // write query sequence
    writer.write(NEW_COLUMN);
    writer.write(fastaSequence.getSequence());
    // write alignment
    writer.write(NEW_COLUMN);
    writer.write(blastResult.getAlignment());
    // write matching sequence
    writer.write(NEW_COLUMN);
    writer.write(blastResult.getSequence());
    writer.write(NEW_LINE);

    writer.flush();
  }
  /**
   * Checks that the sequence of the BlastProtein is not in conflict with the feature ranges that
   * the protein can have in Intact
   *
   * @param range : the range of the feature to check
   * @param protein : the protein hit which could replace the old protein in Intact
   * @return true if there is no conflict between the sequence of this BlastProtein and the range
   */
  private boolean checkRangeValidWithNewSequence(
      Range range, BlastResults protein, BlastReport report) {
    // The difference between the previous start position and the new one in the new sequence
    int diffStart = protein.getStartQuery() - protein.getStartMatch();
    // The difference between the previous end position and the new one in the new sequence
    int diffEnd = protein.getEndQuery() - protein.getEndMatch();

    // Shift the ranges in consequence
    int startFrom = range.getFromIntervalStart() - diffStart;
    int startTo = range.getToIntervalStart() - diffStart;
    int endFrom = range.getFromIntervalEnd() - diffStart;
    int endTo = range.getToIntervalEnd() - diffStart;

    // No ranges should be before the new start positions
    if (startFrom < protein.getStartMatch()
        || range.getFromIntervalStart() < protein.getStartQuery()) {
      report.addWarning(
          "The feature range is "
              + range.getFromIntervalStart()
              + "-"
              + range.getToIntervalStart()
              + " and the alignment with the Swissprot sequence starts after "
              + range.getFromIntervalStart()
              + ". We can't change the previous sequence with the sequence of the Swissprot entry because it will be incoherent with the current feature(s) of the protein.");
      return false;
    }
    // No ranges should be before the new start positions
    else if (startTo > protein.getEndMatch()
        || range.getToIntervalStart() > protein.getEndQuery()) {
      report.addWarning(
          "The feature range is "
              + range.getFromIntervalStart()
              + "-"
              + range.getToIntervalStart()
              + " and the alignment with the Swissprot sequence finishes before "
              + range.getToIntervalStart()
              + ". We can't change the previous sequence with the sequence of the Swissprot entry because it will be incoherent with the current feature(s) of the protein.");
      return false;
    }
    // No ranges should be after the new end positions
    else if (endFrom < protein.getStartMatch()
        || range.getFromIntervalEnd() < protein.getStartQuery()) {
      report.addWarning(
          "The feature range is "
              + range.getFromIntervalEnd()
              + "-"
              + range.getToIntervalEnd()
              + " and the alignment with the Swissprot sequence starts after "
              + range.getFromIntervalStart()
              + ". We can't change the previous sequence with the sequence of the Swissprot entry because it will be incoherent with the current feature(s) of the protein.");
      return false;
    }
    // No ranges should be after the new end positions
    else if (endTo > protein.getEndMatch() || range.getToIntervalEnd() > protein.getEndQuery()) {
      report.addWarning(
          "The feature range is "
              + range.getFromIntervalEnd()
              + "-"
              + range.getToIntervalEnd()
              + " and the alignment with the Swissprot sequence finishes before "
              + range.getToIntervalStart()
              + ". We can't change the previous sequence with the sequence of the Swissprot entry because it will be incoherent with the current feature(s) of the protein.");
      return false;
    } else {
      String rangeSequence = range.getFullSequence();

      if (rangeSequence == null) {
        rangeSequence = range.getFullSequence();
      }

      // Check that the amino acids involved in the feature ranges are identical
      if (startFrom > 0 && endTo > 0) {
        String rangeNewSequence = protein.getSequence().substring(startFrom - 1, endTo);

        if (rangeSequence == null) {
          report.addWarning(
              "The feature "
                  + range.getFeature().getAc()
                  + " doesn't contain any sequence or full sequence but has range positions. This entry needs to ce checked by a curator");
          return false;
        }
        if (!rangeSequence.equals(rangeNewSequence)) {
          report.addWarning(
              "The sequence of the Swissprot entry from "
                  + range.getFromIntervalStart()
                  + " to "
                  + range.getToIntervalStart()
                  + " is different from the previous feature sequence, we can't replace the previous sequence with the sequence of the Swissprot entry.");
          return false;
        }
      }
    }
    return true;
  }