// file: $isip/class/mmedia/AlgorithmData/AlgorithmData.h
// version: $Id: AlgorithmData.h 10603 2006-08-17 20:12:25Z ss754 $
//

// make sure definitions are only made once
//
#ifndef ISIP_ALGORITHM_DATA
#define ISIP_ALGORITHM_DATA

// isip include files
//
#ifndef ISIP_VECTOR_FLOAT
#include <VectorFloat.h>
#endif

#ifndef ISIP_VECTOR_DOUBLE
#include <VectorDouble.h>
#endif

#ifndef ISIP_VECTOR_COMPLEX_FLOAT
#include <VectorComplexFloat.h>
#endif

#ifndef ISIP_MATRIX_FLOAT
#include <MatrixFloat.h>
#endif

#ifndef ISIP_MATRIX_COMPLEX_FLOAT
#include <MatrixComplexFloat.h>
#endif

#ifndef ISIP_VECTOR_COMPLEX_DOUBLE
#include <VectorComplexDouble.h>
#endif

#ifndef ISIP_MATRIX_DOUBLE
#include <MatrixDouble.h>
#endif

#ifndef ISIP_MATRIX_COMPLEX_DOUBLE
#include <MatrixComplexDouble.h>
#endif

#ifndef ISIP_VECTOR
#include <Vector.h>
#endif

#ifndef ISIP_DEBUG_LEVEL
#include <DebugLevel.h>
#endif

// AlgorithmData: a class that defines an interface contract for the
// data passed to all Algorithms. This is the lowest-level class for
// mmedia library and the algo library and is used to encapsulate the
// different data formats one can pass to FrontEnd.
//
class AlgorithmData {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:

  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------
  
  // define the enumeration for data type
  //
  enum DATA_TYPE { NONE = 0,
		   VECTOR_FLOAT, VECTOR_COMPLEX_FLOAT, 
		   MATRIX_FLOAT, MATRIX_COMPLEX_FLOAT,
		   VECTOR_DOUBLE, VECTOR_COMPLEX_DOUBLE, 
		   MATRIX_DOUBLE, MATRIX_COMPLEX_DOUBLE,
		   COMBINATION,
		   DEF_DTYPE = NONE };
  
  // define the enumeration for coefficient type:
  //  note that we only list those types that are stand-alone data types
  //  with well-defined meanings in terms of signal processing. a class
  //  such as Calculus, that operates on generic types of data, is not
  //  listed. a class such as Cepstrum is not listed also because Cepstrum
  //  can be treated as a SIGNAL from a coefficient-type perspective.
  //  in general, the types listed here are those types for which customized
  //  Features exist (for example computing the spectrum from linear
  //  prediction coefficients requires a data-specific Feature).
  //  
  enum COEF_TYPE { GENERIC = 0, PROPAGATE, SIGNAL, SPECTRUM,
		   CORRELATION, COVARIANCE, ENERGY, FILTER,
		   LOG_AREA_RATIO, PREDICTION, REFLECTION,
		   RPS, LYAPUNOV, CORRELATION_INTEGRAL, 
  		   MUTUAL_INFORMATION, CORRELATION_ENTROPY,
  		   CORRELATION_DIMENSION,
  		   DEF_CTYPE = GENERIC };

  // define static NameMap objects
  //
  static const NameMap DTYPE_MAP;
  static const NameMap CTYPE_MAP;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------
  
  static const String DEF_PARAM;
  static const String PARAM_DATA_TYPE;
  static const String PARAM_COEF_TYPE;
  static const String PARAM_DATA;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 50300;
  static const long ERR_TYPE = 50301;

  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------

protected:

  // define the type of the data (vector, matrix, etc.)
  //
  DATA_TYPE data_type_d;

  // define the type of coefficient
  //
  COEF_TYPE coef_type_d;
  
  // a pointer to the data itself
  //
  void* data_d;

  // define a debug level
  //
  static DebugLevel debug_level_d;

  // define the memory manager
  //
  static MemoryManager mgr_d;

  /*  VectorFloat tmp_vec_f_d;
  VectorDouble tmp_vec_d_d;
  MatrixFloat tmp_mat_f_d;
  MatrixDouble tmp_mat_d_d;
  VectorComplexFloat tmp_vec_cf_d;
  VectorComplexDouble tmp_vec_cd_d;
  MatrixComplexFloat tmp_mat_cf_d;
  MatrixComplexDouble tmp_mat_cd_d;
  */

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }

  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);

  // method: setDebug
  //
  boolean setDebug(Integral::DEBUG level) {
    return debug_level_d.assign(level);
  }

  // other debug methods
  //
  boolean debug(const unichar* message) const;

  // method: destructor
  //
  ~AlgorithmData() {
    if (data_d != (void*)NULL) {
      //      (reinterpret_cast <MatrixFloat*> (data_d))->~MatrixFloat();
      //      tmp_mat_f_d.clear();
      //      data_d = (void*)NULL;
      setDataType(NONE);
    }
  }

  // method: default constructor
  //
  AlgorithmData(DATA_TYPE arg = DEF_DTYPE) {
    data_type_d = NONE;
    coef_type_d = DEF_CTYPE;
    data_d = (void*)NULL;
    if (arg != NONE) {
      setDataType(arg);
    }
  }

  // method: copy constructor
  //
  AlgorithmData(const AlgorithmData& arg) {
    data_type_d = NONE;
    coef_type_d = DEF_CTYPE;
    data_d = (void*)NULL;
    assign(arg);
  }
  
  // assign methods
  //
  boolean assign(const AlgorithmData& input_a);

  // method: operator=
  //
  AlgorithmData& operator= (const AlgorithmData& copy_node) {
    assign(copy_node);
    return *this;
  }
  
  // i/o methods
  //

  // method: sofSize
  //
  long sofSize() const;

  // method: read
  //
  boolean read(Sof& sof, long tag, const String& cname = CLASS_NAME);
  
  // method: write
  //
  boolean write(Sof& sof, long tag, const String& cname = CLASS_NAME) const;

  // method: readData
  //
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
		   long size = SofParser::FULL_OBJECT,
		   boolean param = true,
		   boolean nested = false);

  // method: writeData
  //
  boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;


  // equality methods
  //
  boolean eq(const AlgorithmData& arg) const;

  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  // other memory-management methods
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set methods
  //
  //---------------------------------------------------------------------------

  // set methods
  //
  boolean setDataType(DATA_TYPE dtype);

  // method: setCoefType
  //
  boolean setCoefType(COEF_TYPE ctype) {
    coef_type_d = ctype;
    return true;
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  get methods
  //
  //---------------------------------------------------------------------------
  
  // method: getDataType
  //
  DATA_TYPE getDataType() const {
    return data_type_d;
  }

  // method: getCoefType
  //
  COEF_TYPE getCoefType() const {
    return coef_type_d;
  }

  // method: getVectorFloat
  //
  const VectorFloat& getVectorFloat() const {
    if (data_type_d != VECTOR_FLOAT) {
      Error::handle(name(), L"getVectorFloat", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorFloat* > (data_d));
  }

  // method: getVectorFloat
  //
  VectorFloat& getVectorFloat() {
    if (data_type_d != VECTOR_FLOAT) {
      Error::handle(name(), L"getVectorFloat", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorFloat* > (data_d));
  }

  // method: getVectorComplexFloat
  //
  const VectorComplexFloat& getVectorComplexFloat() const {
    if (data_type_d != VECTOR_COMPLEX_FLOAT) {
      Error::handle(name(), L"getVectorComplexFloat", ERR_TYPE,
		    __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorComplexFloat* > (data_d));
  }

  // method: getVectorComplexFloat
  //
  VectorComplexFloat& getVectorComplexFloat() {
    if (data_type_d != VECTOR_COMPLEX_FLOAT) {
      Error::handle(name(), L"getVectorComplexFloat",
		    ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorComplexFloat* > (data_d));
  }

  // method: getMatrixFloat
  //
  const MatrixFloat& getMatrixFloat() const {
    if (data_type_d != MATRIX_FLOAT) {
      Error::handle(name(), L"getMatrixFloat", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixFloat* > (data_d));
  }

  // method: getMatrixFloat
  //
  MatrixFloat& getMatrixFloat() {
    if (data_type_d != MATRIX_FLOAT) {
      Error::handle(name(), L"getMatrixFloat", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixFloat* > (data_d));
  }

  // method: getMatrixComplexFloat
  //
  
  const MatrixComplexFloat& getMatrixComplexFloat() const {
    if (data_type_d != MATRIX_COMPLEX_FLOAT) {
      Error::handle(name(), L"getMatrixComplexFloat",
		    ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixComplexFloat* > (data_d));
  }

  // method: getMatrixComplexFloat
  //
  MatrixComplexFloat& getMatrixComplexFloat() {
    if (data_type_d != MATRIX_COMPLEX_FLOAT) {
      Error::handle(name(), L"getMatrixComplexFloat",
		    ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixComplexFloat* > (data_d));
  }

  // method: getVectorDouble
  //
  const VectorDouble& getVectorDouble() const {
    if (data_type_d != VECTOR_DOUBLE) {
      Error::handle(name(), L"getVectorDouble", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorDouble* > (data_d));
  }

  // method: getVectorDouble
  //
  VectorDouble& getVectorDouble() {
    if (data_type_d != VECTOR_DOUBLE) {
      Error::handle(name(), L"getVectorDouble", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorDouble* > (data_d));
  }

  // method: getVectorComplexDouble
  //
  const VectorComplexDouble& getVectorComplexDouble() const {
    if (data_type_d != VECTOR_COMPLEX_DOUBLE) {
      Error::handle(name(), L"getVectorComplexDouble", ERR_TYPE,
		    __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorComplexDouble* > (data_d));
  }

  // method: getVectorComplexDouble
  //
  VectorComplexDouble& getVectorComplexDouble() {
    if (data_type_d != VECTOR_COMPLEX_DOUBLE) {
      Error::handle(name(), L"getVectorComplexDouble",
		    ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < VectorComplexDouble* > (data_d));
  }

  // method: getMatrixDouble
  //
  const MatrixDouble& getMatrixDouble() const {
    if (data_type_d != MATRIX_DOUBLE) {
      Error::handle(name(), L"getMatrixDouble", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixDouble* > (data_d));
  }

  // method: getMatrixDouble
  //
  MatrixDouble& getMatrixDouble() {
    if (data_type_d != MATRIX_DOUBLE) {
      Error::handle(name(), L"getMatrixDouble", ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixDouble* > (data_d));
  }

  // method: getMatrixComplexDouble
  //
  const MatrixComplexDouble& getMatrixComplexDouble() const {
    if (data_type_d != MATRIX_COMPLEX_DOUBLE) {
      Error::handle(name(), L"getMatrixComplexDouble",
		    ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixComplexDouble* > (data_d));
  }

  // method: getMatrixComplexDouble
  //
  MatrixComplexDouble& getMatrixComplexDouble() {
    if (data_type_d != MATRIX_COMPLEX_DOUBLE) {
      Error::handle(name(), L"getMatrixComplexDouble",
		    ERR_TYPE, __FILE__, __LINE__);
    }
    return *(reinterpret_cast < MatrixComplexDouble* > (data_d));
  }

  // method: getCombination
  //
  const Vector<AlgorithmData>& getCombination() const {
    if (data_type_d != COMBINATION) {
      Error::handle(name(), L"getCombination", ERR_TYPE,
		    __FILE__, __LINE__);
    }
    return *(reinterpret_cast< Vector < AlgorithmData >* > (data_d));
  }
  
  // method: getCombination
  //
  Vector<AlgorithmData>& getCombination() {
    if (data_type_d != COMBINATION) {
      Error::handle(name(), L"getCombination", ERR_TYPE,
		    __FILE__, __LINE__);
    }
    return *(reinterpret_cast < Vector < AlgorithmData >* > (data_d));
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  make methods
  //
  //---------------------------------------------------------------------------
  
  // method: make
  //
  boolean make(const AlgorithmData& arg) {
    return (assign(arg) && clear(Integral::RETAIN));
  }

  // method: makeVectorFloat
  //
  VectorFloat& makeVectorFloat() {
    setDataType(VECTOR_FLOAT);
    return *(reinterpret_cast < VectorFloat* > (data_d));
  }
  
  // method: makeVectorComplexFloat
  //
  VectorComplexFloat& makeVectorComplexFloat() {
    setDataType(VECTOR_COMPLEX_FLOAT);
    return *(reinterpret_cast < VectorComplexFloat* > (data_d));
  }
  
  // method: makeMatrixFloat
  //
  MatrixFloat& makeMatrixFloat() {
    setDataType(MATRIX_FLOAT);
    return *(reinterpret_cast < MatrixFloat* > (data_d));
  }

  // method: makeMatrixComplexFloat
  //
  
  MatrixComplexFloat& makeMatrixComplexFloat() {
    setDataType(MATRIX_COMPLEX_FLOAT);
    return *(reinterpret_cast < MatrixComplexFloat* > (data_d));
  }

  // method: makeVectorDouble
  //
  VectorDouble& makeVectorDouble() {
    setDataType(VECTOR_DOUBLE);
    return *(reinterpret_cast < VectorDouble* > (data_d));
  }
  
  // method: makeVectorComplexDouble
  //
  VectorComplexDouble& makeVectorComplexDouble() {
    setDataType(VECTOR_COMPLEX_DOUBLE);
    return *(reinterpret_cast < VectorComplexDouble* > (data_d));
  }
  
  // method: makeMatrixDouble
  //
  MatrixDouble& makeMatrixDouble() {
    setDataType(MATRIX_DOUBLE);
    return *(reinterpret_cast < MatrixDouble* > (data_d));
  }

  // method: makeMatrixComplexDouble
  //
  MatrixComplexDouble& makeMatrixComplexDouble() {
    setDataType(MATRIX_COMPLEX_DOUBLE);
    return *(reinterpret_cast < MatrixComplexDouble* > (data_d));
  }
  
  // method: makeCombination
  //
  Vector<AlgorithmData>& makeCombination() {
    setDataType(COMBINATION);
    return *(reinterpret_cast < Vector < AlgorithmData >* > (data_d));
  }

  // method to set the parser
  //
  boolean setParser(SofParser* parser);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  swap methods
  //
  //---------------------------------------------------------------------------

  // method to swap out the data in one object to another
  //
  boolean swap(AlgorithmData& arg);
  
  //---------------------------------------------------------------------------
  //
  // this class does not need an interface contract
  //
  //---------------------------------------------------------------------------

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:
};

// end of include file
// 
#endif
