// file: $isip/class/search/SymbolGraph/SymbolGraph.h
// version: $Id: SymbolGraph.h 9374 2003-12-22 22:45:48Z alphonso $
//

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

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

#ifndef ISIP_FILENAME
#include <Filename.h>
#endif

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

#ifndef ISIP_FLOAT
#include <Float.h>
#endif

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

#ifndef ISIP_PAIR
#include <Pair.h>
#endif

#ifndef ISIP_TRIPLE
#include <Triple.h>
#endif

#ifndef ISIP_HASH_TABLE
#include <HashTable.h>
#endif

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

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

#ifndef ISIP_SEARCH_LEVEL
#include <SearchLevel.h>
#endif

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

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

// SymbolGraph: a class to hold a symbol representing some part of the search
//
class SymbolGraph {

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

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

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

  static const String DEF_PARAM;
  static const String DEF_SYMBOL;  
  static const String DEF_FORMAT;  
  static const String PARAM_FORMAT;
  static const String PARAM_VERSION;
  static const String PARAM_SCALE;
  static const String PARAM_PENALTY;  
  static const String DEF_START_SYMBOL;
  static const String DEF_TERM_SYMBOL;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // default values
  //
  static const float DEF_SCALE = 1.0;
  static const float DEF_PENALTY = 0.0;
  static const float DEF_FRAME_DURATION = 0.01;  
  
  static const long DEF_ORDER = 1;  
  static const long DEF_NUM_NODES = 0;
  static const long DEF_NUM_ARCS = 0;  
  
  //---------------------------------------
  //
  // error codes
  //
  //---------------------------------------

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

  // define the format
  //
  String format_d;
  
  // define the language model scale factor
  //
  Float scale_d;
  
  // define the symbol insertion penalty
  //
  Float penalty_d;

  // define the n-symbol order
  //
  Long order_d;
  
  // define the number of nodes in the graph
  //
  Long num_nodes_d;
  
  // define the number of arcs in the graph
  //
  Long num_arcs_d;
  
  // define the linked list of nodes corresponding to this graph
  //
  SingleLinkedList<SymbolGraphNode> nodes_d;

  // define the start node and term nodes
  //
  SymbolGraphNode start_node_d;
  SymbolGraphNode term_node_d;  
  
  // define a static memory manager
  //
  static MemoryManager mgr_d;
  
  // define a static debug level
  //
  static Integral::DEBUG debug_level_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
  //
  static boolean setDebug(Integral::DEBUG debug_level) {
    debug_level_d = debug_level;
    return true;
  }
  
  // method: destructor
  //
  ~SymbolGraph() {
    clear();
  }

  // default constructor
  //
  SymbolGraph();

  // method: copy constructor
  //
  SymbolGraph(const SymbolGraph& copy_grp) {
    assign(copy_grp);
  }
  
  // method: assign
  //
  boolean assign(const SymbolGraph& copy_grp) {
    return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__);
  }

  // method: operator=
  //
  SymbolGraph& operator=(const SymbolGraph& arg) {
    assign(arg);
    return *this;
  }

  // i/o methods
  //
  long sofSize() const;

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

  boolean readDataText(Sof& sof_a, const String& pname, long size,
		       boolean param, boolean nested);
  boolean readDataBinary(Sof& sof);
  
  // write methods
  //
  boolean write(Sof& sof, long tag, const String& cname = CLASS_NAME) const;
  boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;

  boolean writeTextData(Sof& sof, const String& pname,
	      Vector<Long>& nodes,
	      Vector<Triple<Long, Long, String> >& symbols,
	      Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs) const;
  boolean writeBinaryData(Sof& sof, const String& pname,
	      Vector<Long>& nodes,
	      Vector<Triple<Long, Long, String> >& symbols,
	      Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs) const;

  // equality method
  //
  boolean eq(const SymbolGraph& compare_graph) 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);
  }

  // clear method
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //
  //---------------------------------------------------------------------------

  // method: getFormat
  //
  boolean getFormat(String& arg) {
    return arg.assign(format_d);
  }

  // method: setFormat
  //
  boolean setFormat(const String& arg) {
    return format_d.assign(arg);
  }
  
  // method: getScale
  //
  float getScale() const {
    return scale_d;
  }

  // method: setScale
  //
  boolean setScale(const float arg) {
    return (scale_d = arg);
  }  

  // method: getPenalty
  //
  float getPenalty() const {
    return penalty_d;
  }

  // method: setPenalty
  //
  boolean setPenalty(const float arg) {
    return (penalty_d = arg);
  }

  // method: getOrder
  //
  long getOrder() const {
    return order_d;
  }

  // method: setOrder
  //
  boolean setOrder(const long arg) {
    return (order_d = arg);
  }  

  // method: getNodes
  //
  SingleLinkedList<SymbolGraphNode>& getNodes() {
    return nodes_d;
  }
  
  // method: getNumNodes
  //
  long getNumNodes() const {
    return num_nodes_d;
  }

  // method: setNumNodes
  //
  boolean setNumNodes(const long arg) {
    return (num_nodes_d = arg);
  }

  // method: getNumArcs
  //
  long getNumArcs() const {
    return num_arcs_d;
  }

  // method: setNumArcs
  //
  boolean setNumArcs(const long arg) {
    return (num_arcs_d = arg);
  }    

  // method: getStart
  //
  SymbolGraphNode* getStart() {
    return (SymbolGraphNode*)&start_node_d;
  }

  // method: getTerm
  //
  SymbolGraphNode* getTerm() {
    return (SymbolGraphNode*)&term_node_d;    
  }  

  // method: incrementNodes
  //
  boolean incrementNodes() {
    num_nodes_d++;
    return true;
  }
  
  // method: decrementNodes
  //
  boolean decrementNodes() {
    num_nodes_d--;
    return true;
  }

  // method: incrementArcs
  //
  boolean incrementArcs() {
    num_arcs_d++;
    return true;
  }
  
  // method: decrementArcs
  //
  boolean decrementArcs() {
    num_arcs_d--;
    return true;
  }    

  // method: find
  //
  boolean find(const SymbolGraphNode* obj) {
    return nodes_d.find(obj);
  }

  // method: contains
  //
  boolean contains(const SymbolGraphNode* obj) {
    return nodes_d.find(obj);
  }

  // insert/remove methods
  //
  SymbolGraphNode* insertNode(long frame, const String& str = DEF_SYMBOL);
  boolean removeNode(SymbolGraphNode* obj);

  // graph reduction methods
  //
  boolean prune();
  boolean compact(SymbolGraph& graph);  

  // method to convert the symbol grapph into a digraph representation
  //
  boolean convert(SearchLevel& level, DiGraph<SearchNode>& digraph);
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // methods to get and set the graph internal structure
  //
  boolean get(Vector<Long>& nodes,
	      Vector<Triple<Long, Long, String> >& symbols,
	      Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs);

  boolean set(Vector<Long>& nodes,
	      Vector<Triple<Long, Long, String> >& symbols,
	      Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs);
  
  // method to read the lattice format
  //
  boolean readLatticeFormat(Sof& sof, const String& pname,
			    long size, boolean param,
			    boolean nested);
};

// end of include file
//
#endif
