package nxm.dsp.lib;

import nxm.sys.inc.Constants;
import nxm.sys.lib.Convert;
import nxm.sys.lib.MidasException;
import nxm.sys.lib.Shell;

/**
  Structure for a DSP Library

  This function may have implementations in more than one language.

  The NeXtMidas policy is to code DSP functions in C or Fortran to allow
  code sharing with other versions of Midas.  All other framework and GUI
  code is in Java for portability and deployment options.

  Typically, DSP functions needed by GUIs are included in the SYS tree.
  Some functions are coded here in Java and in C for performance comparisons.

  The Java code for each function library exposes methods for setting and
  getting each of the library's properties.  If native code is used, the
  Java wrapper loads the native code and calls the standard library interface
  routines as appropriate.

  If a library has native code, it should override the hasNative() method to
  return true, and provide the code in a &lt;className&gt;.c file.

  Native code libraries should have the following methods:
    alloc()  -  allocates the handle to an instance of this library
    setkey() -  sets a parameter
    getkey() -  gets a parameter
    init()   -  initialize the library for the current set of parameters
    work()   -  perform the desired function on a segment of data
    free()   -  release all resources

  @author Jeff Schoen
*/
public class DSPLib extends Object implements Constants {

  protected long handle;
  protected boolean useNative;

  /** allocates the handle to an instance of this library
   *  @return handle value for an instance of this library
   */
  public native long alloc();
  /** sets a parameter
   *  @param handle the handle to an instance of this library
   *  @param key    index to key
   *  @param value  buffer containing the value
   *  @param len    length of buffer
   *  @return 0 if successful, otherwise -1 if invalid key index
   */
  public native int setkey (long handle, int key, byte[] value, int len);
  /** Gets a parameter
   *  @param handle the handle to an instance of this library
   *  @param key    index to key
   *  @param value  buffer for the value
   *  @param len    length of buffer
   *  @return 0 if successful, otherwise -1 if invalid key index
   */
  public native int getkey (long handle, int key, byte[] value, int len);
  /** Initialize
   *  @param handle the handle/pointer to an instance of this library
   *  @return status code 0
   */
  public native int init (long handle);
  /** Process data for native DSP library
   *  @param handle the handle/pointer to an instance of this library
   *  @return status code 0
   */
  public native int work (long handle);
  /** Deallocate storage space for native DSP library
   *  @param handle handler for native DSP library
   *  @return status code 0
   */
  public native int free (long handle);

  /** Get whether this function has native code implementation
   *  @return whether this function has native code implementation. */
  public boolean hasNative() {
    return false;
  }

  /** Create an instance of this function with optional native implementation.
      @param useNative try to use native code if available
   */
  public DSPLib (boolean useNative) {
    if (useNative && hasNative()) {
      this.useNative = Shell.loadLibrary(getClass().getName());
      if (this.useNative) {
        handle = alloc();
        if (handle==0) throw new MidasException ("Problem with native library alloc()");
      }
    }
  }

  /** Open
   *  @return status code 0
   */
  public int open() {
    if (useNative) return init(handle);
    return 0;
  }

  /** Process
   *  @return status code 0
   */
  public int process() {
    if (useNative) return work(handle);
    return 0;
  }

  /** Close and free the allocated memory
   *  @return status code 0
   */
  public int close() {
    if (useNative) return free(handle);
    return 0;
  }

  /** SetKey helper for native library double parameter.
      @param key   index to key
      @param value double parameter to store at key index
   */
  public void setKeyD (int key, double value) {
    byte[] buffer = new byte[8];
    Convert.packD(buffer,0,value);
    if (setkey (handle, key, buffer, 8) < 0)
      throw new MidasException ("Problem setting key="+key+" to value="+value);
  }
  /** GetKey helper for native library double parameter.
      @param key index to key
      @return double parameter at specified key index
   */
  public double getKeyD (int key) {
    byte[] buffer = new byte[8];
    if (getkey (handle, key, buffer, 8) < 0)
      throw new MidasException ("Problem getting key="+key);
    return Convert.unpackD(buffer,0);
  }

  /** SetKey helper for native library float parameter.
      @param key index to key
      @param value float parameter to store at key index
   */
  public void setKeyF (int key, float value) {
    byte[] buffer = new byte[4];
    Convert.packF(buffer,0,value);
    if (setkey (handle, key, buffer, 4) < 0)
      throw new MidasException ("Problem setting key="+key+" to value="+value);
  }
  /** GetKey helper for native library float parameter.
      @param key index to key
      @return float parameter to store at key index
   */
  public float getKeyF (int key) {
    byte[] buffer = new byte[4];
    if (getkey (handle, key, buffer, 4) < 0)
      throw new MidasException ("Problem getting key="+key);
    return Convert.unpackF(buffer,0);
  }

  /** SetKey helper for native library int parameter.
      @param key index to key
      @param value int parameter to store at key index
   */
  public void setKeyL (int key, int value) {
    byte[] buffer = new byte[4];
    Convert.packL(buffer,0,value);
    if (setkey (handle, key, buffer, 4) < 0)
      throw new MidasException ("Problem setting key="+key+" to value="+value);
  }
  /** GetKey helper for native library int parameter.
      @param key index to key
      @return int parameter at key index
   */
  public int getKeyL (int key) {
    byte[] buffer = new byte[4];
    if (getkey (handle, key, buffer, 4) < 0)
      throw new MidasException ("Problem getting key="+key);
    return Convert.unpackL(buffer,0);
  }

}
