// file: $isip/class/sp/Component/Component.h
// version: $Id: Component.h 9257 2003-07-01 01:31:13Z gao $
//

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

#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_LONG
#include <Long.h>
#endif

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

#ifndef ISIP_ALGORITHM
#include <Algorithm.h>
#endif

// Component: signal flow graphs in isip_transform are represented
//  using a graph of algorithm objects. this class is used to represent
//  a block in this graph. a related class, Recipe, is used to
//  represent the entire graph (as a graph of Component objects).
//
class Component {

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

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

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

  static const String DEF_PARAM;
  static const String PARAM_INPUT_NAMES;
  static const String PARAM_OUTPUT_NAME;
  static const String PARAM_COMPONENT;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const Char DELIM;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 80100;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------

protected:

  // start with this data:
  //  note that each component can have multiple inputs and one output.
  //
  Vector<String> input_names_d;
  Vector<Long> input_offsets_d;
  
  // go through this transformation
  //
  Algorithm algo_d;

  // end up with this data:
  //  note that each component can have only one output.
  //
  String output_name_d;

  // debug level
  //
  static Integral::DEBUG debug_level_d;
  
  // memory manager
  //
  static MemoryManager mgr_d;

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }
  
  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // debug methods
  //  setDebug is inherited from base class
  //
  boolean debug(const unichar* msg) const;

  // destructor/constructor(s)
  //

  // method: destructor
  //
  ~Component() {}

  // method: default constructor
  //
  Component() {}

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

  // method: assign
  //
  boolean assign(const Component& arg) {
    return (input_names_d.assign(arg.input_names_d) &&
	    input_offsets_d.assign(arg.input_offsets_d) &&
	    output_name_d.assign(arg.output_name_d) &&
	    algo_d.assign(arg.algo_d));
  }
  
  // i/o methods
  //
  long sofSize() const; 
  boolean read(Sof& sof, long tag, const String& name = CLASS_NAME);
  boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const;

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

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

  // method: eq
  //
  boolean eq(const Component& arg) const {
    return (input_names_d.eq(arg.input_names_d)
	    && input_offsets_d.eq(arg.input_offsets_d)
	    && output_name_d.eq(arg.output_name_d)
	    && algo_d.eq(arg.algo_d));
  }

  // 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);
  }

  // method: clear
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE) {
    return (input_names_d.clear(ctype) &&
	    input_offsets_d.clear(ctype) &&
	    output_name_d.clear(ctype) &&
	    algo_d.clear(ctype));
  }

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

  // method: setAlgorithm
  //
  boolean setAlgorithm(const Algorithm& arg) {
    return algo_d.assign(arg);
  }

  // method: setInputName
  //
  boolean setInputName(const String& str);

  // other methods to set the input name:
  //
  boolean setInputName(long index, const String& str);
  
  // method: setOutputName
  //
  boolean setOutputName(const String& oname) {
    return output_name_d.assign(oname);
  }

  // method: setSampleFrequency
  //
  boolean setSampleFrequency(float sf) {
    return algo_d.setSampleFrequency(sf);
  }

  // method: setFrameDuration
  //
  boolean setFrameDuration(float dur) {
    return algo_d.setFrameDuration(dur);
  }

  // method: setLeftoverSamps
  //
  boolean setLeftoverSamps(long dur) {
    return algo_d.setLeftoverSamps(dur);
  }
  
  // method: setFrameIndex
  //
  boolean setFrameIndex(long index) {
    return algo_d.setFrameIndex(index);
  }
  
  // method: setSignalDuration
  //
  boolean setSignalDuration(float dur) {
    return algo_d.setSignalDuration(dur);
  }

  // method: setInputFilename
  //
  boolean setInputFilename(Filename& basename) {
    return algo_d.setInputFilename(basename);
  }

  // method: setOutputDirectory
  //
  boolean setOutputDirectory(String& new_dir) {
    return algo_d.setOutputDirectory(new_dir);
  }

  // method: setOutputBasename
  //
  boolean setOutputBasename(String& basename) {
    return algo_d.setOutputBasename(basename);
  }

  // method: setOutputExtension
  //
  boolean setOutputExtension(String& extension) {
    return algo_d.setOutputExtension(extension);
  }  

  // method: setOutputPreserve
  //
  boolean setOutputPreserve(long new_pres_level) {
    return algo_d.setOutputPreserve(new_pres_level);
  }
  
  // method: setOutputSuffix
  //
  boolean setOutputSuffix(String& suffix) {
    return algo_d.setOutputSuffix(suffix);
  }

  // method: setOutputType
  //
  boolean setOutputType(File::TYPE& type) {
    return algo_d.setOutputType(type);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  get methods
  //
  //---------------------------------------------------------------------------

  // method: getAlgorithm
  //
  const Algorithm& getAlgorithm() const {
    return algo_d;
  }

  // method: getInputName
  //
  const String& getInputName(long index) const {
    return input_names_d(index);
  }

  // method: getOutputName
  //
  const String& getOutputName() const {
    return output_name_d;
  }

  // method: getInputOffset
  //
  long getInputOffset(long index) const {
    return input_offsets_d(index);
  }

  // method: getNumInputs
  //
  long getNumInputs() const {
    return input_names_d.length();
  }
  
  // method: isInput
  //
  boolean isInput(const Component& arg) const {
    return input_names_d.contains(&(arg.getOutputName()));
  }
  
  // method: isCoefficientLabel
  //
  boolean isCoefficientLabel() const {
    return (algo_d.getType() == Algorithm::COEFFICIENT_LABEL);
  }

  // method: isCoefficientLabel
  //
  boolean isCoefficientLabel(CoefficientLabel::TYPE arg) const {
    return ((algo_d.getType() == Algorithm::COEFFICIENT_LABEL) &&
	    (algo_d.getCLabelType() == arg));
  }

  // method: getGenSampleFrequency
  //
  boolean getGenSampleFrequency(Float& sf) {
    return algo_d.getGenSampleFrequency(sf);
  }

  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  methods related to the algo/AlgorithmBase interface contract
  //
  //---------------------------------------------------------------------------

  // method: init
  //
  boolean init() {
    return algo_d.init();
  }

  // method: apply
  //
  boolean apply(Vector<AlgorithmData>& output,
		const Vector< CircularBuffer<AlgorithmData> >& input) {
    return algo_d.apply(output, input);
  }
  
  // configuration methods dealing with multiframe computations
  //

  // method: getLeadingPad
  //
  long getLeadingPad() const {
    return algo_d.getLeadingPad();
  }

  // method: getTrailingPad
  //
  long getTrailingPad() const {
    return algo_d.getTrailingPad();
  }

  // special getInputFilename method to get the input filename from
  // Constant class
  //
  
  // method: getInputFilename
  //
  boolean const getInputFilename(String& filename) const {
    return algo_d.getInputFilename(filename);
  }

  // special getOutputFilename method to get the output filename from
  // Output or Constant class
  //  
  
  // method: getOutputFilename
  //
  boolean const getOutputFilename(String& filename) const {
    return algo_d.getOutputFilename(filename);
  }

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // methods to manipulate names
  //
  boolean splitName(String& base_name, Long& offset, const String& str) const;
  boolean joinName(String& output) const;
};

// end of include file
// 
#endif
