// file: $isip/class/search/SearchLevel/slev_09.cc
// version: $Id: slev_09.cc 9458 2004-04-19 15:08:38Z gao $
//

// isip include files
//
#include "SearchLevel.h"

#ifndef ISIP_SOF
#include <Sof.h>
#endif

#ifndef ISIP_SUPPORT_VECTOR_MODEL
#include <SupportVectorModel.h>
#endif

#ifndef ISIP_UNIFORM_MODEL
#include <UniformModel.h>
#endif

// method: connectStatisticalModels
//
// arguments: none
//
// return: a boolean indicating status
//
// this method maps the statistical models to the symbols in the symbol table
//
boolean SearchLevel::connectStatisticalModels() {
  
  // check if the statistical models have already been loaded
  //
  if (stat_models_d.length() == 0 ) {
    return false;
  }
  
  // loop through all the subgraphs in the last level
  //
  long num_subgraphs = sub_graphs_d.length();
  for (long index = 0; index < num_subgraphs; index++) {
    
    // get the graph
    //
    DiGraph<SearchNode>& subgraph = sub_graphs_d(index);

    // variable for searching nodes in the graph
    //
    long num_vertices = subgraph.length() + 2;    
    GraphVertex<SearchNode>* tmp_vert[num_vertices];
 
    // go through all the vertices of the subgraph
    //
    tmp_vert[0] = subgraph.getStart();
    
    subgraph.gotoFirst();
    for (long i = 1; i < num_vertices - 1; i++) {

      // get the search node for the vertex
      //
      SearchNode* snode;
      tmp_vert[i] = (GraphVertex<SearchNode>*)subgraph.getCurr();  
      snode = tmp_vert[i]->getItem();
       
      // get the search symbol corresponding to the given node
      //
      SearchSymbol hashed_symbol;
      snode->getSymbol(hashed_symbol);

      // get statistical model index from the level's symbol_hash_d
      // and then set statistical model for this search node
      //
      Long* model_index = symbol_hash_d.get(hashed_symbol);
      if (model_index == NULL) {
	String message(L"connectStatisticalModels - load ");
	message.concat(L"\n Symbol: \"");
	message.concat(hashed_symbol);
	message.concat(L"\" not found in statistical model hash table!");
	return Error::handle(name(), message, Error::ARG, __FILE__, __LINE__);
      }

      snode->setModelId((long)*model_index);
      snode->setStatisticalModel(&stat_models_d(*model_index));

      // move to the next vertex
      //
      subgraph.gotoNext();
    }
  
    // the last vertex is the terminal node
    //
    tmp_vert[num_vertices - 1] = subgraph.getTerm();
  } 
  
  // exit gracefully
  //
  return true;
}

// method: createStatisticalModels
//
// arguments:
//  Sof& sof: (input) sof file object for statistical model file
//  long tag: (input) sof object instance tag
//
// return: a boolean indicating status
//
// this method create the statistical models from Sof file, and assumes
// the input sof file has already been opened correctly
//
boolean SearchLevel::createStatisticalModels(Sof& sof_a, long tag_a) {
  
  // make sure the symbol table has been loaded
  //  
  long num_keys = 0;

  // if no tag is specified, the tag should be zero
  //
  if (tag_a == DEF_TAG) {
    tag_a = (long)level_index_d;
  }
   
  // read the hashtable from the input sof file
  //
  if (symbol_hash_d.read(sof_a, tag_a, PARAM_STAT_HASH)) {

    // set the num_symbols
    //
    num_keys = symbol_hash_d.getNumItems();
  }
  else {    
    return false;
  }

  // set up empty statistical models
  //
  stat_models_d.clear();
  stat_models_d.setLength(num_keys);
  stat_models_d.setCapacity(num_keys);
  
  // set each stat models
  //
  for (long i = 0; i < num_keys; i++) {

    MixtureModel mix_model;
    VectorFloat weights(num_of_mixtures_d);
    mix_model.setWeights(weights);

    for (long j = 0; j < num_of_mixtures_d; j++ ) {

      // set statistical models
      //
      if (stat_model_type_d == StatisticalModel::GAUSSIAN_MODEL ) {
	GaussianModel gau_model;
	gau_model.setMean(0.0);
	MatrixFloat cov;
	cov.setDimensions(1, 1, false, Integral::DIAGONAL);
	cov.assign(1.0);
	gau_model.setCovariance(cov);
	mix_model.add(gau_model);
      }
      else if ( stat_model_type_d == StatisticalModel::UNIFORM_MODEL ){
	UniformModel uni_model;
	mix_model.add(uni_model);
      }
      else if ( stat_model_type_d == StatisticalModel::SUPPORT_VECTOR_MODEL ){
	SupportVectorModel svm_model;
	mix_model.add(svm_model);
      }
      else {
	return Error::handle(name(), L"createStatisticalModels: wrong model type", Error::ARG, __FILE__, __LINE__);
      }
    }

    // set statistical model
    //
    stat_models_d(i).setType(StatisticalModel::MIXTURE_MODEL);
    stat_models_d(i).assign(mix_model);
  }
  
  // gracefully exit
  //
  return true;
}

// method: loadStatisticalModels
//
// arguments:
//  Sof& sof: (input) sof file object for statistical model file
//  long tag: (input) sof object instance tag
//
// return: a boolean indicating status
//
// this method read the statistical models from Sof file, and assumes
// the input sof file has already been opened correctly
//
boolean SearchLevel::loadStatisticalModels(Sof& sof_a, long tag_a) {
  
  // make sure the symbol table has been loaded
  //  
  long num_symbols = symbol_table_d.length();

  if (num_symbols == 0) {
    return Error::handle(name(), L"loadStatisticalModels", Error::ARG, __FILE__, __LINE__);
  }
 
  // if no tag is specified, the tag should be zero
  //
  if (tag_a == DEF_TAG) {
    tag_a = (long)level_index_d;
  }
   
  // read the hashtable from the input sof file
  //
  if (symbol_hash_d.read(sof_a, tag_a, PARAM_STAT_HASH)) {

    // check whether the number of keys in the hashtable is the same
    // as that of the symbols in the symbol_table_d.If yes give a
    // warning when debug level is greater than BRIEF.
    //    
      
      if (symbol_hash_d.getNumItems() != num_symbols && debug_level_d >= Integral::BRIEF) {
	
	Console::increaseIndention();
	Console::put(L"Warning:The number of symbols in the statistical model pool and the language model are not the same");
	Console::decreaseIndention();
      
      }
  }
  else {    
    return false;
  }
  
  // read statistical models if being present in file
  //
  if (stat_models_d.read(sof_a, tag_a, PARAM_STAT)) {  
    
    // check if the number of stat models is no more than that of
    // symbols.If yes give a warning when debug level is greater than
    // BRIEF
    //
    if (stat_models_d.length() > num_symbols && debug_level_d >= Integral::BRIEF ) {   
      
      Console::increaseIndention();
      Console::put(L"Warning:The number of symbols in the statistical model pool and the language model are not the same");
      Console::decreaseIndention();
      
    }
  }
  else {
    return false;
  }
  
  // gracefully exit
  //
  return true;
}

// method: storeStatisticalModels
//
// arguments:
//  Sof& sof: (input) sof file object for statistical model file
//  long tag: (input) sof object instance tag
//
// return: a boolean indicating status
//
// this method writes the statistical models from Sof file
//
boolean SearchLevel::storeStatisticalModels(Sof& sof_a, long tag_a) {
 
  // if no tag is specified, the tag should be zero
  //
  if (tag_a == DEF_TAG) {
    tag_a = (long)level_index_d;
  }
   
  // write the hashtable from the input sof file
  //
  if (!symbol_hash_d.isEmpty()) {
    if (!symbol_hash_d.write(sof_a, tag_a, PARAM_STAT_HASH)) {
      return Error::handle(name(), L"storeStatisticalModels", Error::ARG, __FILE__, __LINE__);
    }
  }
  
  // write statistical models if being present in file
  //
  if (!stat_models_d.write(sof_a, tag_a, PARAM_STAT)) {  
    return Error::handle(name(), L"storeStatisticalModels", Error::ARG, __FILE__, __LINE__);
  }
  
  // gracefully exit
  //
  return true;
}
