package hex;

import water.*;
import water.api.DocGen;
import water.fvec.*;
import water.util.Log;
import water.util.RString;

import java.util.Random;

/**
 * Create a Frame from scratch
 * If randomize = true, then the frame is filled with Random values.
 *
 */
public class CreateFrame extends Request2 {
  static final int API_WEAVER=1; // This file has auto-gen'd doc & json fields
  static public DocGen.FieldDoc[] DOC_FIELDS; // Initialized from Auto-Gen code.

  @API(help = "Name (Key) of frame to be created", required = true, filter = Default.class, json=true)
  public String key;

  @API(help = "Number of rows", required = true, filter = Default.class, json=true)
  public long rows = 10000;

  @API(help = "Number of data columns (in addition to the first response column)", required = true, filter = Default.class, json=true)
  public int cols = 10;

  @API(help = "Random number seed", filter = Default.class, json=true)
  public long seed = new Random().nextLong();

  @API(help = "Whether frame should be randomized", filter = Default.class, json=true)
  public boolean randomize = true;

  @API(help = "Constant value (for randomize=false)", filter = Default.class, json=true)
  public long value = 0;

  @API(help = "Range for real variables (-range ... range)", filter = Default.class, json=true)
  public long real_range = 100;

  @API(help = "Fraction of categorical columns (for randomize=true)", filter = Default.class, json=true)
  public double categorical_fraction = 0.2;

  @API(help = "Factor levels for categorical variables", filter = Default.class, json=true)
  public int factors = 100;

  @API(help = "Fraction of integer columns (for randomize=true)", filter = Default.class, json=true)
  public double integer_fraction = 0.2;

  @API(help = "Range for integer variables (-range ... range)", filter = Default.class, json=true)
  public long integer_range = 100;

  @API(help = "Fraction of missing values", filter = Default.class, json=true)
  public double missing_fraction = 0.01;

  @API(help = "Number of factor levels of the first column (1=real, 2=binomial, N=multinomial)", filter = Default.class, json=true)
  public int response_factors = 2;

  public boolean positive_response; // only for response_factors=1

  @Override public Response serve() {
    try {
      if (integer_fraction + categorical_fraction > 1)
        throw new IllegalArgumentException("Integer and categorical fractions must add up to <= 1.");

      if (cols <= 0 || rows <= 0)
        throw new IllegalArgumentException("Must have number of rows > 0 and columns > 1.");

      if (!randomize) {
        if (integer_fraction != 0 || categorical_fraction != 0)
          throw new IllegalArgumentException("Cannot have integer or categorical fractions > 0 unless randomize=true.");
      } else {
        if (value != 0)
          throw new IllegalArgumentException("Cannot set data to a constant value if randomize=true.");
      }

      final FrameCreator fct = new FrameCreator(this);
      H2O.submitTask(fct);
      fct.join();

      Log.info("Created frame '" + key + "'.");
      return Response.done(this);
    } catch( Throwable t ) {
      return Response.error(t);
    }
  }

  @Override public boolean toHTML( StringBuilder sb ) {
    Frame fr = UKV.get(Key.make(key));
    if (fr==null) {
      return false;
    }
    RString aft = new RString("<a href='Inspect2.html?src_key=%$key'>%key</a>");
    aft.replace("key", key);
    DocGen.HTML.section(sb, "Frame creation done.<br/>Frame '" + aft.toString()
            + "' now has " + fr.numRows() + " rows and " + (fr.numCols()-1)
            + " data columns, as well as a " + (response_factors == 1 ? "real-valued" : (response_factors == 2 ? "binomial" : "multi-nomial"))
            + " response variable as the first column.<br/>Number of chunks: " + fr.anyVec().nChunks() + ".");
    return true;
  }

}

@@ -651,32 +651,42 @@
 = Default.class,
+ lmin = 1,
  json=true)%0A  pu
@@ -825,32 +825,42 @@
 = Default.class,
+ lmin = 1,
  json=true)%0A  pu
@@ -1450,32 +1450,52 @@
 = Default.class,
+ dmin = 0, dmax = 1,
  json=true)%0A  pu
@@ -1527,32 +1527,136 @@
 raction = 0.2;%0A%0A
+  //@API(help = %22Factor levels for categorical variables%22, filter = Default.class, lmin = 2, json=true)%0A
   @API(help = %22F
@@ -1841,32 +1841,52 @@
 = Default.class,
+ dmin = 0, dmax = 1,
  json=true)%0A  pu
@@ -2116,32 +2116,52 @@
 = Default.class,
+ dmin = 0, dmax = 1,
  json=true)%0A  pu
@@ -2310,32 +2310,42 @@
 = Default.class,
+ lmin = 1,
  json=true)%0A  pu
@@ -2546,24 +2546,16 @@
 ion %3E 1)
-%0A       
  throw n
@@ -2596,16 +2596,390 @@
 er and c
+ategorical fractions must add up to %3C= 1.%22);%0A      if (Math.abs(missing_fraction) %3E 1) throw new IllegalArgumentException(%22Missing fraction must be between 0 and 1.%22);%0A      if (Math.abs(integer_fraction) %3E 1) throw new IllegalArgumentException(%22Integer fraction must be between 0 and 1.%22);%0A      if (Math.abs(categorical_fraction) %3E 1) throw new IllegalArgumentException(%22C
 ategoric
@@ -2993,35 +2993,190 @@
 tion
-s
  must 
-add up to %3C= 1
+be between 0 and 1.%22);%0A      if (response_factors %3C 1) throw new IllegalArgumentException(%22Response factors must be either 1 (real-valued response), or %3E=2 (factor levels)
 .%22);%0A
-%0A
     
@@ -3204,24 +3204,16 @@
 ws %3C= 0)
-%0A       
  throw n

Add more range checks to createFrame.