package nxm.sys.libm;

import nxm.sys.inc.Constants;

/**
   Performs the LogarithmBounded operation on arrays. <br>
   See {@link Operator} for a description of the available I/O Modes.
   @author  Auto-Generated
   @see     Operator
*/
@SuppressWarnings("cast")
public final class LogarithmBounded extends Operator implements Constants {

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

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

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

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

  public final int validate (char type, int n, int mode) {
    switch (mode) {
      case SS: return n;
      case CS: return n;
      case VS: return n;
      default: return NOSUPPORT;
    }
  }

  public final int process (double[][] v, int n, int mode) {
    switch (mode) {
      case SS: SS(v[0],v[1],n, scale); return n;
      case CS: CS(v[0],v[1],n, scale); return n;
      case VS: VS(v[0],v[1],n, scale); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (double[][] v, int n, int mode, double scale) {
    switch (mode) {
      case SS: SS(v[0],v[1],n, scale); return n;
      case CS: CS(v[0],v[1],n, scale); return n;
      case VS: VS(v[0],v[1],n, scale); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#SS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(double[][],int,int,double)
   */
  public static final void SS (double[] a, double[] b, int n, double scale) {
      for (int i=0; i<n; i++) {
        b[i]=(double)(scale*Math.log(Math.max(1e-12,(double)Math.abs(a[i]))));
      }
  }

  /** Apply this operator to mode {@link Operator#CS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(double[][],int,int,double)
   */
  public static final void CS (double[] a, double[] b, int n, double scale) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        b[i]=(double)(scale*Math.log(Math.max(1e-12,(double)(a[j]*a[j]+a[j+1]*a[j+1]))));
      }
  }

  /** Apply this operator to mode {@link Operator#VS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(double[][],int,int,double)
   */
  public static final void VS (double[] a, double[] b, int n, double scale) {
      for (int i=0,k=0; i<n; i++,k+=3) {
        b[i]=(double)(scale*Math.log(Math.max(1e-12,(double)(a[k]*a[k]+a[k+1]*a[k+1]+a[k+2]*a[k+2]))));
      }
  }

  public final int process (float[][] v, int n, int mode) {
    switch (mode) {
      case SS: SS(v[0],v[1],n, scale); return n;
      case CS: CS(v[0],v[1],n, scale); return n;
      case VS: VS(v[0],v[1],n, scale); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (float[][] v, int n, int mode, double scale) {
    switch (mode) {
      case SS: SS(v[0],v[1],n, scale); return n;
      case CS: CS(v[0],v[1],n, scale); return n;
      case VS: VS(v[0],v[1],n, scale); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#SS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(float[][],int,int,double)
   */
  public static final void SS (float[] a, float[] b, int n, double scale) {
      for (int i=0; i<n; i++) {
	// Jeff's logic change (original commented out below) since 3.9.0
        double aa=a[i]; if (aa<0) aa=-aa; if (aa<1e-12) aa=1e-12; // Change from Jeff since 3.9.0
        b[i]=(float)(scale*Math.log(aa));
//        b[i]=(float)(scale*Math.log(Math.max(1e-12,(double)Math.abs(a[i]))));
      }
  }

  /** Apply this operator to mode {@link Operator#CS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(float[][],int,int,double)
   */
  public static final void CS (float[] a, float[] b, int n, double scale) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        b[i]=(float)(scale*Math.log(Math.max(1e-12,(double)(a[j]*a[j]+a[j+1]*a[j+1]))));
      }
  }

  /** Apply this operator to mode {@link Operator#VS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(float[][],int,int,double)
   */
  public static final void VS (float[] a, float[] b, int n, double scale) {
      for (int i=0,k=0; i<n; i++,k+=3) {
        b[i]=(float)(scale*Math.log(Math.max(1e-12,(double)(a[k]*a[k]+a[k+1]*a[k+1]+a[k+2]*a[k+2]))));
      }
  }

  public final int process (int[][] v, int n, int mode) {
    switch (mode) {
      case SS: SS(v[0],v[1],n, scale); return n;
      case CS: CS(v[0],v[1],n, scale); return n;
      case VS: VS(v[0],v[1],n, scale); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (int[][] v, int n, int mode, double scale) {
    switch (mode) {
      case SS: SS(v[0],v[1],n, scale); return n;
      case CS: CS(v[0],v[1],n, scale); return n;
      case VS: VS(v[0],v[1],n, scale); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#SS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(int[][],int,int,double)
   */
  public static final void SS (int[] a, int[] b, int n, double scale) {
      for (int i=0; i<n; i++) {
        b[i]=(int)(scale*Math.log(Math.max(1e-12,(double)Math.abs(a[i]))));
      }
  }

  /** Apply this operator to mode {@link Operator#CS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(int[][],int,int,double)
   */
  public static final void CS (int[] a, int[] b, int n, double scale) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        b[i]=(int)(scale*Math.log(Math.max(1e-12,(double)(a[j]*a[j]+a[j+1]*a[j+1]))));
      }
  }

  /** Apply this operator to mode {@link Operator#VS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param n     The number of elements to operate on.
      @param scale The scale factor.
      @see #process(int[][],int,int,double)
   */
  public static final void VS (int[] a, int[] b, int n, double scale) {
      for (int i=0,k=0; i<n; i++,k+=3) {
        b[i]=(int)(scale*Math.log(Math.max(1e-12,(double)(a[k]*a[k]+a[k+1]*a[k+1]+a[k+2]*a[k+2]))));
      }
  }

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