// file: $isip/class/sp/Recipe/Recipe.h
// version: $Id: Recipe.h 8416 2002-07-17 20:22:13Z gao $
//

// this file defines the Recipe class
//

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

// isip include files
//
#ifndef ISIP_FRONTEND_BASE
#include <FrontEndBase.h>
#endif

#ifndef ISIP_FTR_BUFFER
#include <FtrBuffer.h>
#endif

#ifndef ISIP_DI_GRAPH
#include <DiGraph.h>
#endif

#ifndef ISIP_COMPONENT
#include <Component.h>
#endif

#ifndef ISIP_SINGLE_LINKED_LIST
#include <SingleLinkedList.h>
#endif

// forward class definitions
//
class FrontEndBase;
class FtrBuffer;

// Recipe: this class is the workhorse of the front end software. it processes
// a graph of algorithm objects (Components) and produces an output
// signal or feature vector (AlgorithmData).
//
class Recipe {

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

  // define the class name
  //
  static const String CLASS_NAME;
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------

  static const String PARAM_RECIPE;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------
  
  // default values of class data
  //
  static const String INPUT_PREFIX;
  static const String OUTPUT_PREFIX;

  static const String SAMPLED_DATA_NAME;
  static const String DUMMY_OUTPUT_NAME;
  
  static const String DUMMY_DATA_NAME;
  
  // default arguments to methods
  //
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 80400;
  static const long ERR_MPATH = 80401;
  static const long ERR_NOPATH = 80402;
  
  //---------------------------------------------------------------------------
  //
  // public data
  //
  //---------------------------------------------------------------------------
public:

  // all the processes we know about
  //
  DiGraph<Component> recipe_d;

  // declare a static debug level for all class instantiations
  //
  static Integral::DEBUG debug_level_d;  
  
  // the memory manager
  //
  static MemoryManager mgr_d;

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }
  
  static boolean diagnose(Integral::DEBUG level);

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

  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG debug_level) {
    debug_level_d = debug_level;
    return true;
  }
  
  // method: destructor
  //
  ~Recipe() {
    clear(Integral::FREE);
  }

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

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

  // method: assign
  //
  boolean assign(const Recipe& arg) {
    return recipe_d.assign(arg.recipe_d);
  }

  // i/o methods
  //
  long sofSize() const;
  boolean read(Sof& sof_a, long tag, const String& name = CLASS_NAME);
  boolean write(Sof& sof_a, long tag, const String& name = CLASS_NAME) const;

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

  boolean writeData(Sof& sof_a,
		    const String& param = String::getEmptyString()) const;

  // method: equality
  //
  boolean eq(const Recipe& arg) const {
    return (recipe_d.eq(arg.recipe_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 recipe_d.clear(ctype);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set/get methods
  //
  //---------------------------------------------------------------------------
public:
  
  // method: setAllocationMode
  //
  boolean setAllocationMode(DstrBase::ALLOCATION alloc) {
    return recipe_d.setAllocationMode(alloc);
  }
  
  // method: getAllocationMode
  //
  DstrBase::ALLOCATION getAllocationMode() const {
    return recipe_d.getAllocationMode();
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  methods to manipulate graphs
  //
  //---------------------------------------------------------------------------

  // read the recipe
  //
  boolean readGraph(Sof& sof, long graph_tag = 0);
  
  // method: isEmpty
  //
  boolean isEmpty() const {
    return (recipe_d.length() == 0);
  }

  // determine a sequence of processes to apply from the available inputs,
  // desired output, and a graph of components 
  //  
  boolean findComponent(SingleLinkedList<Component>& comp,
			const FrontEndBase& fend,
			const String& cname);
  
  boolean findComponent(SingleLinkedList<Component>& comp,
			const FrontEndBase& fend,
			Vector<String>& inputs);  

  // the processes we will apply, and in order of delay. the first element is
  // the list of processes that can be applied with zero latency, the
  // second with one frame of latency, etc.
  //
  boolean delayComponent(Vector< SingleLinkedList<Component> >& dcomp,
			 FtrBuffer& buf,
			 FrontEndBase& fend,
			 SingleLinkedList<Component>& temp_list);

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

  // method: topologicalSort
  //
  boolean topologicalSort(SingleLinkedList<Component>& sorted_data,
			  boolean partial = false) {
    return recipe_d.topologicalSort(sorted_data, partial);
  }

  // method: makeColorHash
  //  creates a color hash table
  //
  boolean makeColorHash(Integral::COLOR col = Integral::DEF_COLOR) {
    return recipe_d.makeColorHash(col);
  }

  // visits all paths to the node in reverse
  //
  boolean reverseVisitDfs(const FrontEndBase& fend, const String& cname);

  // support methods for readGraph
  //
  boolean checkInputs();
  boolean expandSubGraphs(Sof& sof);
  boolean readSubGraph(GraphVertex<Component>*& sub_in,
		       GraphVertex<Component>*& sub_out,
		       Sof& sof, long graph_tag);
};

//
// end of include file
#endif
