package nxm.sys.libm;

import static java.lang.Math.cos;
import static nxm.sys.inc.Constants.TWOPI;

/** Class to create windows, primarily for Fft functions.

    @author Jeff Schoen
    @version $Id: Window.java,v 1.8 2015/09/10 19:47:32 ntn Exp $
 */
public class Window extends Object {
  /** Prevent instantiation since all methods are static. */
  private Window () { } // private since 3.7.0, it was deprecated in 3.3.1

  /** List of all the possible Windows available */
  public static String nameList = "None,Hanning,Hamming,Bartlett,Blackman,BH61,BH67,BH74,BH92";

  /** Calls {@link #get(String, int, double, boolean)} to retrieve the Window buffer array
      @param name  Window name
      @param size  Window size
      @param scale Window scale
      @return Window buffer array
   */
  public static float[] get (String name, int size, double scale) {
    return (size<0)? get(name,-size,scale,true )
                   : get(name, size,scale,false);
  }

  // Although this is a cleaner implementation, it is significantly slower (by a
  // factor of two). When profiling the code during a run of %TEST_TUNER, this
  // used up more CPU time than FFt.init(..) or FFt.process(..). The underlying
  // cause appears to be the unnecessary trig calls in the loop for Hanning/Hamming
  // filters and other unnecessary floating-point math operations.
  //
  //  public static float[] get (String name, int size, double scale, boolean symmetric) {
  //    int i, sizeh;
  //    double c0=0, c1=0, c2=0, c3=0, a,d;
  //    float[] buf = new float[size];
  //    if (symmetric) size--;
  //    sizeh = size/2;
  //    name = name.toUpperCase();
  //         if (name.startsWith("NONE")) for (i=0; i<=sizeh; i++) buf[i]=1;
  //    else if (name.startsWith("BART")) for (i=0; i<=sizeh; i++) buf[i]=((float)i)/(float)sizeh;
  //    else if (name.startsWith("HANN")) { c0=0.5; c1=-0.5; }
  //    else if (name.startsWith("HAMM")) { c0=0.54; c1=-0.46; }
  //    else if (name.startsWith("BLAC")) { c0=0.42; c1=-0.5; c2=0.08; }
  //    else if (name.startsWith("BH61")) { c0=0.44959; c1=-0.49364; c2=0.05677; }
  //    else if (name.startsWith("BH67")) { c0=0.42323; c1=-0.49755; c2=0.07922; }
  //    else if (name.startsWith("BH74")) { c0=0.40217; c1=-0.49703; c2=0.09897; c3=-.00183; }
  //    else if (name.startsWith("BH92")) { c0=0.35875; c1=-0.48829; c2=0.14128; c3=-.01168; }
  //    else return null;
  //    if (c0!=0) for (i=0; i<=sizeh; i++) {
  //      a = 2*Math.PI*(double)i/(double)size;
  //      d = c0 + c1*Math.cos(a) + c2*Math.cos(2*a) + c3*Math.cos(3*a);
  //      buf[i] = (float)d;
  //    }
  //    for (i=sizeh+1; i<size; i++) buf[i] = buf[size-i];
  //    if (scale!=1) for (i=0; i<size; i++) buf[i] = (float)scale*buf[i];
  //    if (symmetric) buf[size] = buf[0];
  //    return buf;
  //  }

  /** Gets the array representation of a Window buffer
      @param name      Window name
      @param size      Window size
      @param scale     Window scale
      @param symmetric whether or not the Window is symmetric
      @return Window buffer array
   */
  public static float[] get (String name, int size, double scale, boolean symmetric) {
    float[] buf = new float[size];
    if (symmetric) size--;

    int     sizeh      = size/2;
    double  twoPi_Size = TWOPI / size;

    name = name.toUpperCase();
    if (name.startsWith("NONE")) {
      float fscale = (float)scale;
      for (int i=0; i<=sizeh; i++) {
        buf[i] = fscale;
      }
    }
    else if (name.startsWith("BART")) {
      float fscale = (float)scale;
      float fsizeh = (float)sizeh;
      for (int i=0; i<=sizeh; i++) {
        buf[i] = (i / fsizeh) * fscale;
      }
    }
    else if (name.startsWith("HANN")) {
      for (int i=0; i<=sizeh; i++) {
        double a = twoPi_Size * i;
        double d = 0.5 - 0.5*cos(a);
        buf[i] = (float)(d * scale);
      }
    }
    else if (name.startsWith("HAMM")) {
      for (int i=0; i<=sizeh; i++) {
        double a = twoPi_Size * i;
        double d = 0.54 - 0.46*cos(a);
        buf[i] = (float)(d * scale);
      }
    }
    else if (name.startsWith("BLAC")) {
      for (int i=0; i<=sizeh; i++) {
        double a = twoPi_Size * i;
        double d = 0.42 - 0.50*cos(a) + 0.08*cos(2*a);
        buf[i] = (float)(d * scale);
      }
    }
    else if (name.startsWith("BH61")) {
      for (int i=0; i<=sizeh; i++) {
        double a = twoPi_Size * i;
        double d = 0.44959 - 0.49364*cos(a) + 0.05677*cos(2*a);
        buf[i] = (float)(d * scale);
      }
    }
    else if (name.startsWith("BH67")) {
      for (int i=0; i<=sizeh; i++) {
        double a = twoPi_Size * i;
        double d = 0.42323 - 0.49755*cos(a) + 0.07922*cos(2*a);
        buf[i] = (float)(d * scale);
      }
    }
    else if (name.startsWith("BH74")) {
      for (int i=0; i<=sizeh; i++) {
        double a = twoPi_Size * i;
        double d = 0.40217 - 0.49703*cos(a) + 0.09897*cos(2*a) - 0.00183*cos(3*a);
        buf[i] = (float)(d * scale);
      }
    }
    else if (name.startsWith("BH92")) {
      for (int i=0; i<=sizeh; i++) {
        double a = twoPi_Size * i;
        double d = 0.35875 - 0.48829*cos(a) + 0.14128*cos(2*a) - 0.01168*cos(3*a);
        buf[i] = (float)(d * scale);
      }
    }
    else {
      return null;
    }

    for (int i=sizeh+1; i<size; i++) buf[i] = buf[size-i];
    if (symmetric) buf[size] = buf[0];
    return buf;
  }
}
