//
// $Id: mkstat.cpp,v 1.5 2003/02/13 23:37:46 mcoletti Exp $
//
// Utility for creating a STAT module from the contents of an existing
// CATD module.
//

#include <iostream>
#include <fstream>
#include <strstream>

#include <algorithm>

#include <cstdlib>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

using namespace std;

#include "sysutils/fileutils.h"



// stooopid IRIX has non-standard getopt() behavior; it returns -1
// instead of EOF when the last command line argument is processed

#ifdef _SGIAPI
#include <getopt.h>
#else
const int GETOPTDONE = EOF;
#endif



#include <sdts++/container/sc_Record.h>
#include <sdts++/io/sio_8211Converter.h>
#include <sdts++/io/sio_Writer.h>
#include <sdts++/io/sio_Reader.h>
#include <sdts++/builder/sb_Module.h>
#include <sdts++/builder/sb_Stat.h>
#include <sdts++/builder/sb_Catd.h>


#include "emit.h"


static const char* _ident = 
   "$Id: mkstat.cpp,v 1.5 2003/02/13 23:37:46 mcoletti Exp $";



bool verbose;                   // true if user wants noisy output
bool force_lowercase;           // XXX Kludge!  This doesn't need it!



void
usage( const char* executable )
{
  cout << "Usage:\t"
       << executable
       << " [-h]"
       << " [-v]"
       << " <CATD module filename>"
       << " <STAT module filename>\n";

  exit( -1 );

} // usage





//
// Given a file name for a module, open it and return how many records it has.
//
static
int
_getRecordCount( string const& file_name )
{
  ifstream ifs( file_name.c_str(), ios::in );

  if ( ! ifs )
  {
    cerr << "unable to open module " << file_name << "\n";
    return 0;
  }

  sio_8211Reader reader( ifs );

  sio_8211ForwardIterator i( reader );

  int count = 0;

  while ( i )
  {
    ++count;
    ++i;
  }

  ifs.close();

  return count;

} // _getRecordCount
 



void
create_stat( ifstream& catd_stream, 
             string const& catd_fn, 
             string const& stat_fn,
             ofstream& stat_stream )
{
  // first blat out the 8211 DDR

  sb_Stat stat_module;


  sio_8211Schema stat_schema;

  stat_module.getSchema( stat_schema );

  sio_8211Writer writer( stat_stream, 
                         fileutils::basename( stat_fn ), 
                         stat_schema );


  writer.emitDDR();             // blat out ISO 8211 header


                                // first we iterate through the catalog
                                // module so that we're assured of
                                // getting the canonical file names
                                // for this transfer -- I didn't want
                                // to risk using any sort of directory
                                // walking scheme that would
                                // inadvertently pick up files that
                                // happened to be leftover from other
                                // transfer encoding runs


  sio_8211Reader reader( catd_stream );
  sio_8211ForwardIterator record_itr( reader );

  sc_Record record;

  sb_Catd catd_module;


  string path = fileutils::dirname( catd_fn );

                                // assume that all the
                                // modules we're going to look at are
                                // in the same directory as the CATD
                                // module; so, strip out the directory
                                // part of the path name so we can
                                // later prepend that to the file
                                // names we find in the CATD module


  path += "/";                  // '/' terminate path


  string tmp_string;

  long id_counter = 0;


  stat_module.setNSAD( 0 );     // set once and then re-used

  while( record_itr )
  {
    record_itr.get( record );

    if ( ! catd_module.setRecord( record ) )
      {
        cerr << catd_fn << " is not a valid CATD module ... aborting\n";
        exit( 1 );
      }

    catd_module.getNAME( tmp_string );
    stat_module.setMNRF( tmp_string );

    if ( "STAT" == tmp_string ) // we're currently writing it, so just
    {                           // skip it; we'll build it last
      ++record_itr;
      continue;
    }

    id_counter++;
    stat_module.setID( id_counter ); // Set RCID

    catd_module.getTYPE( tmp_string );
    stat_module.setMNTF( tmp_string );

    catd_module.getFILE( tmp_string );
    stat_module.setNREC(  _getRecordCount( path + tmp_string )  );

    emit( stat_module, writer );

    ++record_itr;
  }

                                // now add the STAT module record
  id_counter++;

  stat_module.setID( id_counter );

  stat_module.setMNTF( "Transfer Statistics" );
  stat_module.setNREC( id_counter );
  stat_module.setMNRF( "STAT" );

  emit( stat_module, writer );

} // create_stat


int
main( int argc, char** argv )
{

#ifdef EF
  EF_PROTECT_FREE  = 1;         // ElectricFence
  EF_PROTECT_BELOW = 0;
  EF_ALIGNMENT     = 0;
#endif


  extern char *optarg;
  extern int   optind;

  string catd_filename;
  string stat_filename;

  verbose = false;

  int ch;                      // getopt char buffer

  while((ch = getopt(argc, argv, "hv")) != GETOPTDONE)
    switch(ch)
    {
      case 'v':
        verbose = true;
        break;

      case 'h':
        usage( argv[0] );
        exit( 0 );
        break;

      case '?':
      default:
        usage( argv[0] );
        exit( 1 );
        break;
    }

  if ( optind == argc )
    {
      cerr << "missing CATD module file name\n";
      usage( argv[0] );
      exit( 1 );
    }

  catd_filename = argv[optind];

  if ( catd_filename.empty() )
    {
      cerr << "must specifiy CATD module filename\n";
      usage( argv[0] );
      exit( 1 );
    }

  if ( ! argv[optind+1] )
    {
      cerr << "must specifiy a STAT module filename\n";
      usage( argv[0] );
      exit( 1 );
    }

  stat_filename = argv[optind+1];


  ifstream catd_stream;

  catd_stream.open( catd_filename.c_str(), ios::in );

  if( ! catd_stream )
    {
      cout << "Unable to open CATD module " << catd_filename 
           << ".  Aborting.\n";
      return 2;
    }


  ofstream stat_stream;

  stat_stream.open( stat_filename.c_str(), ios::out );

  if( ! stat_stream )
    {
      cout << "Unable to create STAT module " << stat_filename 
           << ".  Aborting.\n";
      return 2;
    }
                                //  now go run off and make the STAT
                                //  module by iterating through the
                                //  CATD module, getting file names,
                                //  opening those up, and then
                                //  counting each record.

  create_stat( catd_stream, catd_filename, stat_filename, stat_stream );



  catd_stream.close();          // clean-up
  stat_stream.close();


  return 0;

}


syntax highlighted by Code2HTML, v. 0.9.1