// file: $isip/class/algo/AlgorithmBase/AlgorithmBase.h
// version: $Id: AlgorithmBase.h 9262 2003-07-06 11:16:19Z picone $
//

// make sure definitions are only made once:
//
#ifndef ISIP_ALGORITHM_BASE
#define ISIP_ALGORITHM_BASE

// isip include files
//
#ifndef ISIP_ALGORITHM_DATA
#include <AlgorithmData.h>
#endif

#ifndef ISIP_CIRCULAR_BUFFER
#include <CircularBuffer.h>
#endif

// AlgorithmBase: a class that defines an interface contract for all
// algorithms.
//
// there are two complicating factors in this class. first, every
// algorithm class must support an interface contract through a
// virtual function mechanism. because of this, there are many virtual
// functions which the derived class must provide.
//
// second, since this class has protected data, it must supply methods
// to manipulate the data. below, there are some virtual functions not
// set to zero which means this specific class supplies an implementation
// for that function.
//
class AlgorithmBase {

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

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

  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------
  
  // define an enumeration for the computational mode:
  //  many algorithms share a property that they can operate
  //  only on data within the current frame (FRAME_INTERNAL) or on
  //  data across several frames (CROSS_FRAME). Some classes, such
  //  as Statistics, output data only once per file (ACCUMULATE).
  //
  enum CMODE { FRAME_INTERNAL = 0, CROSS_FRAME, ACCUMULATE,
	       DEF_CMODE = FRAME_INTERNAL };

  // define an enumeration for all possible data formats:
  //  for some classes, such as filter, we must know whether the
  //  the algorithm is frame-based or sample-based, so that we output
  //  the correct number of samples. this allows some applications
  //  to produce output files that are the same length as the input files.
  //
  enum DMODE { FRAME_BASED = 0, SAMPLE_BASED,
	       DEF_DMODE = FRAME_BASED };
  
  // define static NameMap objects
  //
  static const NameMap CMODE_MAP;
  static const NameMap DMODE_MAP;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------

  static const String PARAM_DBGL;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // signal processing constants
  //
  static const float DEF_SAMPLE_FREQUENCY = 8000;
  static const float DEF_FRAME_DURATION = 0.01;
  static const float DEF_SIGNAL_DURATION = 1.0;
  static const long DEF_FRAME_INDEX = (long)-1;
  
  // multichannel signal-related constants
  //
  static const long DEF_NUM_CHANNELS = 1;
  static const long DEF_CHANNEL_INDEX = 0;

  // define the default value(s) of the class data
  //
  static const long DEF_LEADING_PAD = 0;
  static const long DEF_TRAILING_PAD = 0;
  static const long DEF_LEFTOVER_SAMPS = 0;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 70000;
  static const long ERR_UNKALG = 70001;
  static const long ERR_UNKIMP = 70002;
  static const long ERR_UNKTYP = 70003;  
  static const long ERR_UNSUPA = 70004;
  static const long ERR_UNSUPI = 70005;
  static const long ERR_UNSUPM = 70006;
  static const long ERR_INSUFD = 70007;
  static const long ERR_ORDER = 70008;
  static const long ERR_UNCTYP = 70009;  
  static const long ERR_COMPF = 70010;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // define parameters that are part of the i/o for the class
  //

  // debugging parameters
  //
  DebugLevel debug_level_d;

  // this flag is used to determine if the object's init method
  // needs to be called
  //
  boolean is_valid_d;

  // computational mode
  //
  CMODE cmode_d;
  
  // data processing mode
  //
  DMODE dmode_d;
  
  // define parameters that are not part of the i/o for the class
  //
  float sample_freq_d;
  float frame_dur_d;
  float signal_duration_d;
  long leftover_samps_d;
  long frame_index_d;
  long num_channels_d;
  long num_elements_d;
  long offset_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
  //
  // note that this method is not virtual since
  // it operates on protected data found in this class. 
  //
  boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }

  // other debug methods
  //
  virtual boolean debug(const unichar* msg) const;

  // method: destructor
  //
  virtual ~AlgorithmBase() {}

  // method: default constructor
  //
  AlgorithmBase();

  // method: copy constructor
  //
  AlgorithmBase(const AlgorithmBase& arg) {
    assign(arg);
  }

  // assign methods:
  //  note that this method is not set to zero. this class must supply
  //  a version of this method, since it manipulates protected data.
  //
  virtual boolean assign(const AlgorithmBase& arg);
  
  // method: sofSize
  //
  virtual long sofSize() const = 0;

  // method: read
  //
  virtual boolean read(Sof& sof, long tag, const String& name) = 0;

  // method: write
  //
  virtual boolean write(Sof& sof, long tag, const String& name) const = 0;

  // method: readData
  //
  virtual boolean readData(Sof& sof, const String& pname,
			   long size, boolean param, boolean nested) = 0;

  // method: writeData
  //
  virtual boolean writeData(Sof& sof, const String& pname) const = 0;
  
  // method: eq
  //
  virtual boolean eq(const AlgorithmBase& arg) const;

  // memory management methods:
  //  new and delete methods are omitted since only the derived
  //  classes will be used
  //
  virtual boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set methods
  //
  // note: these functions are needed to manipulate protected data for
  // this class that must be invoked by the public interface for the
  // class. note that the set methods are virtual so a derived class
  // can override it if it needs to do more with the method, such as
  // buffer resizing.
  //
  //--------------------------------------------------------------------------

  // method: setComputeMode
  //
  virtual boolean setComputeMode(CMODE cmode) {
    cmode_d = cmode;
    is_valid_d = false;    
    return true;  
  }  

  // method: setDataMode
  //
  virtual boolean setDataMode(DMODE mode) {
    dmode_d = mode;
    is_valid_d = false;    
    return true;  
  }

  // method: setSampleFrequency
  //
  virtual boolean setSampleFrequency(float sf) {
    sample_freq_d = sf;
    is_valid_d = false;
    return true;
  }

  // method: setFrameDuration
  //
  virtual boolean setFrameDuration(float fdur) {
    frame_dur_d = fdur;
    is_valid_d = false;    
    return true;
  }

  // method: setSignalDuration
  //
  virtual boolean setSignalDuration(float sdur) {
    signal_duration_d = sdur;
    is_valid_d = false;    
    return true;
  }

  // method: setLeftoverSamps
  //
  boolean setLeftoverSamps(long samps) {
    leftover_samps_d = samps;
    is_valid_d = false;    
    return true;
  }

  // method: setFrameIndex
  //
  virtual boolean setFrameIndex(long index) {
    frame_index_d = index;
    is_valid_d = false;    
    return true;
  }
  
  // method: setNumChannels
  //
  virtual boolean setNumChannels(long nchan) {
    num_channels_d = nchan;
    is_valid_d = false;
    return true;
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  get methods
  //
  //---------------------------------------------------------------------------
    
  // method: getComputeMode
  //
  CMODE getComputeMode() const {
    return cmode_d;
  }

  // method: getDataMode
  //
  DMODE getDataMode() const {
    return dmode_d;
  }

  // method: getSampleFrequency
  //
  float getSampleFrequency() const {
    return sample_freq_d;
  }

  // method: getFrameDuration
  //
  float getFrameDuration() const {
    return frame_dur_d;
  }

  // method: getSignalDuration
  //
  float getSignalDuration() const {
    return signal_duration_d;
  }
  
  // method: getLeftoverSamps
  //
  long getLeftoverSamps() const {
    return leftover_samps_d;
  }
  
  // method: getFrameIndex
  //
  long getFrameIndex() const {
    return frame_index_d;
  }
  
  // method: getNumChannels
  //
  long getNumChannels() const {
    return num_channels_d;
  }

  // method: isValid
  //
  boolean isValid() const {
    return is_valid_d;
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:  
  //  interface contract methods
  //
  // note: the methods below constitute the interface required by all
  // algorithms that are going to be part of the generalized transform
  // software (Cepstrum, Calculus etc.).
  //
  //---------------------------------------------------------------------------

  // method: className
  //
  virtual const String& className() const = 0;
  
  // method: init
  //
  virtual boolean init() {
    return true;
  }

  // method: apply
  //
  virtual boolean apply(Vector<AlgorithmData>& output,
		const Vector< CircularBuffer<AlgorithmData> >& input) = 0;


  // method: getLeadingPad
  //
  virtual long getLeadingPad() const {
    return DEF_LEADING_PAD;
  }

  // method: getTrailingPad
  //
  virtual long getTrailingPad() const {
    return DEF_TRAILING_PAD;
  }

  // method: getOutputMode
  //
  virtual CMODE getOutputMode() const {
    return DEF_CMODE;
  }

  // method: setParser
  //
  virtual boolean setParser(SofParser* parser) { return false; }

  // method: displayStart
  //
  boolean displayStart(const AlgorithmBase* algo) {
    if (debug_level_d >= Integral::ALL) {
      algo->debug(L"");
    }
    return true;
  }

  // method: displayFinish
  //
  boolean displayFinish(const AlgorithmBase* algo) {
    if (debug_level_d >= Integral::BRIEF) {
      Console::decreaseIndention();
    }
    return true;
  }

  // method: displayChannel
  //
  boolean displayChannel(long channel) {
    if (debug_level_d > Integral::NONE) {
      if (channel != 0) {
	Console::decreaseIndention();
      }
      String output(L"Channel ");
      output.concat(channel);
      output.concat(L":\n");
      Console::put(output);
      Console::increaseIndention();
    }
    return true;
  }

  // method: display
  //  
  template <class TData0, class TData1>
  boolean display(const TData0& output, const TData1& input,
		  const String& algo_name) {
    if (debug_level_d >= Integral::DETAILED) {
      String str(algo_name);
      str.concat(L" input");
      input.debug(str);
    }
    if (debug_level_d >= Integral::BRIEF) {
      String str(algo_name);
      str.concat(L" output");
      output.debug(str);
    }
    return true;
  }
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:
};

// end of include file
// 
#endif
