package water.api;

import hex.AUC2;
import hex.ModelMetricsBinomial;
import water.util.TwoDimTable;

import java.util.Arrays;

public class ModelMetricsBinomialV3<I extends ModelMetricsBinomial, S extends ModelMetricsBinomialV3<I, S>> extends ModelMetricsBase<I,S> {
//  @API(help="The standard deviation of the training response.", direction=API.Direction.OUTPUT)
//  public double sigma; // Belongs in a mythical ModelMetricsSupervisedV3

  @API(help="The R^2 for this scoring run.", direction=API.Direction.OUTPUT)
  public double r2;

  @API(help="The logarithmic loss for this scoring run.", direction=API.Direction.OUTPUT)
  public double logloss;

  @API(help="The AUC for this scoring run.", direction=API.Direction.OUTPUT)
  public double AUC;

  @API(help="The Gini score for this scoring run.", direction=API.Direction.OUTPUT)
  public double Gini;

//  @API(help = "The ConfusionMatrix at the threshold for maximum F1.", direction = API.Direction.OUTPUT)
//  public ConfusionMatrixBase cm;

  @API(help = "The Metrics for various thresholds.", direction = API.Direction.OUTPUT)
  public TwoDimTableBase thresholds_and_metric_scores;

  @API(help = "The Metrics for various criteria.", direction = API.Direction.OUTPUT)
  public TwoDimTableBase max_criteria_and_metric_scores;

  @Override
  public ModelMetricsBinomialV3 fillFromImpl(ModelMetricsBinomial modelMetrics) {
    super.fillFromImpl(modelMetrics);
//    sigma = modelMetrics._sigma;
    r2 = modelMetrics.r2();
    logloss = modelMetrics._logloss;

    AUC2 auc = modelMetrics._auc;
    if (null != auc) {
      AUC  = auc._auc;
      Gini = auc._gini;

      // Fill TwoDimTable
      String[] thresholds = new String[auc._nBins];
      for( int i=0; i<auc._nBins; i++ )
        thresholds[i] = Double.toString(auc._ths[i]);
      AUC2.ThresholdCriterion crits[] = AUC2.ThresholdCriterion.VALUES;
      String[] colHeaders = new String[crits.length+2];
      String[] types      = new String[crits.length+2];
      String[] formats    = new String[crits.length+2];
      colHeaders[0] = "Threshold";
      types[0] = "double";
      formats[0] = "%f";
      int i;
      for( i=0; i<crits.length; i++ ) {
        colHeaders[i+1] = crits[i].toString();
        types     [i+1] = crits[i]._isInt ? "long" : "double";
        formats   [i+1] = crits[i]._isInt ? "%d"   : "%f"    ;
      }
      colHeaders[i+1] = "idx"; types[i+1] = "integer"; formats[i+1] = "%d";
      TwoDimTable thresholdsByMetrics = new TwoDimTable("Metric Scores for Thresholds", null, new String[auc._nBins], colHeaders, types, formats, null );
      for( i=0; i<auc._nBins; i++ ) {
        int j=0;
        thresholdsByMetrics.set(i, j, thresholds[i]);
        for (j = 0; j < crits.length; j++) {
          double d = crits[j].exec(auc, i); // Note: casts to Object are NOT redundant
          thresholdsByMetrics.set(i, 1+j, crits[j]._isInt ? (Object) ((long) d) : d);
        }
        thresholdsByMetrics.set(i, 1+j, i);
      }
      this.thresholds_and_metric_scores = new TwoDimTableV3().fillFromImpl(thresholdsByMetrics);

      // Fill TwoDimTable
      TwoDimTable maxMetrics = new TwoDimTable("Maximum Metrics", null, Arrays.copyOfRange(colHeaders, 1, crits.length+1),
              new String[]{"Threshold","Value","idx"},
              new String[]{"double",   "double","long"},
              new String[]{"%f",       "%f",    "%d"},
              "Metric" );
      for( i=0; i<crits.length; i++ ) {
        int idx = crits[i].max_criterion_idx(auc);
        maxMetrics.set(i,0,idx==-1 ? Double.NaN : auc._ths[idx]);
        maxMetrics.set(i,1,idx==-1 ? Double.NaN : crits[i].exec(auc,idx));
        maxMetrics.set(i,2,idx);
      }

      max_criteria_and_metric_scores = new TwoDimTableV3().fillFromImpl(maxMetrics);
    }
    return this;
  }
}

@@ -1909,33 +1909,33 @@
 ng%5Bcrits.length+
-2
+1
 %5D;%0A      String%5B
@@ -1965,33 +1965,33 @@
 ng%5Bcrits.length+
-2
+1
 %5D;%0A      String%5B
@@ -2033,97 +2033,10 @@
 gth+
-2%5D;%0A      colHeaders%5B0%5D = %22Threshold%22;%0A      types%5B0%5D = %22double%22;%0A      formats%5B0%5D = %22%25f%22
+1%5D
 ;%0A  
@@ -2044,16 +2044,18 @@
    int i
+=0
 ;%0A      
@@ -2104,26 +2104,24 @@
 colHeaders%5Bi
-+1
 %5D = crits%5Bi%5D
@@ -2149,26 +2149,24 @@
 types     %5Bi
-+1
 %5D = crits%5Bi%5D
@@ -2214,18 +2214,16 @@
 ats   %5Bi
-+1
 %5D = crit
@@ -2281,18 +2281,16 @@
 eaders%5Bi
-+1
 %5D = %22idx
@@ -2299,18 +2299,16 @@
  types%5Bi
-+1
 %5D = %22int
@@ -2323,18 +2323,16 @@
 ormats%5Bi
-+1
 %5D = %22%25d%22
@@ -2394,67 +2394,53 @@
 le(%22
-Metric Scores for Thresholds%22, null, new String%5Bauc._nBins%5D
+Thresholds x Metric Scores%22, null, thresholds
 , co
@@ -2465,20 +2465,28 @@
 ormats, 
-null
+%22Thresholds%22
  );%0A    
@@ -2536,64 +2536,8 @@
 nt j
-=0;%0A        thresholdsByMetrics.set(i, j, thresholds%5Bi%5D)
 ;%0A  
@@ -2703,18 +2703,16 @@
 .set(i, 
-1+
 j, crits
@@ -2799,10 +2799,8 @@
 (i, 
-1+
 j, i
@@ -2996,17 +2996,16 @@
 m Metric
-s
 %22, null,
@@ -3022,13 +3022,8 @@
 pyOf
-Range
 (col
@@ -3034,11 +3034,8 @@
 ers,
- 1,
  cri
@@ -3043,18 +3043,16 @@
 s.length
-+1
 ),%0A     

Revert "Fix formatting of Model Metrics TwoDimTable: don't use thresholds as rowHeaders, and rename tables."