package hex;

import water.Job;
import water.Key;
import water.fvec.Frame;
import water.fvec.FrameCreator;

import java.util.Random;

/**
 * Create a Frame from scratch
 * If randomize = true, then the frame is filled with Random values.
 */
public class CreateFrame extends Job<Frame> {
  public long rows = 10000;
  public int cols = 10;
  public long seed = new Random().nextLong();
  public boolean randomize = true;
  public long value = 0;
  public long real_range = 100;
  public double categorical_fraction = 0.2;
  public int factors = 100;
  public double integer_fraction = 0.2;
  public long integer_range = 100;
  public double binary_fraction = 0.1;
  public double binary_ones_fraction = 0.02;
  public double missing_fraction = 0.01;
  public int response_factors = 2;
  public boolean positive_response; // only for response_factors=1
  public boolean has_response = false;

  public CreateFrame(Key<Frame> dest, String desc) { super(dest, (desc == null ? "CreateFrame" : desc)); }
  public CreateFrame() { super(Key.make(), "CreateFrame"); }

  public Job<Frame> execImpl() {
    if (integer_fraction + binary_fraction + categorical_fraction > 1) throw new IllegalArgumentException("Integer, binary and categorical fractions must add up to <= 1.");
    if (Math.abs(missing_fraction) > 1) throw new IllegalArgumentException("Missing fraction must be between 0 and 1.");
    if (Math.abs(integer_fraction) > 1) throw new IllegalArgumentException("Integer fraction must be between 0 and 1.");
    if (Math.abs(binary_fraction) > 1) throw new IllegalArgumentException("Binary fraction must be between 0 and 1.");
    if (Math.abs(binary_ones_fraction) > 1) throw new IllegalArgumentException("Binary ones fraction must be between 0 and 1.");
    if (Math.abs(categorical_fraction) > 1) throw new IllegalArgumentException("Categorical fraction must be between 0 and 1.");
    if (categorical_fraction > 0 && factors <= 1) throw new IllegalArgumentException("Factors must be larger than 2 for categorical data.");
    if (response_factors < 1) throw new IllegalArgumentException("Response factors must be either 1 (real-valued response), or >=2 (factor levels).");
    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.");
    }
    if (_dest == null) throw new IllegalArgumentException("Destination key cannot be null.");

    FrameCreator fc = new FrameCreator(this, this._key);
    start(fc, fc.nChunks()*5);
    return this;
  }
}

@@ -7,16 +7,34 @@
 e hex;%0A%0A
+import water.H2O;%0A
 import w
@@ -117,16 +117,47 @@
 Creator;
+%0Aimport water.util.PrettyPrint;
 %0A%0Aimport
@@ -2232,112 +2232,1101 @@
 if (
-cols %3C= 0 %7C%7C rows %3C= 0) throw new IllegalArgumentException(%22Must have number of rows %3E 0 and columns %3E 1
+response_factors %3E 1024) throw new IllegalArgumentException(%22Response factors must be %3C= 1024.%22);%0A    if (factors %3E 1000000) throw new IllegalArgumentException(%22Number of factors must be %3C= 1,000,000).%22);%0A    if (cols %3C= 0 %7C%7C rows %3C= 0) throw new IllegalArgumentException(%22Must have number of rows %3E 0 and columns %3E 1.%22);%0A%0A    // estimate byte size of the frame%0A    double byte_estimate = randomize ? rows * cols * (%0A            binary_fraction * 1./8 //bits%0A                    + categorical_fraction * (factors %3C 128 ? 1 : factors %3C 32768 ? 2 : 4)%0A                    + integer_fraction * (integer_range %3C 128 ? 1 : integer_range %3C 32768 ? 2 : integer_range %3C (1%3C%3C31) ? 4 : 8)%0A                    + (1-integer_fraction - binary_fraction - categorical_fraction) * 8 ) //reals%0A            + rows * 1 //response is%0A            : 0; // all constants - should be small%0A%0A    if (byte_estimate %3E H2O.CLOUD._memary%5B0%5D.get_max_mem() * H2O.CLOUD.size())%0A      throw new IllegalArgumentException(%22Frame is expected to require %22 + PrettyPrint.bytes((long) byte_estimate) + %22, won't fit into H2O's memory
 .%22);

Add admission control for createFrame.