package nxm.sys.libm;

import nxm.sys.inc.Constants;

/**
   Performs the Multiply 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 Multiply extends Operator implements Constants {

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

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

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

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

  public final int validate (char type, int n, int mode) {
    switch (mode) {
      case SSS: return n;
      case CSC: return n;
      case SCC: return n;
      case CCC: return n;
      case GCC: return n;
      case CGC: return n;
      case VSV: return n;
      default: return NOSUPPORT;
    }
  }

  public final int process (double[][] v, int n, int mode) {
    switch (mode) {
      case SSS: SSS(v[0],v[1],v[2],n); return n;
      case CSC: CSC(v[0],v[1],v[2],n); return n;
      case SCC: SCC(v[0],v[1],v[2],n); return n;
      case CCC: CCC(v[0],v[1],v[2],n); return n;
      case GCC: GCC(v[0],v[1],v[2],n); return n;
      case CGC: CGC(v[0],v[1],v[2],n); return n;
      case VSV: VSV(v[0],v[1],v[2],n); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (double[][] v, int n, int mode, double scale) {
    switch (mode) {
      case SSS: SSS(v[0],v[1],v[2],n); return n;
      case CSC: CSC(v[0],v[1],v[2],n); return n;
      case SCC: SCC(v[0],v[1],v[2],n); return n;
      case CCC: CCC(v[0],v[1],v[2],n); return n;
      case GCC: GCC(v[0],v[1],v[2],n); return n;
      case CGC: CGC(v[0],v[1],v[2],n); return n;
      case VSV: VSV(v[0],v[1],v[2],n); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#SSS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(double[][],int,int)
   */
  public static final void SSS (double[] a, double[] b, double[] c, int n) {
    if (b.length == 1) {
      for (int i=0; i<n; i++) {
        c[i]=a[i]*b[0];
      }
    } else if (a.length == 1) {
      for (int i=0; i<n; i++) {
        c[i]=a[0]*b[i];
      }
    } else {
      for (int i=0; i<n; i++) {
        c[i]=a[i]*b[i];
      }
    }
  }

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

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

  /** Apply this operator to mode {@link Operator#CCC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(double[][],int,int)
   */
  public static final void CCC (double[] a, double[] b, double[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[j]*b[0]-a[j+1]*b[1]; c[j+1]=a[j+1]*b[0]+a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[0]*b[j]-a[1]*b[j+1]; c[j+1]=a[1]*b[j]+a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[j]*b[j]-a[j+1]*b[j+1]; c[j+1]=a[j+1]*b[j]+a[j]*b[j+1]; c[j]=t;
      }
    }
  }

  /** Apply this operator to mode {@link Operator#GCC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(double[][],int,int)
   */
  public static final void GCC (double[] a, double[] b, double[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[j]*b[0]+a[j+1]*b[1]; c[j+1]=-a[j+1]*b[0]+a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[0]*b[j]+a[1]*b[j+1]; c[j+1]=-a[1]*b[j]+a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[j]*b[j]+a[j+1]*b[j+1]; c[j+1]=-a[j+1]*b[j]+a[j]*b[j+1]; c[j]=t;
      }
    }
  }

  /** Apply this operator to mode {@link Operator#CGC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(double[][],int,int)
   */
  public static final void CGC (double[] a, double[] b, double[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[j]*b[0]+a[j+1]*b[1]; c[j+1]=a[j+1]*b[0]-a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[0]*b[j]+a[1]*b[j+1]; c[j+1]=a[1]*b[j]-a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        double t=a[j]*b[j]+a[j+1]*b[j+1]; c[j+1]=a[j+1]*b[j]-a[j]*b[j+1]; c[j]=t;
      }
    }
  }

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

  public final int process (float[][] v, int n, int mode) {
    switch (mode) {
      case SSS: SSS(v[0],v[1],v[2],n); return n;
      case CSC: CSC(v[0],v[1],v[2],n); return n;
      case SCC: SCC(v[0],v[1],v[2],n); return n;
      case CCC: CCC(v[0],v[1],v[2],n); return n;
      case GCC: GCC(v[0],v[1],v[2],n); return n;
      case CGC: CGC(v[0],v[1],v[2],n); return n;
      case VSV: VSV(v[0],v[1],v[2],n); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (float[][] v, int n, int mode, double scale) {
    switch (mode) {
      case SSS: SSS(v[0],v[1],v[2],n); return n;
      case CSC: CSC(v[0],v[1],v[2],n); return n;
      case SCC: SCC(v[0],v[1],v[2],n); return n;
      case CCC: CCC(v[0],v[1],v[2],n); return n;
      case GCC: GCC(v[0],v[1],v[2],n); return n;
      case CGC: CGC(v[0],v[1],v[2],n); return n;
      case VSV: VSV(v[0],v[1],v[2],n); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#SSS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(float[][],int,int)
   */
  public static final void SSS (float[] a, float[] b, float[] c, int n) {
    if (b.length == 1) {
      for (int i=0; i<n; i++) {
        c[i]=a[i]*b[0];
      }
    } else if (a.length == 1) {
      for (int i=0; i<n; i++) {
        c[i]=a[0]*b[i];
      }
    } else {
      for (int i=0; i<n; i++) {
        c[i]=a[i]*b[i];
      }
    }
  }

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

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

  /** Apply this operator to mode {@link Operator#CCC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(float[][],int,int)
   */
  public static final void CCC (float[] a, float[] b, float[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[j]*b[0]-a[j+1]*b[1]; c[j+1]=a[j+1]*b[0]+a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[0]*b[j]-a[1]*b[j+1]; c[j+1]=a[1]*b[j]+a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[j]*b[j]-a[j+1]*b[j+1]; c[j+1]=a[j+1]*b[j]+a[j]*b[j+1]; c[j]=t;
      }
    }
  }

  /** Apply this operator to mode {@link Operator#GCC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(float[][],int,int)
   */
  public static final void GCC (float[] a, float[] b, float[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[j]*b[0]+a[j+1]*b[1]; c[j+1]=-a[j+1]*b[0]+a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[0]*b[j]+a[1]*b[j+1]; c[j+1]=-a[1]*b[j]+a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[j]*b[j]+a[j+1]*b[j+1]; c[j+1]=-a[j+1]*b[j]+a[j]*b[j+1]; c[j]=t;
      }
    }
  }

  /** Apply this operator to mode {@link Operator#CGC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(float[][],int,int)
   */
  public static final void CGC (float[] a, float[] b, float[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[j]*b[0]+a[j+1]*b[1]; c[j+1]=a[j+1]*b[0]-a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[0]*b[j]+a[1]*b[j+1]; c[j+1]=a[1]*b[j]-a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        float t=a[j]*b[j]+a[j+1]*b[j+1]; c[j+1]=a[j+1]*b[j]-a[j]*b[j+1]; c[j]=t;
      }
    }
  }

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

  public final int process (int[][] v, int n, int mode) {
    switch (mode) {
      case SSS: SSS(v[0],v[1],v[2],n); return n;
      case CSC: CSC(v[0],v[1],v[2],n); return n;
      case SCC: SCC(v[0],v[1],v[2],n); return n;
      case CCC: CCC(v[0],v[1],v[2],n); return n;
      case GCC: GCC(v[0],v[1],v[2],n); return n;
      case CGC: CGC(v[0],v[1],v[2],n); return n;
      case VSV: VSV(v[0],v[1],v[2],n); return n;
      default:  return NOSUPPORT;
    }
  }

  public final int process (int[][] v, int n, int mode, double scale) {
    switch (mode) {
      case SSS: SSS(v[0],v[1],v[2],n); return n;
      case CSC: CSC(v[0],v[1],v[2],n); return n;
      case SCC: SCC(v[0],v[1],v[2],n); return n;
      case CCC: CCC(v[0],v[1],v[2],n); return n;
      case GCC: GCC(v[0],v[1],v[2],n); return n;
      case CGC: CGC(v[0],v[1],v[2],n); return n;
      case VSV: VSV(v[0],v[1],v[2],n); return n;
      default:  return NOSUPPORT;
    }
  }

  /** Apply this operator to mode {@link Operator#SSS} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public static final void SSS (int[] a, int[] b, int[] c, int n) {
    if (b.length == 1) {
      for (int i=0; i<n; i++) {
        c[i]=a[i]*b[0];
      }
    } else if (a.length == 1) {
      for (int i=0; i<n; i++) {
        c[i]=a[0]*b[i];
      }
    } else {
      for (int i=0; i<n; i++) {
        c[i]=a[i]*b[i];
      }
    }
  }

  /** Apply this operator to mode {@link Operator#CSC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public static final void CSC (int[] a, int[] b, int[] c, int n) {
    if (b.length == 1) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        c[j]=a[j]*b[0]; c[j+1]=a[j+1]*b[0];
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        c[j]=a[0]*b[i]; c[j+1]=a[1]*b[i];
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        c[j]=a[j]*b[i]; c[j+1]=a[j+1]*b[i];
      }
    }
  }

  /** Apply this operator to mode {@link Operator#SCC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public static final void SCC (int[] a, int[] b, int[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        c[j]=a[i]*b[0]; c[j+1]=a[i]*b[1];
      }
    } else if (a.length == 1) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        c[j]=a[0]*b[j]; c[j+1]=a[0]*b[j+1];
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        c[j]=a[i]*b[j]; c[j+1]=a[i]*b[j+1];
      }
    }
  }

  /** Apply this operator to mode {@link Operator#CCC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public static final void CCC (int[] a, int[] b, int[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[j]*b[0]-a[j+1]*b[1]; c[j+1]=a[j+1]*b[0]+a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[0]*b[j]-a[1]*b[j+1]; c[j+1]=a[1]*b[j]+a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[j]*b[j]-a[j+1]*b[j+1]; c[j+1]=a[j+1]*b[j]+a[j]*b[j+1]; c[j]=t;
      }
    }
  }

  /** Apply this operator to mode {@link Operator#GCC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public static final void GCC (int[] a, int[] b, int[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[j]*b[0]+a[j+1]*b[1]; c[j+1]=-a[j+1]*b[0]+a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[0]*b[j]+a[1]*b[j+1]; c[j+1]=-a[1]*b[j]+a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[j]*b[j]+a[j+1]*b[j+1]; c[j+1]=-a[j+1]*b[j]+a[j]*b[j+1]; c[j]=t;
      }
    }
  }

  /** Apply this operator to mode {@link Operator#CGC} data.
      @param a     The first  operand.
      @param b     The second  operand.
      @param c     The third  operand.
      @param n     The number of elements to operate on.
      @see #process(int[][],int,int)
   */
  public static final void CGC (int[] a, int[] b, int[] c, int n) {
    if (b.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[j]*b[0]+a[j+1]*b[1]; c[j+1]=a[j+1]*b[0]-a[j]*b[1]; c[j]=t;
      }
    } else if (a.length == 2) {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[0]*b[j]+a[1]*b[j+1]; c[j+1]=a[1]*b[j]-a[0]*b[j+1]; c[j]=t;
      }
    } else {
      for (int i=0,j=0; i<n; i++,j+=2) {
        int t=a[j]*b[j]+a[j+1]*b[j+1]; c[j+1]=a[j+1]*b[j]-a[j]*b[j+1]; c[j]=t;
      }
    }
  }

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

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