// file: $isip/util/speech/isip_svm_classify/isip_svm_classify.cc
//
// isip include files
//
#include "isip_svm_classify.h"

// isip_svm_classify: computes the distance of the feature from the hyperplain
//
int main(int argc, const char** argv) {

  // setup the command line
  //
  Sdb sdb;
  CommandLine cmdl(sdb);
  cmdl.setUsage(
#include "usage_message.text"
                );
  cmdl.setHelp(
#include "help_message.text"
               );

  cmdl.setIdent("$Revision: 10624 $",
		"$Name: $",
		"$Date: 2006-08-24 11:05:14 -0500 (Thu, 24 Aug 2006) $");
  
  // add a command line option for the model file
  //
  Filename model_file;
  cmdl.addOptionParam(model_file, OPTION_MODEL_FILE, (Filename)EMPTY);

  // add a command line option for the audio database file
  //  
  Filename audio_db_file;
  cmdl.addOptionParam(audio_db_file, OPTION_AUDIO_DB_FILE, (Filename)EMPTY);  

  // add a command line option for the output file
  //
  Filename output_file;
  cmdl.addOptionParam(output_file, OPTION_OUTPUT_FILE, (Filename)EMPTY);
  
  // add a command line option for the debug level
  //
  DebugLevel debug_level;
  cmdl.addOptionParam(debug_level, OPTION_DEBUG_LEVEL,
		      DEBUG_LEVEL_DEFAULT);

  // add a command line option for the log verbosity level
  //
  DebugLevel verbosity;
  cmdl.addOptionParam(verbosity, OPTION_VERBOSITY_LEVEL,
		      VERBOSITY_LEVEL_DEFAULT);

  // add a command line option for the log file
  //
  Filename log_file;
  cmdl.addOptionParam(log_file, OPTION_LOG_FILE, (Filename)LOG_FILE_DEFAULT);
  
  // parse the command line
  //
  if (!cmdl.parse(argc, argv)) {
    cmdl.printUsage();
  };

  // open the log file
  //
  if (log_file.ne(L"-")) {
    Console::open(log_file);
    Console::setLineWrap(File::NO_WRAP);
  }

  // print the command line
  //
  if (verbosity >= Integral::BRIEF) {
    cmdl.printCommandLine();
    cmdl.printVersion();
  }

  // check the model file argument
  //
  if(model_file.eq((Filename)EMPTY)) {
    cmdl.printUsage();
  };

  // check the output file argument
  //  
  if(output_file.eq((Filename)EMPTY)) {
    cmdl.printUsage();
  };

  // check the audio database file argument
  //  
  if(audio_db_file.eq((Filename)EMPTY)) {
    cmdl.printUsage();
  };  

  // declare local variables
  //
  Sof mfile;
  File ofile;  
  
  String output;
  String identifier;
  String distance_str;
  
  Filename input_ID;
  Filename input_file_name;
  
  AudioDatabase audio_db;  
  StatisticalModel stat_model;

  FeatureFile feature_file;  
  Vector<AlgorithmData> data;

  long total_num_frames = 0;
  long current_file_num = 0;
  
  // setup the algorithm data structure for reading
  //
  data.setLength(1);
  data(0).makeVectorFloat();
  
  // open the support vector model
  //  
  if (!mfile.open(model_file, File::READ_ONLY)) {
    output.assign(L"\ncannot open file: ");
    output.concat(model_file);
    output.concat(L", bailing out...");
    Console::put(output);
    Integral::exit();
  }
  
  // read the support vector model
  //
  if (verbosity >= Integral::BRIEF) {
    Console::increaseIndention();    
    output.assign(L"\nloading support vector model: ");
    output.concat(model_file);
    Console::put(output);
    Console::decreaseIndention();    
  }
  
  if (!stat_model.read(mfile, (long)0)) {
    output.assign(L"\nerror reading model: ");
    output.concat(model_file);
    output.concat(L", bailing out...");
    Console::put(output);
    Integral::exit();    
  }

  // load the audio database
  //
  if (verbosity >= Integral::BRIEF) {
    Console::increaseIndention();
    output.assign(L"\nloading audio database: ");
    output.concat(audio_db_file);
    Console::put(output);
    Console::decreaseIndention();
  }
  
  if (!audio_db.open(audio_db_file)) {
    output.assign(L"\ncannot load audio database: ");
    output.concat(audio_db_file);
    output.concat(L", bailing out...");
    Console::put(output);
    Integral::exit();
  }
  
  // open the output file
  //
  if (verbosity >= Integral::BRIEF) {
    Console::increaseIndention();    
    output.assign(L"\nopening output file: ");
    output.concat(output_file);
    Console::put(output);
    Console::decreaseIndention();    
  }
  
  if (!ofile.open(output_file, File::WRITE_ONLY, File::TEXT)) {
    output.assign(L"\ncannot open file: ");
    output.concat(output_file);
    output.concat(L", bailing out...");
    Console::put(output);
    Integral::exit();
  }
  
  // loop over all feature file(s)
  //
  current_file_num = 0;  

  for (sdb.gotoFirst(); sdb.getName(input_ID); sdb.gotoNext()) {

    current_file_num++;
    
    // get audio file identifier
    //
    identifier.assign(input_ID);
      
    if (!audio_db.getRecord(identifier, input_file_name)) {      
      output.assign(L"\ncannot read identifier from audio database: ");
      output.concat(identifier);
      output.concat(L", bailing out...");
      Console::put(output);
      Integral::exit();
    }

    // print utterance processing information
    //      
    if (verbosity >= Integral::BRIEF) {
      Console::increaseIndention();
      output.assign(L"\nprocessing file ");
      output.concat(current_file_num);
      output.concat(L" (");
      output.concat(identifier);
      output.concat(L")");
      output.concat(L": ");
      output.concat(input_file_name);
      Console::put(output);
      Console::decreaseIndention();	    
    }
    
    // open the sof file for reading
    //
    if (!feature_file.open(input_file_name)) {
      output.assign(L"\ncannot open feature file: ");
      output.concat(input_file_name);
      output.concat(L", bailing out...");
      Console::put(output);
      Integral::exit();
    }
    
    // loop over all features in the feature file
    //
    long num_frames = feature_file.getNumFrames();
    total_num_frames += num_frames;
    
    for (long i=0; i < num_frames; i++) {

      // read the feature
      //
      feature_file.getBufferedData(data, i, 1);

      // compute the distance
      //
      double distance =
	stat_model.getSupportVectorModel().getDistance(data(0).getVectorFloat());
      distance_str.assign(distance);

      // write the distance to file
      //
      ofile.put(distance_str);
      ofile.put(L"\n");      
      
      if (debug_level >= Integral::DETAILED) {
	distance_str.debug(L"distance");
      }
    }
    
    // close the file descriptor
    //
    feature_file.close();
  }
  
  // close the file descriptor(s)
  //
  mfile.close();
  ofile.close();
  
  // close the audio database
  //
  audio_db.close();

  if (verbosity >= Integral::BRIEF) {    
    output.assign(L"\nprocessed ");
    output.concat(current_file_num);
    output.concat(L" file(s) successfully, attempted ");
    output.concat(current_file_num);
    output.concat(L" file(s), ");
    output.concat(total_num_frames);
    output.concat(L" frame(s)\n");    
    Console::put(output);
  }
    
  // close the log file
  //
  if (log_file.ne(L"-")) {
    Console::close();
  }

  // exit gracefully
  //
  return Integral::exit();
}
