// ***** This file is automatically generated from ThreeScalar.java.jpp
package daikon.inv.ternary.threeScalar;

import daikon.*;
import daikon.inv.*;
import daikon.inv.ternary.TernaryInvariant;
import org.checkerframework.checker.interning.qual.Interned;
import org.checkerframework.checker.lock.qual.GuardSatisfied;
import org.plumelib.util.Intern;
import typequals.prototype.qual.NonPrototype;
import typequals.prototype.qual.Prototype;

/**
 * Abstract base class for invariants over three numeric variables. An example is {@code z = ax + by
 * + c}.
 */
public abstract class ThreeFloat extends TernaryInvariant {
  static final long serialVersionUID = 20020122L;

  protected ThreeFloat(PptSlice ppt) {
    super(ppt);
  }

  protected @Prototype ThreeFloat() {
    super();
  }

  @Override
  public final boolean valid_types(VarInfo[] vis) {

    return ((vis.length == 3)
            && vis[0].file_rep_type.isFloat()
            && vis[1].file_rep_type.isFloat()
            && vis[2].file_rep_type.isFloat());
  }

  public VarInfo var1(@GuardSatisfied ThreeFloat this) {
    return ppt.var_infos[0];
  }

  public VarInfo var2(@GuardSatisfied ThreeFloat this) {
    return ppt.var_infos[1];
  }

  public VarInfo var3(@GuardSatisfied ThreeFloat this) {
    return ppt.var_infos[2];
  }

  @Override
  public InvariantStatus check(@Interned Object val1, @Interned Object val2, @Interned Object val3, int mod_index, int count) {
    // Tests for whether a value is missing should be performed before
    // making this call, so as to reduce overall work.
    assert ! falsified;
    if ((mod_index < 0) || (mod_index > 8)) {
      assert (mod_index >= 0) && (mod_index < 8)
        : "var 1 " + ppt.var_infos[0].name() + " value = "
         + val1 + "mod_index = " +  mod_index;
    }
    double v1 = ((Double) val1).doubleValue();
    double v2 = ((Double) val2).doubleValue();
    if (!(val3 instanceof Double)) {
      System.out.println("val3 should be PRIMITIVE, but is " + val3.getClass());
    }
    double v3 = ((Double) val3).doubleValue();
    if (mod_index == 0) {
      return check_unmodified(v1, v2, v3, count);
    } else {
      return check_modified(v1, v2, v3, count);
    }
  }

  @Override
  public InvariantStatus add(@Interned Object val1, @Interned Object val2, @Interned Object val3, int mod_index, int count) {
    // Tests for whether a value is missing should be performed before
    // making this call, so as to reduce overall work.
    assert ! falsified;
    if ((mod_index < 0) || (mod_index > 8)) {
      assert (mod_index >= 0) && (mod_index < 8)
        : "var 1 " + ppt.var_infos[0].name() + " value = "
         + val1 + "mod_index = " +  mod_index + " line "
         + FileIO.get_linenum();
    }
    double v1 = ((Double) val1).doubleValue();
    double v2 = ((Double) val2).doubleValue();
    if (!(val3 instanceof Double)) {
      System.out.printf("val3 should be PRIMITIVE, but is %s=%s, v2 is %s=%s%n",
              val3.getClass().getName(), Debug.toString(val3),
              val2.getClass().getName(), Debug.toString(val2));
      System.out.println("our class = " + this.getClass().getName());
      System.out.println("our slice = " + this.ppt);
      PptSlice slice = this.ppt;
      System.out.printf("var3 reptype = %s%n", slice.var_infos[2].rep_type);
      assert (slice.var_infos[0].rep_type == ProglangType.INT)
                  && (slice.var_infos[1].rep_type == ProglangType.INT)
                  && (slice.var_infos[2].rep_type == ProglangType.INT);
    }
    double v3 = ((Double) val3).doubleValue();
    if (mod_index == 0) {
      return add_unmodified(v1, v2, v3, count);
    } else {
      return add_modified(v1, v2, v3, count);
    }
  }

  /**
   * Presents a sample to the invariant. Returns whether the sample is consistent with the
   * invariant. Does not change the state of the invariant.
   *
   * @param count how many identical samples were observed in a row. For example, three calls to
   * check_modified with a count parameter of 1 is equivalent to one call to check_modified with a
   * count parameter of 3.
   * @return true if the sample is consistent with the invariant
   */
  public abstract InvariantStatus check_modified(double v1, double v2, double v3, int count);

  public InvariantStatus check_unmodified(double v1, double v2, double v3, int count) {
    return InvariantStatus.NO_CHANGE;
  }

  /**
   * Similar to {@link #check_modified} except that it can change the state of the invariant if
   * necessary. If the invariant doesn't have any state, then the implementation should simply call
   * {@link #check_modified}. This method need not check for falsification; that is done by the
   * caller.
   */
  public abstract InvariantStatus add_modified(double v1, double v2, double v3, int count);

  /** By default, do nothing if the value hasn't been seen yet. Subclasses can override this. */
  public InvariantStatus add_unmodified(double v1, double v2, double v3, int count) {
    return InvariantStatus.NO_CHANGE;
  }
}
