// file: $isip/class/search/Instance/Instance.h
// version: $Id: Instance.h 9347 2003-11-26 20:46:15Z alphonso $
//

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

// isip include files
//
#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_MEMORY_MANAGER
#include <MemoryManager.h>
#endif

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

#ifndef ISIP_BI_GRAPH
#include <BiGraph.h>
#endif

#ifndef ISIP_HASH_KEY
#include <HashKey.h>
#endif

#ifndef ISIP_HISTORY
#include <History.h>
#endif

#ifndef ISIP_TRAIN_NODE
#include <TrainNode.h>
#endif

#ifndef ISIP_SYMBOL_GRAPH_NODE
#include <SymbolGraphNode.h>
#endif

// forward class definitions
//
class Context;
class History;
class TrainNode;

// Instance: the fundamental place holder in a recognition system which keeps
// track of the paths in the search space as well as the hypothesis scores
//
class Instance {

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

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

  // define the instance mode options
  //
  enum INSTANCE_MODE { DECODE = 0, TRAIN, DEF_INSTANCE_MODE = DECODE };

  // define the instance internal states
  //
  enum INSTANCE_STATE { INACTIVE = 0, PSEUDO_ACTIVE, ACTIVE,
			DEF_INSTANCE_STATE = INACTIVE };  
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  

  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------  

  // define the inactive likelihood score
  //    
  static const float INACTIVE_SCORE = -11111111111111.0f;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const float DEF_SCORE = 0.0;
  static const ulong DEF_FRAME = 0;
  static const ulong DEF_COUNT = 0;  
  static const ulong DEF_SKIP_LEVEL = 0;
  static const ulong DEF_NSYMBOL_LENGTH = 0;  
  
  // define default arguments to methods
  //
  static const ulong DEF_REF_INCR = 1;
  static const ulong DEF_REF_DECR = 1;  

  //---------------------------------------
  //
  // error codes
  //
  //---------------------------------------

  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:
  
  // define a enum that determines the instance mode
  //
  INSTANCE_MODE instance_mode_d;

  // define a enum that determines the instance internal state
  //
  INSTANCE_STATE instance_state_d;  

  // define a structure to maintain the previous n-symbols
  //
  Context** nsymbol_d;
  
  // define a back pointer to the previous trace(s)
  //
  Instance* back_ptr_d;
  
  // define variables to maintain the skip contexts
  //
  ulong skip_symbol_d;
  ulong skip_level_d;  
  
  // define a structure to maintain the current location in the search space
  //
  History* history_d;

  // define the current symbol and context at the current location
  //
  Context* symbol_d;

  // define the history of previously generated context dependent symbols
  //
  History* symbol_stack_d;

  // define the reference to the symbol graph node
  //
  SymbolGraphNode* symbol_node_d;
  
  // define the likelihood score for the path in the search space that this
  // instance represents
  //
  float score_d;

  // define the lm score for the path in the search space that this instance
  // represents
  //
  float lm_score_d;
  
  // define the time stamp (frame) associaed with this instance
  //
  ulong frame_d;
  
  // define a reference count that says when this instance can be deleted
  //
  ulong reference_count_d;

  // define a reference pointer to a search node used during training
  //
  BiGraphVertex<TrainNode>* reference_vertex_d;

  // define the static nsymbol length
  //
  static Ulong nsymbol_length_d;
  
  // define a static 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:
  //
  boolean debug(const unichar* message) const;

  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG debug_level) {
    debug_level_d = debug_level;
    return true;
  }
  
  // destructor/constructor(s)
  //
  ~Instance();

  // method: default constructor
  //
  Instance(float arg = DEF_SCORE) {

    if (debug_level_d >= Integral::ALL) { 
      fprintf(stdout, "Constructor of instance: %p\n", this);
      fflush(stdout);
    }

    nsymbol_d = (Context**)NULL;
    back_ptr_d = (Instance*)NULL;
    frame_d = DEF_FRAME;
    skip_level_d = DEF_SKIP_LEVEL;
    reference_count_d = DEF_COUNT;
    instance_mode_d = DEF_INSTANCE_MODE;
    instance_state_d = DEF_INSTANCE_STATE;
    lm_score_d = DEF_SCORE;     
    history_d = (History*)NULL;
    symbol_d = (Context*)NULL;
    symbol_stack_d = (History*)NULL;
    reference_vertex_d = (BiGraphVertex<TrainNode>*)NULL;
    symbol_node_d = (SymbolGraphNode*)NULL;
 
    setScore(arg);
  }

  // method: copy constructor
  //
  Instance(const Instance& arg) {

    if (debug_level_d >= Integral::ALL) { 
      fprintf(stdout, "Constructor of instance: %p\n", this);
      fflush(stdout);
    }    

    nsymbol_d = (Context**)NULL;    
    back_ptr_d = (Instance*)NULL;    
    frame_d = DEF_FRAME;
    skip_level_d = DEF_SKIP_LEVEL;    
    reference_count_d = DEF_COUNT;
    instance_mode_d = DEF_INSTANCE_MODE;
    instance_state_d = DEF_INSTANCE_STATE;    
    score_d = DEF_SCORE;
    lm_score_d = DEF_SCORE;    
    history_d = (History*)NULL;
    symbol_d = (Context*)NULL;
    symbol_stack_d = (History*)NULL;
    reference_vertex_d = (BiGraphVertex<TrainNode>*)NULL;
    symbol_node_d = (SymbolGraphNode*)NULL;
 
    assign(arg);
  }
  
  // assign methods
  //
  boolean assign(const Instance& arg);

  // method: sofSize
  //
  long sofSize() const {
    return Error::handle(name(), L"sofSize", Error::ARG, __FILE__, __LINE__);
  }
  
  // method: read
  //
  boolean read(Sof& sof, long tag, const String& cname = CLASS_NAME) {
    return Error::handle(name(), L"read", Error::ARG, __FILE__, __LINE__);
  }

  // method: write
  //
  boolean write(Sof& sof, long tag, const String& cname = CLASS_NAME) const {
    return Error::handle(name(), L"write", Error::ARG, __FILE__, __LINE__);
  }

  // method: readData
  //
  boolean readData(Sof& sof, const String& pname = String::EMPTY,
		   long size = SofParser::FULL_OBJECT,
		   boolean param = true,
                   boolean nested = false) {
    return Error::handle(name(), L"readData", Error::ARG, __FILE__, __LINE__);
  }

  // method: writeData
  //
  boolean writeData(Sof& sof, const String& pname = String::EMPTY) const {
    return Error::handle(name(), L"writeData", Error::ARG, __FILE__, __LINE__);
  }

  // equality methods
  //
  boolean eq(const Instance& arg) const;
  boolean match(const Instance& arg) const;
  
  // method: lt
  //
  boolean lt(Instance& instance_a) const {
    return (score_d < instance_a.score_d);
  }

  // method: gt
  //
  boolean gt(Instance& instance_a) const {
    return (score_d > instance_a.score_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);
  }

  // clear methods
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //
  //---------------------------------------------------------------------------

  // method: setInstanceMode
  //
  boolean setInstanceMode(INSTANCE_MODE arg) {
    instance_mode_d = arg;
    return true;
  }

  // method: getInstanceMode
  //
  INSTANCE_MODE getInstanceMode() {
    return instance_mode_d;
  }

  // method: setInstanceState
  //
  boolean setInstanceState(INSTANCE_STATE arg) {
    instance_state_d = arg;
    return true;
  }

  // method: getInstanceState
  //
  INSTANCE_STATE getInstanceState() {
    return instance_state_d;
  }  

  // method: setScore
  //
  boolean setScore(float score) {
    score_d = score;
    return true;
  }

  // method: getScore
  //
  float getScore() const {
    return score_d;
  }

  // method: setLMScore
  //
  boolean setLMScore(float score) {
    lm_score_d = score;
    return true;
  }

  // method: getLMScore
  //
  float getLMScore() const {
    return lm_score_d;
  }

  // method: getSymbolNode
  //
  SymbolGraphNode* getSymbolNode() {
    return symbol_node_d;
  }

  // method: setSymbolNode
  //
  boolean setSymbolNode(SymbolGraphNode* arg) {
    return (symbol_node_d = arg);
  }  
  
  // method: getNSymbol
  //
  Context**& getNSymbol() {
    return (Context**&)nsymbol_d;
  }

  // method: setNSymbol
  //
  boolean setNSymbol(Context**& arg) {
    return (nsymbol_d = arg);
  }
  
  // method: setSkipSymbol
  //
  boolean setSkipSymbol(ulong symbol) {
    skip_symbol_d = symbol;
    return true;
  }
  
  // method: getSkipSymbol
  //
  ulong getSkipSymbol() {
    return skip_symbol_d;
  }    

  // method: setSkipLevel
  //
  boolean setSkipLevel(ulong level) {
    skip_level_d = level;
    return true;
  }
  
  // method: getSkipLevel
  //
  ulong getSkipLevel() {
    return skip_level_d;
  }    

  // history methods
  //
  boolean setHistory(const History* arg);
  History* getHistory() const;

  // symbol methods
  //
  boolean setSymbol(const Context* arg);
  Context* getSymbol() const;

  // context dependent symbol stack methods
  //  
  boolean setSymbolStack(const History* arg);
  History* getSymbolStack() const;
  
  // method to set the instance back pointer
  //
  boolean setBackPointer(Instance* back_ptr);

  // method: getBackPointer
  //
  Instance* getBackPointer() const {
    return back_ptr_d;    
  }
  
  // method: hasNextLevelContext
  //
  boolean hasNextLevelContext() {
    if (symbol_stack_d != (History*)NULL) {
      return !symbol_stack_d->isEmpty();
    }
    return false;
  }
  
  // history manipulation methods
  //
  boolean printHistory(History* history);
  
  // reference counting methods
  //
  ulong decrementRefCount(ulong decrement = DEF_REF_DECR);  

  // method: incrementRefCount
  //
  ulong incrementRefCount(ulong increment = DEF_REF_INCR) {
    return (reference_count_d += increment);
  }

  // method: getReference
  //
  BiGraphVertex<TrainNode>* getReference() const {
    return reference_vertex_d;
  }

  // method: setReference
  //
  boolean setReference(BiGraphVertex<TrainNode>* vertex) {
    reference_vertex_d = vertex;
    return true;
  }
    
  // method: setRefCount
  //
  boolean setRefCount(ulong count) {
    reference_count_d = count;
    return true;
  }
  
  // method: getRefCount
  //
  ulong getRefCount() const {
    return reference_count_d;
  }

  // method: setFrame
  //
  boolean setFrame(ulong frame) {
    frame_d = frame;
    return true;
  }

  // method: getFrame
  //
  ulong getFrame() const {
    return frame_d;
  }

  // instance activity methods
  //
  boolean setActive(boolean is_active);

  // method: isActive
  //
  boolean isActive() const {
    return (score_d != INACTIVE_SCORE);
  }

  // method: getNSymbolLength
  //
  static ulong getNSymbolLength() {
    return nsymbol_length_d;
  }
  
  // method: setNSymbolLength
  //
  static boolean setNSymbolLength(ulong arg) {
    return (nsymbol_length_d = arg);
  }
  
  // instance deletion methods
  //
  static boolean deleteInstance(Instance* in_instance, boolean is_recursive,
	      boolean clean_search_node = false);

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

};

// include the train node class here circumvent the circular dependency
//
#ifndef ISIP_CONTEXT
#include <Context.h>
#endif

// end of include file
//
#endif








