// file: $isip/class/search/SymbolGraph/sgrp_04.cc
// version: $Id: sgrp_04.cc 9311 2003-09-26 20:20:41Z alphonso $
//

// isip include files
//
#include "SymbolGraph.h"
#include <Sof.h>

// method: write
//
// arguments:
//  Sof& sof: (input) sof file object
//  long tag: (input) sof object instance tag
//  const String& name: (input) sof object instance name
//
// return: a boolean indicating status
//
// this method has the object write itself to an Sof file
//
boolean SymbolGraph::write(Sof& sof_a, long tag_a,
			    const String& name_a) const {

  // declare a temporary size variable
  //
  long obj_size = 0;

  // switch on ascii or binary mode
  //
  if (sof_a.isText()) {  

    // set the size to be dynamic
    //
    obj_size = Sof::ANY_SIZE;
  }
  else {

    // the size of the binary data to write
    //
    obj_size = sofSize();
  }
  
  // write the object into the sof file's index
  //
  if (!sof_a.put(name_a, tag_a, obj_size)) {
    return false;
  }

  // exit gracefully
  //
  return writeData(sof_a);
}

// method: writeData
//
// arguments:
//  Sof& sof: (input) sof file object
//  const String& pname: (input) parameter name
//
// return: logical error status
//
// this method writes the object to the Sof file. it assumes that the
// Sof file is already positioned correctly.
//
boolean SymbolGraph::writeData(Sof& sof_a, const String& pname_a) const {

  // declare local variables and structures to read the graph
  //
  boolean status = false;

  Vector<Long> nodes;
  Vector<Triple<Long, Long, String> > symbols;
  Vector<Triple<Pair<Long, Long>, Float, Float> > arcs;

  // read the current structure of the graph
  //
  const_cast<SymbolGraph* >(this)->get(nodes, symbols, arcs);
  
  // when we are writing text data
  //  
  if (sof_a.isText()) {
    status = writeTextData(sof_a, pname_a, nodes, symbols, arcs);
  }

  // when we are writing binary data
  //
  else {
    status = writeBinaryData(sof_a, pname_a, nodes, symbols, arcs);
  }
  
  // exit gracefully
  //
  return status;
}

// method: writeTextData
//
// arguments:
//  Sof& sof: (input) sof file object
//  const String& pname: (input) parameter name
//  Vector<Long>& nodes: (output) graph nodes
//  Vector<Triple<Long, Long, String> >& symbols: (output) graph symbols
//  Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs: (output) graph arcs
//
// return: logical error status
//
// this method writes the object to the Sof file. it assumes that the
// Sof file is already positioned correctly.
//
boolean SymbolGraph::writeTextData(Sof& sof_a, const String& pname_a,
	      Vector<Long>& nodes_a,
	      Vector<Triple<Long, Long, String> >& symbols_a,
	      Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs_a) const {

  // declare local variables
  //
  String output;
  String value;
  
  // write a start string if necessary
  //
  sof_a.writeLabelPrefix(pname_a);

  // first write the format
  //
  format_d.writeData(sof_a, PARAM_FORMAT);
  sof_a.puts(L"\n");
  
  // write the source file version
  //
  sof_a.puts(PARAM_VERSION);
  sof_a.puts(L"\n");    

  // write the language model scale
  //
  value.assign(scale_d);  
  output.assign(PARAM_SCALE);
  output.concat(L"=");
  output.concat(value);  
  output.concat(L"\n");

  sof_a.puts(output);
  
  // write the symbol penalty
  //
  value.assign(penalty_d);  
  output.assign(PARAM_PENALTY);
  output.concat(L"=");
  output.concat(value);  
  output.concat(L"\n");

  sof_a.puts(output);
  
  // write the number of nodes in the graph
  //
  long num_nodes = nodes_a.length();
  
  value.assign(num_nodes);
  output.assign(L"N=");
  output.concat(value);
  output.concat(L"   ");
  
  sof_a.puts(output);
  
  // write the number of arcs in the graph
  //
  long num_arcs = arcs_a.length();
  
  value.assign(num_arcs);
  output.assign(L"L=");
  output.concat(value);
  output.concat(L"\n");

  sof_a.puts(output);

  // loop over all nodes and write them
  //
  for (long node_index=0; node_index < num_nodes; node_index++) {

    float time_index = (float)nodes_a(node_index) * DEF_FRAME_DURATION;

    // write the node index
    //
    value.assign(node_index);
    output.assign(L"I=");
    output.concat(value);
    output.concat(L"   ");

    sof_a.puts(output);

    // write the frame index
    //
    value.assign(time_index);
    output.assign(L"t=");
    output.concat(value);
    output.concat(L"\n");
    
    sof_a.puts(output);
  }

  // loop over all arcs and write them
  //
  for (long arc_index=0; arc_index < num_arcs; arc_index++) {

    // get the parent and child indices
    //
    long parent_index = (long)(arcs_a(arc_index).first().first());
    long child_index =  (long)(arcs_a(arc_index).first().second());

    // get the language model and acoustic model scores for the transition
    //
    float ac_score = (float)(arcs_a(arc_index).second());    
    float lm_score = (float)(arcs_a(arc_index).third());

    // get the symbol for the transition
    //
    String symbol;
    long pind = symbols_a(arc_index).first();
    long cind = symbols_a(arc_index).second();    
    symbol.assign(symbols_a(arc_index).third());

    // the indices must match
    //
    if ((pind != parent_index) || (cind != child_index)) {
      return Error::handle(name(), L"writeTextData", Error::ARG, __FILE__, __LINE__);
    }
    
    // write the arc index
    //
    value.assign(arc_index);
    output.assign(L"J=");
    output.concat(value);
    output.concat(L"   ");

    sof_a.puts(output);

    // write the parent index
    //
    value.assign(parent_index);
    output.assign(L"S=");
    output.concat(value);
    output.concat(L"   ");
    
    sof_a.puts(output);

    // write the child index
    //
    value.assign(child_index);
    output.assign(L"E=");
    output.concat(value);
    output.concat(L"   ");
    
    sof_a.puts(output);

    // write the symbol
    //
    output.assign(L"W=");
    output.concat(symbol);
    output.concat(L"   ");    
    
    sof_a.puts(output);

    // write the pronunciation
    //
    output.assign(L"v=0");
    output.concat(L"   ");
    
    sof_a.puts(output);

    // write the acoustic model score
    //
    value.assign(ac_score);
    output.assign(L"a=");
    output.concat(value);    
    output.concat(L"   ");
    
    sof_a.puts(output);
    
    // write the language model score
    //
    value.assign(lm_score);
    output.assign(L"l=");
    output.concat(value);    
    output.concat(L"\n");
    
    sof_a.puts(output);    
  }
  
  // put an end string if necessary
  //
  sof_a.writeLabelSuffix(pname_a);
  
  // exit gracefully
  //
  return true;
}

// method: writeBinaryData
//
// arguments:
//  Sof& sof: (input) sof file object
//  const String& pname: (input) parameter name
//  Vector<Long>& nodes: (output) graph nodes
//  Vector<Triple<Long, Long, String> >& symbols: (output) graph symbols
//  Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs: (output) graph arcs
//
// return: logical error status
//
// this method writes the object to the Sof file. it assumes that the
// Sof file is already positioned correctly.
//
boolean SymbolGraph::writeBinaryData(Sof& sof_a, const String& pname_a,
              Vector<Long>& nodes_a,
	      Vector<Triple<Long, Long, String> >& symbols_a,
	      Vector<Triple<Pair<Long, Long>, Float, Float> >& arcs_a) const {

  // write the scale
  //
  scale_d.writeData(sof_a, pname_a);
  
  // write the penalty
  //
  penalty_d.writeData(sof_a, pname_a);
  
  // write the graph nodes
  //
  nodes_a.writeData(sof_a, pname_a);

  // write the graph symbols
  //
  symbols_a.writeData(sof_a, pname_a);  
  
  // write the graph arcs
  //
  arcs_a.writeData(sof_a, pname_a);
  
  // exit gracefully
  //
  return true;
}

// method: sofSize
//
// arguments: none
//
// return: size of object as written to disk via the i/o methods
//
// this method determines the size of the object on disk. it has to
// nearly go through as much trouble as writing the object to
// determine the exact binary size.
//
long SymbolGraph::sofSize() const {

  // declare lists to read the graph structure
  //
  Vector<Long> in_nodes;
  Vector<Triple<Long, Long, String> > in_symbols;
  Vector<Triple<Pair<Long, Long>, Float, Float> > in_arcs;
  
  // start with the length
  //
  long bytes = scale_d.sofSize() + penalty_d.sofSize();

  // get the structure of the graph
  //
  const_cast<SymbolGraph* >(this)->get(in_nodes, in_symbols, in_arcs);

  // add the lengths of the lists
  //
  bytes += in_nodes.sofSize();
  bytes += in_symbols.sofSize();
  bytes += in_arcs.sofSize();    
  
  // return the size
  //
  return bytes;
}
