package com.bbn.bue.common.evaluation;

import com.bbn.bue.common.Inspector;
import com.bbn.bue.common.symbols.Symbol;

import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
import com.google.common.io.CharSink;

import java.io.IOException;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Observes an {@link Alignment} between system items on the left and gold standard items on the
 * right. A system/gold item is assumed to be found if aligned.  Writes summary F-measure scores
 * based on its observations.
 *
 * At the moment this only writes confusion matrices but it will be extended to write more soon.
 *
 * Although this only implements {@code Inspector<Alignment<Object,Object>>}, it is safe to cast it
 * to inspect any alignment.
 */
@Beta
public final class AggregateBinaryFScoresInspector<KeyT, TestT>
    implements Inspector<Alignment<? extends KeyT, ? extends TestT>> {

  private final SummaryConfusionMatrices.Builder summaryConfusionMatrixB =
      SummaryConfusionMatrices.builder();
  private final ImmutableList.Builder<FMeasureCounts> countsBuilder;
  private final CharSink outSink;
  private static final Symbol PRESENT = Symbol.from("Present");
  private static final Symbol ABSENT = Symbol.from("Absent");

  private AggregateBinaryFScoresInspector(final CharSink outSink) {
    this.outSink = checkNotNull(outSink);
    countsBuilder = ImmutableList.builder();
  }

  public static <KeyT, TestT> AggregateBinaryFScoresInspector<KeyT, TestT> createOutputtingTo(
      CharSink outputSink) {
    return new AggregateBinaryFScoresInspector<KeyT, TestT>(outputSink);
  }

  @Override
  public void finish() throws IOException {
    final SummaryConfusionMatrix summaryConfusionMatrix = summaryConfusionMatrixB.build();
    final FMeasureCounts summaryCounts = FMeasureCounts.combineToMicroFMeasure(countsBuilder.build());
    outSink.write(SummaryConfusionMatrices.prettyPrint(summaryConfusionMatrix)
        + summaryCounts.compactPrettyString());
  }

  @Override
  public void inspect(final Alignment<? extends KeyT, ? extends TestT> alignment) {
    final int truePositives = alignment.rightAligned().size();
    final int falseNegatives = alignment.leftUnaligned().size();
    final int falsePositives = alignment.rightUnaligned().size();
    summaryConfusionMatrixB
        .accumulatePredictedGold(PRESENT, PRESENT, truePositives);
    summaryConfusionMatrixB
        .accumulatePredictedGold(PRESENT, ABSENT, falseNegatives);
    summaryConfusionMatrixB
        .accumulatePredictedGold(ABSENT, PRESENT, falsePositives);
    countsBuilder.add(FMeasureCounts.from(truePositives, falsePositives, falseNegatives));
  }
}


@@ -100,25 +100,21 @@
 mon.
-symbols.Symbol
+StringUtils
 ;%0A
-%0A
 impo
@@ -112,37 +112,38 @@
 ils;%0Aimport com.
-googl
+bbn.bu
 e.common.annotat
@@ -139,24 +139,22 @@
 mon.
-annotations.Beta
+symbols.Symbol
 ;%0Aim
@@ -180,29 +180,24 @@
 mon.
-collect.ImmutableList
+annotations.Beta
 ;%0Aim
@@ -1055,77 +1055,8 @@
 ();%0A
-  private final ImmutableList.Builder%3CFMeasureCounts%3E countsBuilder;%0A
   pr
@@ -1326,53 +1326,8 @@
 k);%0A
-    countsBuilder = ImmutableList.builder();%0A
   %7D%0A
@@ -1684,125 +1684,62 @@
     
-final FMeasureCounts summaryCounts = FMeasureCounts.combineToMicroFMeasure(countsBuilder.build());%0A    outSink.write(
+outSink.write(StringUtils.NewlineJoiner.join(%0A        
 Summ
@@ -1794,16 +1794,17 @@
 nMatrix)
+,
 %0A       
@@ -1808,23 +1808,85 @@
     
-+ summaryCounts
+SummaryConfusionMatrices.FMeasureVsAllOthers(summaryConfusionMatrix, PRESENT)
 .com
@@ -1904,16 +1904,17 @@
 tring())
+)
 ;%0A  %7D%0A%0A 
@@ -2362,19 +2362,19 @@
 old(
-PRE
+AB
 SENT, 
-AB
+PRE
 SENT
@@ -2449,35 +2449,35 @@
 edictedGold(
-AB
+PRE
 SENT, 
-PRE
+AB
 SENT, falseP
@@ -2491,102 +2491,10 @@
 s);%0A
-    countsBuilder.add(FMeasureCounts.from(truePositives, falsePositives, falseNegatives));%0A
   %7D%0A%7D%0A
-%0A

Simplify F score output for AggregateBinaryFScoresInspector.