package nxm.sys.libm;

import nxm.sys.inc.Constants;

/**
   Performs the RandomSecure operation on arrays. <br>
   Cryptographically strong pseudo-random number generator (PRNG) using java.security.SecureRandom. <br>
   See {@link Operator} for a description of the available I/O Modes.
   @author  Auto-Generated
   @see     Operator
*/
@SuppressWarnings("cast")
public final class RandomSecure extends Operator implements Constants {

  /* Parameter declarations. */
  private static final java.security.SecureRandom prng = new java.security.SecureRandom();

  /** Create a new instance. */
  public RandomSecure() {
    super();
  }

  /** Create a new instance.
      @param flags The processing flags to use.
   */
  public RandomSecure (int flags) {
    super(flags);
  }

  /** Create a new instance.
      @param scale The scale factor to use.
   */
  public RandomSecure (double scale) {
    super(scale);
  }

  /** Create a new instance.
      @param flags The processing flags to use.
      @param scale The scale factor to use.
   */
  public RandomSecure (int flags, double scale) {
    super(flags,scale);
  }

  public final int validate (char type, int n, int mode) {
    switch (mode) {
      case S: return n;
      case C: return n;
      case V: return n;
      default: return NOSUPPORT;
    }
  }

  public final int process (double[][] v, int n, int mode) {
    switch (mode) {
      case S: S(v[0],n); return n;
      case C: C(v[0],n); return n;
      case V: V(v[0],n); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (double[][] v, int n, int mode, double scale) {
    switch (mode) {
      case S: S(v[0],n); return n;
      case C: C(v[0],n); return n;
      case V: V(v[0],n); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#S} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(double[][],int,int)
   */
  public final void S (double[] a, int n) {
      for (int i=0; i<n; i++) {
        a[i]=(double)prng.nextDouble();
      }
  }

  /** Apply this operator to mode {@link Operator#C} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(double[][],int,int)
   */
  public final void C (double[] a, int n) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        a[j]=(double)prng.nextDouble();
        a[j+1]=(double)prng.nextDouble();
      }
  }

  /** Apply this operator to mode {@link Operator#V} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(double[][],int,int)
   */
  public final void V (double[] a, int n) {
      for (int i=0,k=0; i<n; i++,k+=3) {
        a[k]=(double)prng.nextDouble();
        a[k+1]=(double)prng.nextDouble();
        a[k+2]=(double)prng.nextDouble();
      }
  }

  public final int process (float[][] v, int n, int mode) {
    switch (mode) {
      case S: S(v[0],n); return n;
      case C: C(v[0],n); return n;
      case V: V(v[0],n); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (float[][] v, int n, int mode, double scale) {
    switch (mode) {
      case S: S(v[0],n); return n;
      case C: C(v[0],n); return n;
      case V: V(v[0],n); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#S} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(float[][],int,int)
   */
  public final void S (float[] a, int n) {
      for (int i=0; i<n; i++) {
        a[i]=(float)prng.nextDouble();
      }
  }

  /** Apply this operator to mode {@link Operator#C} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(float[][],int,int)
   */
  public final void C (float[] a, int n) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        a[j]=(float)prng.nextDouble();
        a[j+1]=(float)prng.nextDouble();
      }
  }

  /** Apply this operator to mode {@link Operator#V} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(float[][],int,int)
   */
  public final void V (float[] a, int n) {
      for (int i=0,k=0; i<n; i++,k+=3) {
        a[k]=(float)prng.nextDouble();
        a[k+1]=(float)prng.nextDouble();
        a[k+2]=(float)prng.nextDouble();
      }
  }

  public final int process (int[][] v, int n, int mode) {
    switch (mode) {
      case S: S(v[0],n); return n;
      case C: C(v[0],n); return n;
      case V: V(v[0],n); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (int[][] v, int n, int mode, double scale) {
    switch (mode) {
      case S: S(v[0],n); return n;
      case C: C(v[0],n); return n;
      case V: V(v[0],n); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#S} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public final void S (int[] a, int n) {
      for (int i=0; i<n; i++) {
        a[i]=(int)prng.nextDouble();
      }
  }

  /** Apply this operator to mode {@link Operator#C} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public final void C (int[] a, int n) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        a[j]=(int)prng.nextDouble();
        a[j+1]=(int)prng.nextDouble();
      }
  }

  /** Apply this operator to mode {@link Operator#V} data.
      @param a     The first  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public final void V (int[] a, int n) {
      for (int i=0,k=0; i<n; i++,k+=3) {
        a[k]=(int)prng.nextDouble();
        a[k+1]=(int)prng.nextDouble();
        a[k+2]=(int)prng.nextDouble();
      }
  }

  public int getInputs() { return 0; }
  public int getOutputs() { return 1; }
}
