Logo Search packages:      
Sourcecode: magics++ version File versions  Download package

MvObs.cc

// MvObs.cc,     vk 940818...
//           rev vk 980501

//--------------------------------------------------------------------
//  A class to hide the complexities of BUFR routines written in
//  FORTRAN.  'MvObs' tries to wrap these routines into a nicer C++
//  interface and hide the required data structures.
//  Headers for the FORTRAN functions are defined in the file 'MvBufr.h'
//--------------------------------------------------------------------
//    FORTRAN routines and required data structures are described in:
//
//    "Decoding Data Represented in FM 94 BUFR"
//         by J.K.Gibson and M.Dragosavac
//
//             published as PAPER 4 in
//
//    "BINARY
//     UNIVERSAL FORM FOR
//     DATA REPRESENTATION
//     ----------------------------------
//     FM 94 BUFR
//     Collected papers and specification"
//
//            ECMWF February 1988.
//
//  and in:
//
//     "BUFR User Guide and Reference Manual"
//         by Milan Dragosavac
//     European Centre for Medium-Range Weather Forecasts
//         preprint  12 October 1994
//--------------------------------------------------------------------

#include "inc_iostream.h"
#include <sstream>  //-- requires new templated standard io headers!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
//F #include "Metview.h"
#include "MvObs.h"

#ifdef METVIEW
#  include "MvException.h"
#else
#  include <exception>
#endif

// Static int used to duplicate stdout and get it back.
static int new_fd = -1;

const int MAX_BUBOX_KELEM_LIMIT  = MAX_KELEM;

static string CCITTIA5("CCITTIA5");
static string MESSED_UP("[messed messages!]");

static string BBOXNAME("prtbbox.txt"); //for BUPRTBOX output.
static string redirect_dir(""); // For tmp files from print.

//--------------------------------------------------------
// Fortran routines expect previous values to be remained
// (at least in some of the arrays) if new msg has same
// descriptors as previous msg !!!
// Thus static arrays, common to all bufr-objects...
// Added lazy evaluation 980501/vk...
//--------------------------------------------------------
static char* In_CNAMES = 0;  //static char In_CNAMES[ MAX_KELEM ][ 64 ]; //- is not updated if same descriptors
static char* In_CUNITS = 0;  //static char In_CUNITS[ MAX_KELEM ][ 24 ]; //- is not updated if same descriptors
static char* In_CVALS  = 0;  //static char In_CVALS [ MAX_KVALS ][ 80 ]; //+ rest of the arrays always updated
static char* Out_CVALS = 0;  //static char Out_CVALS [ MAX_KVALS ][ 80 ];

static fortfloat* In_VALUES = 0;  //static fortfloat  In_VALUES[ MAX_KVALS ];
static fortfloat* Out_VALUES = 0; //static fortfloat Out_VALUES[ MAX_KVALS ];

static fortint  In_KELEM;
static fortint  In_KVALS;
static fortint  Out_KELEM = -1;
                                      // for BUSEL
static fortint  In_KTDEXL;
static fortint* In_KTDEXP = 0;  //static fortint  In_KTDEXP[ MAX_KELEM ];
static fortint  In_KTDLEN;
static fortint* In_KTDLST = 0;  //static fortint  In_KTDLST[ MAX_KELEM ];
static fortint  Out_KTDEXL;
static fortint* Out_KTDEXP = 0; //static fortint Out_KTDEXP[ MAX_KELEM ];
static fortint  Out_KTDLEN;
static fortint* Out_KTDLST = 0; //static fortint Out_KTDLST[ MAX_KELEM ];

static int arraySizeIndex = 0; // incremented each time we try to allocate a new size of arrays
static int kVals;

long MvBufr::_bufrIn_ref = 0;
long MvBufrOut::_bufrOut_ref = 0; //not yet implemented...


//-- Linux/g++ does not like hardcoded big? arrays (works ok in debugger,
//-- but crashes inside Metview...) => create arrays dynamically, once!
//-- These are for BUFR-BOX routines (accessing Feedback info)

static fortint    myKSUB, myKBOX, myKAPP, myKLEN, myKERR;
static fortint*   myKBOXR = 0;
static fortfloat* myVALS  = 0;
static char*      myCBOXN = 0;
static char*      myCBOXU = 0;


const long cPressureCoordinate = 7004L;  // pressure vertical coord. descriptor value

//--------------------------------------------------------
//  Descriptor mnemonics for class 'MvBufrParam'
//--------------------------------------------------------

#ifndef DOXYGEN_SHOULD_SKIP_THIS

typedef struct
{
   const char *name;
   long        descriptor;
} descriptorStruct;

static descriptorStruct knownParams[] =
{
   {"z", 10003}, {"p", 10004},
   {"ddd", 11001}, {"ff", 11002}, {"u", 11003}, {"v", 11004}, {"w", 11006},
   {"T", 12001}, {"Td",12003}, {"T(2m)",12004}, {"Td(2m)",12006},
   {"END",0}
};
#endif

//--------------------------------------------------------
//  Function definitions for the FORTRAN & C BUFR routines
//--------------------------------------------------------

extern "C" {

 void
 BUS012( fortint *KBUFL, fortint *KBUFF, fortint *KSUP
       , fortint *KSEC0, fortint *KSEC1, fortint *KSEC2, fortint *KERR );

 void
 BUPRS0( fortint *KSEC0 );
 void
 BUPRS1( fortint *KSEC1 );
 void
 BUPRS2( fortint *KSUP, fortint *KEY);

 void
 BUFREX( fortint *KBUFL, fortint *KBUFF, fortint *KSUP
       , fortint *KSEC0, fortint *KSEC1, fortint *KSEC2, fortint *KSEC3, fortint *KSEC4
       , fortint *KELEM, char *CNAMES,     char *CUNITS
       , fortint *KVALS, fortfloat *VALUES,  char *CVALS, fortint *KERR );

 void
 BUFREN( fortint *KSEC0, fortint *KSEC1, fortint *KSEC2, fortint *KSEC3, fortint *KSEC4
       , fortint *KTDLEN,fortint *KTDLST,fortint *KDLEN, fortint *KDATA
       , fortint *KELEM, fortint *KVALS, fortfloat *VALUES, char *CVALS
       , fortint *KBUFL, fortint *KBUFF, fortint *KERR );

 void
 BUSEL( fortint *KTDLEN, fortint *KTDLST, fortint *KTDEXL, fortint *KTDEXP, fortint *KERR );

 void
 BUUKEY(fortint *KSEC1, fortint *KSEC2, fortint *KEY, fortint *KSUP,fortint *KERR);
 void
 BUPRS3( fortint *KSEC3, fortint *KTDLEN, fortint *KTDLST
       , fortint *KTDEXL, fortint *KTDEXP, fortint *KELEM, char *CNAMES );

 void
 BUBOX( fortint *KSUB,   fortint *KSUP,      fortint *KELEM
      , fortint *KWTR,   char *CNAMES, char *CUNITS
      , fortint *KVALS,  fortfloat *VALUES,  fortint *KBOX
      , fortint *KAPP,   fortint *KLEN,      fortint *KBOXR
      , fortfloat *VALS, char* CBOXN,        char* CBOXU
      , fortint *KERR );

  void
  BUPRTBOX( fortint *KBOX,   fortint *KAPP,   fortint *KLEN
          , fortint *KBOXR,  fortfloat *VALS, char* CBOXN
          , char* CBOXU );

 // Helper functions
 boolean redirect_6(const char *);  //-- Trick to redirect Fortran unit 6.
 boolean reconnect_6();
 boolean file_to_stream(const char *,ostream&,int skip);
 void delete_print_file(const char *);
}


//______________________________________________________________________

Section1Base::Section1Base( const unsigned char* octs )
{
   int slen = 65536*octs[0] + 256*octs[1] + octs[2];
   octets_ = new unsigned char[slen];
   memcpy( octets_, octs, slen );
}

Section1Base::Section1Base( const Section1Base* aSec1 )
{
   octets_ = new unsigned char[ aSec1->len() ];
   memcpy( octets_, aSec1->start(), aSec1->len() );
}

bool
Section1Base::isDifferent( const Section1Base* aSec1 ) const
{
   if( len() != aSec1->len() )
      return true;

   for( int i=0; i<len(); ++i )
      if( octets_[i] != aSec1->octets_[i] )
         return true;

   return false;
}

bool
Section1_preEd4::hasSection2()
{
   return octets_[7] > 127;   //-- octet 8
}
bool
Section1_Ed4::hasSection2()
{
   return octets_[9] > 127;   //-- octet 10
}

TDynamicTime
Section1_preEd4::date()
{
   //-- octet 13=year, 14=month, etc.
   return TDynamicTime( octets_[12], octets_[13], octets_[14], octets_[15], octets_[16] );
}
TDynamicTime
Section1_Ed4::date()
{
   //-- octet 13=year, 14=month, etc.
   return TDynamicTime( 256*octets_[15]+octets_[16], octets_[17], octets_[18]
                  , octets_[19], octets_[20], octets_[21] );
}

int
Section1_preEd4::msgType()
{
   return octets_[8];         //-- octet 9
}
int
Section1_Ed4::msgType()
{
   return octets_[10];         //-- octet 11
}

int
Section1_preEd4::msgSubtype()
{
   return octets_[9];         //-- octet 10
}
int
Section1_Ed4::msgSubtype()
{
   return octets_[12];         //-- octet 13
}

int
Section1_preEd4::origCentre2()
{
   //return octets_[5];         //-- octet 5-6
  return 256*octets_[4] + octets_[5]; //-- octets 5 and 6
}
int
Section1_Ed4::origCentre2()
{
   return 256*octets_[4] + octets_[5]; //-- octets 5 and 6
}

int
Section1_preEd4::masterTable()
{
   return octets_[3];         //-- octet 4
}
int
Section1_Ed4::masterTable()
{
   return octets_[3]; //-- octet 4 
}

int
Section1_preEd4::masterTableVersion()
{
   return octets_[10];         //-- octet 11
}
int
Section1_Ed4::masterTableVersion()
{
   return octets_[13]; //-- octet 14 
}

int
Section1_preEd4::localTableVersion()
{
   return octets_[11];         //-- octet 12
}
int
Section1_Ed4::localTableVersion()
{
   return octets_[14]; //-- octet 15
}



//====================================================================== MvBufrBase
//______________________________________________________________________

MvBufrBase :: MvBufrBase( const long len ) : fSec2(NULL),fTotalSec2(NULL),
fSec0(NULL),Sec1(NULL),fSec3(NULL),fSec4(NULL)
{
  _refCount = 0;

  // Make sure the data is correctly aligned.
  longptr = new long[(len/sizeof(long)) + 1];
  fMessage = (char *)longptr;
  //fMessage = new char[ len  + 8 ];    // +8 for an extra "safety word"
  fMessageLength = len;

  fKSUP  = NULL;
  fKSEC0 = NULL;
  fKSEC1 = NULL;
  fKSEC2 = NULL;
  fKSEC3 = NULL;
  fKSEC4 = NULL;

      //-- lazy evaluation: create static arrays when first needed --
  createDataArrays ();
    }
//___________________________________________________________

MvBufrBase :: ~MvBufrBase( void )
{
//  delete [] fMessage;
  delete [] longptr;

  if( fSec2 )
  {
    delete fSec2;
    delete [] fTotalSec2;
  }
  delete fSec3;
  delete fSec4;

  if( fKSUP ) delete [] fKSUP;
  if( fKSEC0 ) delete [] fKSEC0;
  if( fKSEC1 ) delete [] fKSEC1;
  if( fKSEC2 ) delete [] fKSEC2;
  if( fKSEC3 ) delete [] fKSEC3;
  if( fKSEC4 ) delete [] fKSEC4;
}
//___________________________________________________________
void
MvBufrBase :: attach( void )
{
   _refCount++;
}
void
MvBufrBase :: detach( void )
{
   if( --_refCount == 0 )
     delete this;
}
//_________________________________________________________ createFortranArrays
void
MvBufrBase :: createFortranArrays( void )
{
  fKSUP  = new fortint[  9 ];
  fKSEC0 = new fortint[  3 ];
  fKSEC1 = new fortint[ 40 ];
  fKSEC2 = new fortint[ 4096 ]; //[ 128 ]; //[ 64 ];
  fKSEC3 = new fortint[  4 ];
  fKSEC4 = new fortint[  2 ];
}
//_________________________________________________________ createDataArrays
void
MvBufrBase :: createDataArrays( void )
{
    kVals    = aMAX_KVALS[arraySizeIndex];
    In_KVALS = kVals;

    try
    {
        if( In_VALUES == 0 )
            In_VALUES = new fortfloat[ kVals ];

        if( In_CVALS == 0 )
            In_CVALS = new char[ kVals * 80 ];

        if( In_CNAMES == 0 )
            In_CNAMES = new char[ MAX_KELEM * 64 ];

        if( In_CUNITS == 0 )
            In_CUNITS = new char [ MAX_KELEM * 24 ];

        if( In_KTDEXP == 0 )
            In_KTDEXP = new fortint[ MAX_KELEM ];

        if( In_KTDLST == 0 )
            In_KTDLST = new fortint[ MAX_KELEM ];
    }

    catch(...)
    {
        deleteDataArrays ();

#ifdef METVIEW
        marslog( LOG_EROR, "MvBufrBase::MvBufrBase: out-of-memory!" );
        throw MvException( "MvBufrBase::MvBufrBase: out-of-memory!" );
#else
        cerr << ">>>> MvBufrBase::MvBufrBase: out-of-memory => throw an exception <<<<" << endl;
        throw std::bad_alloc();
#endif
    }
}
//_________________________________________________________ createDataArrays
void
MvBufrBase :: deleteDataArrays( void )
{
    if( In_VALUES != 0 )
    {
        delete [] In_VALUES; In_VALUES = 0;
    }

    if( In_CVALS != 0 )
    {
        delete [] In_CVALS;  In_CVALS  = 0;
    }

    if( In_CNAMES != 0 )
    {
        delete [] In_CNAMES; In_CNAMES = 0;
    }

    if( In_CUNITS != 0 )
    {
        delete [] In_CUNITS; In_CUNITS = 0;
    }

    if( In_KTDEXP != 0 )
    {
        delete [] In_KTDEXP; In_KTDEXP = 0;
    }

    if( In_KTDLST != 0 )
    {
        delete [] In_KTDLST; In_KTDLST = 0;
    }
}
//___________________________________________________________
unsigned int
MvBufrBase :: unsignedInt( const unsigned char* firstOctet
                         , int octetCount )
{
  unsigned int value = *firstOctet;
  const unsigned char* anOctet = ++firstOctet;
  for( int i=octetCount-1; i; --i )
  {
    value = 256*value + *anOctet++;
  }
  return value;
}

//______________________________________________________________________
//====================================================================== MvBufr
//______________________________________________________________________

//______________________________________________________________________

MvBufr :: MvBufr( char *msg, long len, long aMessageNumber )
    : MvBufrBase( len )   //( msg, len )
{
  memcpy( fMessage, msg, (int)len );

  const unsigned char* msgStart = (const unsigned char*)fMessage;

  fSec0 = (TSection0 *)fMessage;
  int offSet = fSec0->editionNr < 2 ? 4 : 8;
                        // Section 0 was shorter in BUFR editions 0 and 1 !!!!
                        //                                  rev vk 950802
  if( fSec0->editionNr > 3 )
    Sec1 = new Section1_Ed4( msgStart + offSet );
  else
    Sec1 = new Section1_preEd4( msgStart + offSet );
  offSet += Sec1->len();

  if( Sec1->hasSection2() )         // bit 0 <=> Optional Section 2 present?
  {
    fSec2 = new TSection2;
    memcpy( (char *)fSec2, msgStart + offSet, sizeof(TSection2)  );

    int sec2Len = unsignedInt( &(fSec2->len), 3 );
    fTotalSec2 = new unsigned char[ sec2Len ];
    memcpy( (char *)fTotalSec2, msgStart + offSet, sec2Len );

    offSet += sec2Len;
  }
  else
  {
    fSec2 = NULL;
    fTotalSec2 = NULL;
  }

  fSec3 = new TSection3;
  memcpy( (char *)fSec3, msgStart + offSet, sizeof(TSection3)  );
  offSet += unsignedInt( &(fSec3->len), 3 );

  fSec4 = new TSection4;
  memcpy( (char *)fSec4, msgStart + offSet, sizeof(TSection4)  );
  offSet += unsignedInt( &(fSec4->len), 3 );

  computeIn_KELEM ();

  fMessageNumber = aMessageNumber;
  _currentDescr = 0;
  _currentDescrInd = -1;
  _inState = kBufrIn_Coded;
  _bufrIn_ref++;
  _bufrBoxFilledSubset = 0;
}
//______________________________________________________________________

MvBufr :: ~MvBufr( void ) { }

//____________________________________________________________________ Decode
void
MvBufr :: Decode( void )
{
   if( _inState == kBufrIn_Error )
      return;

   if( _inState < kBufrIn_DataDecoded )
   {
      createFortranArrays();
      fortint myKBUFL = fMessageLength / sizeof(long) + 1;  // +1 = Q&D
        bool keepGoing = true;

        // we will try to decode the BUFR a number of times, starting with
        // relatively small data arrays, then building up to larger ones
        // (so that we don't waste too much memory)

        while (keepGoing)
        {
            keepGoing = false;

      BUFREX(&myKBUFL
          , (fortint *)fMessage  // buffer for the BUFR message
          , fKSUP          // array for suplementary info
          , fKSEC0         // FORTRANized section 0
          , fKSEC1         // FORTRANized section 1
          , fKSEC2         // FORTRANized section 2 (site dependent)
          , fKSEC3         // FORTRANized section 3 (data descriptors)
          , fKSEC4         // FORTRANized section 4 (data values)
          ,&In_KELEM
          , In_CNAMES
          , In_CUNITS
          ,&In_KVALS
          , In_VALUES
          , In_CVALS
          ,&fKERR );


            // if KELEM is not big enough, then we will
            // try again with a bigger value

            if( fKERR == 25 || fKERR == 14)
            {
                cout << "MvBufr :: Decode - kVals of " << kVals << " and In_KELEM of " << In_KELEM
                     << " is not large enough." << endl;
                
                if (++arraySizeIndex < NUM_MAX_KVALS)
                {
                    cout << "Trying kVals of " << aMAX_KVALS[arraySizeIndex] <<
                         " (" << (aMAX_KVALS[arraySizeIndex] * 80) / (1024*1024) << "MB)" << endl;

                    deleteDataArrays ();
                    createDataArrays ();
                    computeIn_KELEM ();

                    keepGoing = true;
                }
                else
                    arraySizeIndex = NUM_MAX_KVALS - 1; // should not be used, but just in case,
                                                        // make sure the index is not out of bounds...
            }
        }
        
        
      if( fKERR )
      {
       cerr << "In_KELEM " << In_KELEM << " kvals " << In_KVALS << endl;
       cerr << " >>> MvBufr::Decode, bufrmsg " << fMessageNumber
            << ": fKERR = " << fKERR << endl;


#ifdef METVIEW
       marslog( LOG_EROR, "BUFR decoding (BUFREX) failed, status = %d", fKERR );
       throw MvException( "Unable to decode BUFR message" );
#endif
       _inState = kBufrIn_Error;
       return;
      }

      _inState = kBufrIn_DataDecoded;
   }
}
//____________________________________________________________________ ExpandDescriptors
void
MvBufr :: ExpandDescriptors( void )
{
   if( _inState == kBufrIn_Error )
      return;

   In_KTDLEN = -1;
   In_KTDEXL = -1;

   if( _inState < kBufrIn_DataDecoded )
      Decode();

   if( _inState == kBufrIn_DataDecoded )
   {
      BUSEL( &In_KTDLEN      // nr of original data descriptors in Section 3
         ,  In_KTDLST      // original descriptors
         , &In_KTDEXL      // nr of expanded data descriptors
         ,  In_KTDEXP      // expanded descriptors
         , &fKERR
         );

      if( fKERR )
      {
       cerr << " >>> MvBufr::ExpandDescriptors: fKERR = " << fKERR << endl;

#ifdef METVIEW
       marslog( LOG_EROR, "BUFR expansion (BUSEL) failed, status = %d", fKERR );
#endif

       _inState = kBufrIn_Error;
      }
      else
         _inState = kBufrIn_DataAndDescriptorsDecoded;
   }
}
//__________________________________________________________ descriptorToFortranIndex
int
MvBufr :: descriptorToFortranIndex( const long aDescr, const int firstIndex )
{
   if( _inState == kBufrIn_Error )
      return -1;

   if( _inState != kBufrIn_DataAndDescriptorsDecoded )
      ExpandDescriptors();

   if( _inState == kBufrIn_DataAndDescriptorsDecoded )
   {
      for( int i=firstIndex; i < In_KTDEXL; i++ )
      {
       if( In_KTDEXP[ i ] == aDescr )
         {
         return i;
         }
      }
   }
   return -1;
}
//__________________________________________________________ computeIn_KELEM
void
MvBufr :: computeIn_KELEM( void )
{
    if ( subsetCount() > 1 )
        In_KELEM = kVals / subsetCount();
    else
        In_KELEM = MAX_KELEM;

    if( In_KELEM > MAX_BUBOX_KELEM_LIMIT )
        In_KELEM = MAX_BUBOX_KELEM_LIMIT;
}
//__________________________________________________________ DataValue
//
// Returns the requested parameter value (or missing value)
// and updates _currentDescrInd.
//

fortfloat
MvBufr :: DataValue( const int aDescrArrayInd, const long aSubsetNumber )
{
   if( _inState < kBufrIn_DataDecoded )
      Decode();

   if( ( aSubsetNumber > subsetCount() ) || ( aDescrArrayInd < 0 ) )
   {
      _currentDescr = 0;
      _currentDescrInd = -1;
      return kFortranBufrMissingValue;
   }

   _currentDescrInd = aDescrArrayInd;
   _currentDescr = In_KTDEXP[ _currentDescrInd ];

   return PeekDataValue( _currentDescrInd, aSubsetNumber );
}
//__________________________________________________________ PeekDataValue
//
// Returns the requested parameter value (or missing value)
// without updating _currentDescrInd.
//

fortfloat
MvBufr :: PeekDataValue( const int aDescrArrayInd, const long aSubsetNumber )
{
   if( ( aSubsetNumber > subsetCount() ) || ( aDescrArrayInd < 0 ) )
     return kFortranBufrMissingValue;
   else
     return In_VALUES[ aDescrArrayInd + ( aSubsetNumber - 1 ) * In_KELEM ];
}
//__________________________________________________________ Value
boolean
MvBufr :: Value( const long aDescriptor
             , const long aSubsetNumber
             , fortfloat &aDataValue
             , int   firstInd )
{
  aDataValue = DataValue( descriptorToFortranIndex( aDescriptor, firstInd )
                  , aSubsetNumber );
  return aDataValue != kFortranBufrMissingValue ? true : false;
}
//__________________________________________________________ intValue
// returns 'kFortranBufrMissingIntValue' if not found!
//----------------------------------------------------
long
MvBufr :: intValue( const long aDescriptor, const int subsetNr )
{
   fortfloat myValue;
   Value( aDescriptor, subsetNr, myValue );

   if( myValue != kFortranBufrMissingValue )
     return (long)myValue;
   else
     return kFortranBufrMissingIntValue;
}
//____________________________________________________________________ feedbackValue
double
MvBufr::feedbackValue( int col, int subset )
{
   if( _currentDescrInd < 0 )
      return kBufrMissingValue;
   else
      //-- first 6 rows is reserved info, obs report starts on row 7
      return feedbackValue( _currentDescrInd + 6, col, subset );
}

double
MvBufr::feedbackValue( int row, int col, int subset )
{
   int err = fillBufrBox( subset );

   assert( row > 0 && row <= myKBOX );
   assert( col > 0 && col <= myKAPP );

   if( err == 0 )
      return myVALS[ myKLEN*(col-1) + row - 1 ];
   else
      return kBufrMissingValue;
}
//____________________________________________________________________ obsTime
TDynamicTime
MvBufr :: obsTime( const int subsetNr )
{
   short myYear  = (short)intValue( 4001L, subsetNr );
   short myMonth = (short)intValue( 4002L, subsetNr );
   short myDay   = (short)intValue( 4003L, subsetNr );
   short myHour  = (short)intValue( 4004L, subsetNr );

   short myMin, mySec;
   fortfloat myValue;

   if( Value( 4005L, subsetNr, myValue ) )
      myMin = (short)myValue;
   else
      myMin = 0;

   if( Value( 4006L, subsetNr, myValue ) )
      mySec = (short)myValue;
   else
      mySec = 0;

   return TDynamicTime( myYear, myMonth, myDay, myHour, myMin, mySec );
}
//____________________________________________________________________ msgTime
TDynamicTime
MvBufr :: msgTime( void )
{
#if 0
   short myYear  = fSec1->yearYY ;
   short myMonth = fSec1->month ;
   short myDay   = fSec1->day ;
   short myHour  = fSec1->hour ;
   short myMin   = fSec1->minute ;

   return TDynamicTime( myYear, myMonth, myDay, myHour, myMin, 0 );
#endif

   return Sec1->date();
}
//____________________________________________________________________ stringValue
string
MvBufr :: stringValue( const long aDescriptor, const int aSubsetNr )
{
   _currentDescrInd = descriptorToFortranIndex( aDescriptor );
   return stringValueByIndex( _currentDescrInd, aSubsetNr );
}
//____________________________________________________________________ stringValue
string
MvBufr :: stringValue( const int aSubsetNr )
{
   return stringValueByIndex( _currentDescrInd, aSubsetNr );
}
//__________________________________________________________ stringValueByIndex
string
MvBufr :: stringValueByIndex( const int anIndex, const int aSubsetNr )
{
   if( ( anIndex < 0 ) || ( anIndex >= In_KTDEXL ) )
     {
       return string( "[string index error!]" );
     }

   //-- get coded float value --
   fortfloat myValue = DataValue( anIndex, aSubsetNr );

   //-- here we should be passing subset nr, not index!!! (020307/vk)
   //-- thus always pass 1:

   if( elementValueType( 1 ) == kEVT_string )
     {
       if( myValue == kFortranBufrMissingValue )
       {
         return string( "[Missing String Value]" );
       }

       //-- get pointer and length to In_CVALS array, In_CVALS starts from 0.. --
       int myIndex = (int)myValue / 1000 - 1;
       int myLength = (int)myValue % 1000;

       //-- add C-terminator (sacrifice last character if necessary) --
       int terminatorPos = myLength;
       if( terminatorPos > 79 )
       terminatorPos = 79;
       //In_CVALS[ myIndex ][ terminatorPos ] = '\0';
       In_CVALS[ myIndex*80 + terminatorPos ] = '\0';

       return string(In_CVALS + myIndex*80);
     }
   else if( elementValueType( 1 ) == kEVT_numeric )
     {
       ostringstream oss;
       oss << myValue;

       return oss.str();
     }

   return string( "[Not a String Value]" );
}
//____________________________________________________________________ unit
string
MvBufr :: unit( const long aDescriptor )
{
   return unitByIndex( descriptorToFortranIndex( aDescriptor ) );
}
//____________________________________________________________________ unit
string
MvBufr :: unit( void )
{
   return unitByIndex( _currentDescrInd );
}
//____________________________________________________________________ unitByIndex
string
MvBufr :: unitByIndex( const int anIndex )
{
   char strbuf[ 25 ];

   if( ( anIndex >= 0 ) && ( anIndex < In_KTDEXL ) )
   {
      strbuf[ 24 ] = '\0';               //-- make a copy
      int pos;
      for( pos=23; pos>=0; --pos )
         strbuf[ pos ] = In_CUNITS[ anIndex*24 + pos ];
         //strbuf[ pos ] = In_CUNITS[ anIndex ][ pos ];

      for( pos=23; pos > 0; pos-- )      //-- remove trailing blanks
         if( strbuf[ pos ] == ' ' )
            strbuf[ pos ] = '\0';
         else
            break;

      return string( strbuf );
   }
   return string( "[Unit not found!]" );
}
//____________________________________________________________________ name
string
MvBufr :: name( const long aDescriptor )
{
   return nameByIndex( descriptorToFortranIndex( aDescriptor ) );
}
//____________________________________________________________________ name
string
MvBufr :: name( void )
{
   return nameByIndex( _currentDescrInd );
}
//____________________________________________________________________ nameByIndex
string
MvBufr :: nameByIndex( const int anIndex )
{
   char strbuf[ 65 ];

   if( ( anIndex >= 0 ) && ( anIndex < In_KTDEXL ) )
   {
      strbuf[ 64 ] = '\0';               //-- make copy
      int pos;
      for( pos=63; pos>=0; --pos )
         strbuf[ pos ] = In_CNAMES[ anIndex*64 + pos ];
        // strbuf[ pos ] = In_CNAMES[ anIndex ][ pos ];

      for( pos=63; pos > 0; pos-- )      //-- remove trailing blanks
         if( strbuf[ pos ] == ' ' )
            strbuf[ pos ] = '\0';
         else
            break;

      boolean retainCapital = true;      //-- change to lower case
      for( pos = 0; pos < strlen( strbuf ); pos++ )
      {
         if( isupper( strbuf[ pos ] ) )
         {
            if( retainCapital )
               retainCapital = false;
            else
               strbuf[ pos ] = tolower( strbuf[ pos ] );
          }
          else
             retainCapital = true;
      }
      return string( strbuf );
   }
   else
      return string( "[Name index error!]" );
}
//____________________________________________________________________ elementValueType
EElementValueType
MvBufr :: elementValueType( const int aSubsetNr )
{
  return elementValueTypeByIndex( _currentDescrInd, aSubsetNr );
}
//____________________________________________________________ elementValueType
EElementValueType
MvBufr :: elementValueType( const long aDescriptor, const int aSubsetNr )
{
  return elementValueTypeByIndex( descriptorToFortranIndex( aDescriptor ), aSubsetNr );
}
//_____________________________________________________ elementValueTypeByIndex
EElementValueType
MvBufr :: elementValueTypeByIndex( const int anIndex, const int aSubsetNr )
{
  fortfloat myValue = DataValue( anIndex, aSubsetNr );

  if( myValue == kFortranBufrMissingValue )
    return kEVT_missing;
  else
    return unitByIndex( anIndex ) == CCITTIA5 ? kEVT_string : kEVT_numeric;
}
//______________________________________________________________________
//
// Reset descriptor iterator by pointing to the first descriptor.
// Make sure msg has been expanded!
//

boolean
MvBufr :: SetFirstDescriptor( void )
{
   if( _inState == kBufrIn_Error )
      return false;

   if( _inState != kBufrIn_DataAndDescriptorsDecoded )
      ExpandDescriptors();

   if( _inState == kBufrIn_DataAndDescriptorsDecoded )
   {
      _currentDescrInd = 0;
      _currentDescr = In_KTDEXP[ _currentDescrInd ];
      return true;
   }
   return false;
}
//______________________________________________________________________
//
// Advance descriptor iterator.
// Check that it still points ok.
//

boolean
MvBufr :: SetNextDescriptor( void )
{
  if( _currentDescrInd < 0 )
     return false;           // SetFirstDescriptor had not been called !

  if( ++_currentDescrInd >= fKSUP[ 5 - 1 ] )
  {
     _currentDescrInd = -1;
     _currentDescr = 0;
     return false;
  }

  _currentDescr = In_KTDEXP[ _currentDescrInd ];
  return true;
}
//______________________________________________________________________
//
// calls Emoslib routines BUBOX and BUPRTBOX to produce "boxed" output
//
int
MvBufr::fillBufrBox( int aSubsetNr )
{
#if 0
  //-- Linux/g++ does not like hardcoded big? arrays (works ok in debugger,
  //-- but crashes inside Metview...) => create arrays dynamically, once!

  static fortint    myKSUB, myKBOX, myKAPP, myKLEN, myKERR;
  static fortint*   myKBOXR = 0;
  static fortfloat* myVALS  = 0;
  static char*      myCBOXN = 0;
  static char*      myCBOXU = 0;
#endif

  if( _bufrBoxFilledSubset == aSubsetNr )
     return 0;                               //-- OK, already filled

  if( ! myKBOXR )
    {
      try
      {
        myKBOXR = new fortint[ kVals ];
        cout << " fillBufrBox: array myKBOXR created" << endl;

        myVALS  = new fortfloat[ kVals ];
        cout << " fillBufrBox: array myVALS  created" << endl;

        myCBOXN = new char[ kVals * 64 ];
        cout << " fillBufrBox: array myCBOXN created" << endl;

        myCBOXU = new char[ kVals * 24 ];
        cout << " fillBufrBox: array myCBOXU created" << endl;
      }
      catch(...)
      {
        cout << " >>> fillBufrBox: problems in creating fort arrays <<<" << endl;
        delete myKBOXR;  myKBOXR = 0;
        delete myVALS;   myVALS  = 0;
        delete myCBOXN;  myCBOXN = 0;
        delete myCBOXU;  myCBOXU = 0;
#ifdef METVIEW
        marslog( LOG_EROR, "MvBufr::fillBufrBox: out-of-memory?" );
#endif
        return -13;
      }
    }


  //-- Initialize array given to bubox. bubox will not initialize
  //-- all values, and this will cause runtime error from buprtbox.
  for (int i = 0; i < kVals; i++ )
    myVALS[i] = kFortranBufrMissingValue;

  if( _inState == kBufrIn_Error )
    {
      cout << " fillBufrBox: BUFR msg error state, return false" << endl;
      return -1313;
    }

  if( _inState < kBufrIn_DataDecoded )
    {
      Decode();
    }

  if( _inState != kBufrIn_DataAndDescriptorsDecoded )
    {
      ExpandDescriptors();
    }

  myKSUB = (fortint)aSubsetNr;
  myKBOX = 0;
  myKAPP = 0;
  myKLEN = 0;
  myKERR = 0;

  BUBOX( &myKSUB     //-- INPUT arguments
       ,  fKSUP
       , &In_KELEM
       ,  In_KTDEXP
       ,  In_CNAMES
       ,  In_CUNITS
       , &In_KVALS
       ,  In_VALUES
                      //-- OUTPUT arguments
       , &myKBOX      //-- number of (valid) elements in 1st column
       , &myKAPP      //-- number of columns (apps) in the box
       , &myKLEN      //-- number of rows in the box
       ,  myKBOXR     //-- Table B descriptors
       ,  myVALS      //-- boxed values
       ,  myCBOXN     //-- boxed element names
       ,  myCBOXU     //-- boxed units
       , &myKERR );

  if( myKERR == 0 )
      _bufrBoxFilledSubset = myKSUB;

  return myKERR;
}
//______________________________________________________________________
//
bool
MvBufr::writeBufrBox( int aSubsetNr )
{
  cout << " writeBufrBox: entering" << endl;

  myKERR = fillBufrBox( aSubsetNr );

  //-- forces Fortran unit 6 into a file
  if( ! redirect_6(BBOXNAME.c_str()) )
    {
      cout << ">>> UNABLE TO REDIRECT stdout <<<" << endl;
      return false;
    }

  if( myKERR == 0 )
  {
     BUPRTBOX(&myKBOX
             ,&myKAPP
             ,&myKLEN
             , myKBOXR
             , myVALS
             , myCBOXN
             , myCBOXU );
  }

  //-- closes "unit'ified" unit 6
  if( ! reconnect_6() )
    {
      cerr << ">>> UNABLE TO RECONNECT TO stdout <<<" << endl;
      cout << ">>> UNABLE TO RECONNECT TO stdout <<<" << endl;
    }

  return myKERR == 0;
}

bool
MvBufr::getBufrBoxSize( int& rows, int& cols, int aSubsetNr )
{
  bool status = false;

  myKERR = fillBufrBox( aSubsetNr );

  if( myKERR == 0 )
  {
     rows = myKBOX;
     cols = myKAPP;
     status = true;
  }
  return status;
}

//------------- Printing functions -----------------
bool
MvBufr :: printSection( ostream& aStream,int which)
{
  boolean return_val = true;
  if( _inState == kBufrIn_Error )
    {
      aStream << "!!!!!!!!!!! Bad BUFR message " << endl;
      return false;
    }

  if ( _inState < kBufrIn_Sections012Expanded )
    Decode();

  if ( which == 3 && _inState < kBufrIn_DataAndDescriptorsDecoded )
    ExpandDescriptors();


  char sec_name[30];
  sprintf(sec_name,"prtsec%d.txt",which);

  redirect_6(sec_name);
  if ( which == 0 )
    BUPRS0(fKSEC0);
  else if ( which == 1 )
    BUPRS1(fKSEC1);
  else if ( which == 2 )
    {
      fortint *fKEY = new fortint[60];
      BUUKEY(fKSEC1,fKSEC2,fKEY,fKSUP,&fKERR);
      if ( fKERR )
      cout << "\nProblems getting key. Maybe non-existent? " << endl;
      else
      BUPRS2(fKSUP,fKEY);

      delete [] fKEY;
    }
  else
    BUPRS3(fKSEC3,&In_KTDLEN,In_KTDLST,&In_KTDEXL,In_KTDEXP,&In_KELEM,In_CNAMES);

  reconnect_6();
  return_val = file_to_stream(sec_name,aStream,1);
  delete_print_file(sec_name);
  return return_val;
}

//______________________________________________________________________
//====================================================================== MvBufrOut
//______________________________________________________________________

MvBufrOut::MvBufrOut( const long len, MvObsSet* aSet )  //( char *msg, long len, MvObsSet* aSet )
    : MvBufrBase( len ), _currentSec1( 0 )
{
  _outSet = aSet;
  _maxNrSubsets = 1;
  Out_KELEM = -1;        // MAX_KELEM / _maxNrSubsets;

  createFortranArrays();

  _outState = kBufrOut_noBuffers;
  resetBuffers();
}
//____________________________________________________________

MvBufrOut :: ~MvBufrOut( void )
{
  if(   _outState == kBufrOut_dataInBuffers )
  {
    encode();
  }
  _outSet->close();
  delete _currentSec1;
}

//____________________________________________________________________ createBuffers
void
MvBufrOut::createBuffers() // XXX still need more dynamic memory allocation
{
  Out_KTDEXL = -1;
  Out_KELEM = -1;
  _KDLEN = 0;
  _nextValue = 0;
  _nextCharParamPos = 0;

  if( _outState == kBufrOut_noBuffers )
    {
      char cbuf[ 120 ];

      try
      {
        cout << "MvBufrOut::createBuffers, checking for memory..." << endl;

        sprintf( cbuf, "requesting %d new fortints", MAX_KELEM );
        cout << cbuf << endl;
        Out_KTDLST = new fortint[ MAX_KELEM ];

        sprintf( cbuf, "requesting %d new fortints", MAX_KELEM );
        cout << cbuf << endl;
        Out_KTDEXP = new fortint[ MAX_KELEM ];

        sprintf( cbuf, "requesting %d new fortfloats", MAX_KVALS );
        cout << cbuf << endl;
        Out_VALUES = new fortfloat[ MAX_KVALS ];

        sprintf( cbuf, "requesting %d new chars", 80*MAX_KVALS );
        cout << cbuf << endl;
        Out_CVALS = new char[ MAX_KVALS * 80 ];
      }
      catch(...)
      {
        delete [] Out_VALUES; //-- (I)
        delete [] Out_CVALS;  //-- (II)
        delete [] Out_KTDEXP; //-- (III)

        Out_VALUES = 0;
        Out_CVALS  = 0;
        Out_KTDEXP = 0;
        Out_KTDLST = 0;

        _outState = kBufrOut_error;

        cout << ">>>\n>>> MvBufrOut::createBuffers failed in " << cbuf << "\n>>>" << endl;
        cout << "MvBufrOut::createBuffers: throw MvException..." << endl;
#ifdef METVIEW
        marslog( LOG_EROR, "MvBufrOut::createBuffers failed in %s", cbuf );
        throw MvException( "MvBufrOut::createBuffers: out-of-memory!" );
#else
          throw std::bad_alloc();
#endif
      }
    }

  cout << "MvBufrOut::createBuffers memory ok" << endl;

  _outState = kBufrOut_emptyBuffers;
}
//____________________________________________________________________ resetBuffers
void
MvBufrOut :: resetBuffers( void )
{
  Out_KTDEXL = -1;
  Out_KELEM = -1;
  _KDLEN = 0;
  _nextValue = 0;
  _nextCharParamPos = 0;

  if( _outState > kBufrOut_emptyBuffers )
    {
      _outState = kBufrOut_emptyBuffers;
    }
}
//____________________________________________________________________ write
void
MvBufrOut :: write( MvObs& anObs )
{
    //-- if no packing into subsets, copy message as is...
    _outSet->write( anObs._bufrIn->fMessage, (int)anObs._bufrIn->fMessageLength );
}

//____________________________________________________________________ add
void
MvBufrOut :: add( MvObs& anObs )
{
  if( _maxNrSubsets == 1 && anObs._bufrIn->subsetCount() == 1 )
    //-- if no packing into subsets, copy message as is...
    write( anObs );
  else
    addIntoBuffers( anObs );
}

//____________________________________________________________________ addIntoBuffers
void
MvBufrOut::addIntoBuffers( MvObs& anObs )
{
  if( _outState <= kBufrOut_noBuffers )
    {
      createBuffers();
    }

  checkDescriptors( anObs );

  if( MAX_KVALS < _nextValue + Out_KTDEXL )
  {
    encode();
    formatBuffers( anObs );
  }

  int elemIndex = _nextValue;
  for( int i = 0; i < Out_KTDEXL; i++, elemIndex++ )
  {
    Out_VALUES[ elemIndex ] = In_VALUES[ anObs.subsetOffset() + i ];

    //-- While checking for character data or delayed replicators, we expect
    //-- that the expanded descriptor sequences are the same for all subsets.
    //-- This is not necessarily true for non-compressed multisubset messages,
    //-- but...                                               (vk/1999-05-26)

    //-- character data..?
    if( fKSUP[ 7-1 ] > 0  && strncmp( In_CUNITS + i*24, "CCITTIA5", 8 ) == 0 )
    {
      //-- copy character string value to next available slot --
      int charInd = (int)Out_VALUES[ elemIndex ] / 1000 - 1;
      int charLen = (int)Out_VALUES[ elemIndex ] % 1000;
      strncpy( (Out_CVALS + _nextCharParamPos*80)
           , (In_CVALS + charInd*80)
           , charLen );

      //-- set "pointer" to this slot --
      Out_VALUES[ elemIndex ] = 1000*( _nextCharParamPos + 1 ) + charLen;
      _nextCharParamPos++;
    }
    else  //-- if delayed replication factor...
    {
      if( isDelayedDescriptor( Out_KTDEXP[ i ] ) )
      {
      if( _KDLEN < MAX_KDLEN )
      {
        _KDATA[ _KDLEN ] = (fortint)Out_VALUES[ elemIndex ];
        _KDLEN++;
      }
      else
        {
          cerr << ">>> MvBufrOut::add: array _KDATA overflow!!!" << endl;
#ifdef METVIEW
          marslog( LOG_EROR, "MvBufrOut::add: array _KDATA overflow!" );
#endif
        }
      }
    }
  }
  _nextValue += (int)Out_KELEM;

  fKSEC3[ 2 ] += 1;  //-- Nr of Subsets
  _outState = kBufrOut_dataInBuffers;

  if( shouldBeWritten() )
    encode();
}
//____________________________________________________________________ formatBuffers
void
MvBufrOut :: formatBuffers( const MvObs& anObs )
{
  delete _currentSec1;
#if 0
  _currentSec1 = new TSection1;
  *_currentSec1 = *(anObs._bufrIn->Sec1);
#endif
  if( anObs._bufrIn->fSec0->editionNr > 3 )
    _currentSec1 = new Section1_Ed4( anObs._bufrIn->Sec1 );
  else
    _currentSec1 = new Section1_preEd4( anObs._bufrIn->Sec1 );

  int i;

  fKSEC0[ 0 ] = 0;
  for( i=1; i<3; i++)
    fKSEC0[ i ] = anObs._bufrIn->fKSEC0[ i ];

  // fKSEC1[ 0 ] = 0; // ??????????
  for( i=0; i<40; i++)
    fKSEC1[ i ] = anObs._bufrIn->fKSEC1[ i ];

  int wmoi = BUFR_ORIGINATING_CENTER;
  if( getenv( "WMO_SITE_NR" ) )
    wmoi = atoi( getenv( "WMO_SITE_NR" ) );  //-- change WMO Centre Number if given

  if( wmoi < 0 || wmoi > 255 )
    wmoi = BUFR_ORIGINATING_CENTER;          //-- fall back to hard coded default

  fKSEC1[ 2 ] = wmoi;                        //-- WMO Originating Centre

  fKSEC1[ 3 ] += 1;                          // increment Update Sequence Number!!
  if( fKSEC1[ 4 ] > 127 )
    fKSEC1[ 4 ] -= 128;                      // remove section 2 (which one to copy?)

  fKSEC3[ 0 ] = 0;
  for( i=1; i<4; i++)
    fKSEC3[ i ] = anObs._bufrIn->fKSEC3[ i ];
  fKSEC3[ 2 ] = 0;                           // reset nr of Subsets

  fKSEC4[ 0 ] = 0;
  for( i=1; i<2; i++)
    fKSEC4[ i ] = anObs._bufrIn->fKSEC4[ i ];

  Out_KTDLEN = In_KTDLEN;             // nr of original data descriptors in Sec 3
  for( i=0; i<In_KTDLEN; i++ )        // packed descriptors
    Out_KTDLST[ i ] = In_KTDLST[ i ];

  Out_KTDEXL = In_KTDEXL;             // expected nr of data values / exp. descriptors
  for( i=0; i<In_KTDEXL; i++ )        // expanded descriptors
    Out_KTDEXP[ i ] = In_KTDEXP[ i ];

  Out_KELEM = In_KTDEXL;  // In_KELEM;// expected nr of expanded elements (????)
  _outState = kBufrOut_formatedBuffers;
}
//____________________________________________________________________ encode
void
MvBufrOut :: encode( void )
{
  if( _outState == kBufrOut_dataInBuffers )
  {
    fortint myKERR = 0;
    fortint myKBUFL = 0;

    BUFREN( fKSEC0, fKSEC1, fKSEC2, fKSEC3, fKSEC4
        , &Out_KTDLEN   // &fKTDEXL
        , Out_KTDLST    // fKTDEXP   // &fKTDLEN, fKTDLST
        , &_KDLEN
        , _KDATA
        , &Out_KELEM
        , &Out_KTDEXL   // was: fKVALS
        , Out_VALUES
        , Out_CVALS
        , &myKBUFL
        , (fortint *)fMessage
        , &myKERR );

    if( myKERR == 0 )
      _outSet->write( fMessage, (int)(myKBUFL*sizeof(fortint)) );
    else
      {
      cerr << ">>> MvBufrOut::encode, KERR=" << myKERR << endl;
#ifdef METVIEW
      marslog( LOG_EROR, "BUFR encoding (BUFREN) failed, status = %d", myKERR );
#endif
      }

    resetBuffers();
  }
}
//_______________________________________________________________ checkDescriptors
// checks descriptors and also header consistency i.e.
// to make sure that the new obs fits into the current
// multisubset message
//---------------------------------------------------------------
void
MvBufrOut :: checkDescriptors( const MvObs& anObs )
{
  if( anObs._bufrIn->_inState != kBufrIn_DataAndDescriptorsDecoded )
     anObs._bufrIn->ExpandDescriptors();

  if( _outState == kBufrOut_emptyBuffers )
    formatBuffers( anObs );
  else
    if( differentDescriptors() || differentHeader( anObs ) )
    {
       encode();
       formatBuffers( anObs );
    }
}

//_______________________________________________________________ differentDescriptors
// returns 1 if descriptors of the BUFR message in 'anObs' differs
// from current descriptors.
// returns 0 if they are equal
//---------------------------------------------------------------
int
MvBufrOut :: differentDescriptors( void ) const
{
  if( _outState < kBufrOut_formatedBuffers )
    return 1;

  if( In_KTDLEN != Out_KTDLEN )
    return 1;

  for( int i = 0; i < In_KTDLEN; i++ )
    if( In_KTDLST[ i ] != Out_KTDLST[ i ] )
      return 1;

  return 0;
}
//_______________________________________________________________ differentHeader
// returns 1 if section 1 header of the BUFR message in 'anObs'
// differs from current header 1.
// returns 0 if they are equal
//---------------------------------------------------------------
int
MvBufrOut :: differentHeader( const MvObs& anObs ) const
{
#if 0
  int seclen = 17;  // = unsignedInt( &(_currentSec1->len), 3 );  //syntax error???

  unsigned char* v1 = &(_currentSec1->len);         //-- start of current section 1
  unsigned char* v2 = &(anObs._bufrIn->fSec1->len); //-- start of sec 1 in other header

  for( int i=seclen; i>0; --i )
  {
     if( *v1 != *v2 )
        return 1;

     ++v1;  ++v2;
  }

  return 0;
#endif

  return _currentSec1->isDifferent( anObs._bufrIn->Sec1 );
}
//______________________________________________________________ shouldBeWritten
int
MvBufrOut :: shouldBeWritten( void )
{
  if( _outState != kBufrOut_dataInBuffers )
    return 0;

  return fKSEC3[ 2 ] >= _maxNrSubsets;  // Nr of Subsets
}
//______________________________________________________________ setSubsetCount
void
MvBufrOut :: setSubsetCount( int maxNrSubsets )
{
  if( _outState == kBufrOut_dataInBuffers )
    encode();
  _maxNrSubsets = maxNrSubsets;
}
//______________________________________________________________ isDelayedDescriptor
boolean
MvBufrOut :: isDelayedDescriptor( const long aDescr ) const
{
  if( aDescr == 31001 || aDescr == 31002 || aDescr == 31011 || aDescr == 31012 )
    return true;
  else
    return false;
}
//______________________________________________________________________
//====================================================================== MvObs
//______________________________________________________________________

01605 MvObs :: MvObs( MvBufr *b, int i )
{
   _subsetNr = i;
   _copy( b );
}

01611 MvObs :: MvObs( const MvObs&  b )
{
   _copy( b );
}
//___________________________________________________________________
MvObs :: ~MvObs()
{
   _clean();
}
//___________________________________________________________________ _copy
void
MvObs :: _copy( MvBufr *b )
{
   _bufrIn = b;
   _bufr_id = 0;
   if( _bufrIn )
   {
     _bufrIn->attach();
     _bufr_id = _bufrIn->currentBufrRef();
   }
   _currentLevelCoordinate = cPressureCoordinate;
   _currentLevelIndex = -1;
   _confidence = new MvBufrConfidence( _bufrIn, _subsetNr );
}
//___________________________________________________________________ _copy
void
MvObs :: _copy( const MvObs& b )
{
  _subsetNr = b._subsetNr;
  _copy( b._bufrIn );

}
//___________________________________________________________________ _clean
void
MvObs :: _clean()
{
   if( _bufrIn )
     _bufrIn->detach();
   _bufrIn = NULL;
   _bufr_id = 0;
   delete _confidence;
   _confidence = 0;
}
//___________________________________________________________________ operator=

MvObs&
01657 MvObs :: operator= ( const MvObs& b )
{
   _clean();
   _copy( b );
   return *this;
}
//___________________________________________________________________ operator void*

01665 MvObs :: operator void* ()
{
   return _bufrIn;
}
//___________________________________________________________________ operator!
bool
01671 MvObs :: operator! ()
{
   return !_bufrIn;
}
//___________________________________________________________________ msg_ok
//
bool
01678 MvObs :: msg_ok() const
{
  if( _bufr_id != _bufrIn->currentBufrRef() )
  {
    //-- restriction due to static bufr arrays --
    cerr << ">>> [MvObs::msg_ok] Static bufr arrays rewritten, not valid any more!" << endl;
    return false;
  }
  return ( _bufrIn && ( _bufrIn->_inState != kBufrIn_Error ) ) ? true : false;
}
//___________________________________________________________________ Advance
bool
01690 MvObs :: Advance()
{
   if( _bufrIn->subsetCount() > 1000 ||
       _bufrIn->subsetCount() < 1 ) // DEBUG TEST ONLY
   {
      cerr << " >>> MvObs::Advance, unbelievable nr of fsubsets ("
         << _bufrIn->subsetCount() << ") in msg "
       << _bufrIn->fMessageNumber << endl;
   }
   _subsetNr++;
   return  _subsetNr <= _bufrIn->subsetCount();
}

//_________________________________________________________________ messageType
int
01705 MvObs :: messageType()
{
   if( ! msg_ok() )
      return -1;

   return _bufrIn->Sec1->msgType();
}
//______________________________________________________________ messageSubtype
int
01714 MvObs :: messageSubtype()
{
   if( ! msg_ok() )
      return -1;

   return _bufrIn->Sec1->msgSubtype();
}
//___________________________________________________________ originatingCentre
int
01723 MvObs::originatingCentre()
{
   if( ! msg_ok() )
      return -1;

   return _bufrIn->Sec1->origCentre2();
}
//___________________________________________________________ editionNumber
int
01732 MvObs::editionNumber()
{
   if( ! msg_ok() )
      return -1;

   return _bufrIn->fSec0->editionNr;
}
//___________________________________________________________ masterTable
int
MvObs::masterTable()
{
   if( ! msg_ok() )
      return -1;

   return _bufrIn->Sec1->masterTable();
}
//___________________________________________________________ masterTableVersion
int
MvObs::masterTableVersion()
{
   if( ! msg_ok() )
      return -1;

   return _bufrIn->Sec1->masterTableVersion();
}
//___________________________________________________________ localTableVersion
int
MvObs::localTableVersion()
{
   if( ! msg_ok() )
      return -1;

   return _bufrIn->Sec1->localTableVersion();
}

//____________________________________________________________________ operator[]
double
01769 MvObs::operator[] ( int index )  //-- index starts from 1: 1,2,...,n
{
  return (double)(_bufrIn->DataValue( index-1, _subsetNr ));
}
//____________________________________________________________________ value
// returns 'kBufrMissingValue' if not found!
//-------------------------------------------------
float
01777 MvObs :: value( long aDescriptor )
{
   if( ! msg_ok() )
      return kBufrMissingValue;

   fortfloat myValue;
   _bufrIn->Value( aDescriptor, _subsetNr, myValue );
   return myValue == kFortranBufrMissingValue ? kBufrMissingValue : myValue;
}
//___________________________________________________________________ nextValue
// returns 'kBufrMissingValue' if not found!
//-------------------------------------------------
float
01790 MvObs :: nextValue()
{
   if( ! msg_ok() )
      return kBufrMissingValue;

   fortfloat myValue;
   _bufrIn->Value( _bufrIn->_currentDescr, _subsetNr, myValue, _bufrIn->_currentDescrInd + 1 );
   return myValue == kFortranBufrMissingValue ? kBufrMissingValue : myValue;
}
//___________________________________________________________ valueByOccurrence
// returns 'kBufrMissingValue' if not found!
//-------------------------------------------------
float
01803 MvObs :: valueByOccurrence( int anOccurrenceIndex, long aDescriptor )
{
  fortfloat myValue = value( aDescriptor );
  for( int myInd = 1; myInd < anOccurrenceIndex; myInd++ )
    myValue = nextValue();
  return myValue == kFortranBufrMissingValue ? kBufrMissingValue : myValue;
}
//______________________________________________________________ hasConfidences
bool
01812 MvObs :: hasConfidences()
{
  return  _confidence->hasConfidences();
}
//__________________________________________________________________ confidence
int
01818 MvObs :: confidence()
{
  return _bufrIn->_currentDescrInd > -1 ?
         _confidence->confidenceByIndex( _bufrIn->_currentDescrInd ) : -1;
}
//____________________________________________________________________ intValue
// returns 'kFortranBufrMissingIntValue' if not found!
//----------------------------------------------------
long
01827 MvObs :: intValue( long aDescriptor )
{
  return msg_ok() ? _bufrIn->intValue( aDescriptor, _subsetNr ) : kFortranBufrMissingIntValue;
}
//____________________________________________________________________ elementValueType
EElementValueType
01833 MvObs :: elementValueType()
{
  return _bufrIn->elementValueType( _subsetNr );
}
//____________________________________________________________________ elementValueType
EElementValueType
01839 MvObs :: elementValueType( long aDescriptor )
{
  return _bufrIn->elementValueType( aDescriptor, _subsetNr );
}
//____________________________________________________________________ stringValue
string
01845 MvObs :: stringValue()
{
  if( ! msg_ok() )
    return MESSED_UP;
  else
    return _bufrIn->stringValue( _subsetNr );
}
//_________________________________________________________________ stringValue
string
01854 MvObs :: stringValue( long aDescriptor )
{
  if( ! msg_ok() )
    return MESSED_UP;
  else
    return _bufrIn->stringValue( aDescriptor, _subsetNr );
}
//______________________________________________________ numberOfPressureLevels
int
01863 MvObs :: numberOfPressureLevels()
{
  return numberOfLevels( cPressureCoordinate );
}
//______________________________________________________ numberOfLevels
int
01869 MvObs :: numberOfLevels( long levelDescriptor )
{
  int myCount = 0;

  if( firstLevel( levelDescriptor ) != kBufrMissingValue )
  {
    myCount++;
    while( nextLevel() != kBufrMissingValue )
      myCount++;
  }

  _currentLevelIndex = -1;
  return myCount;
}
//__________________________________________________________ firstPressureLevel
float
01885 MvObs :: firstPressureLevel()
{
  _currentLevelCoordinate = cPressureCoordinate;
  return pressureLevel( 0 );
}
//__________________________________________________________ firstLevel
float
01892 MvObs :: firstLevel( long levelDescriptor )
{
  _currentLevelCoordinate = levelDescriptor;
  return level( levelDescriptor, 0 );
}
//___________________________________________________________ nextPressureLevel
float
01899 MvObs :: nextPressureLevel()
{
  return pressureLevel( _currentLevelIndex + 1 );
}
//___________________________________________________________ nextLevel
float
01905 MvObs :: nextLevel()
{
  return level( _currentLevelCoordinate, _currentLevelIndex + 1 );
}
//______________________________________________________________ pressureLevel
float
MvObs :: pressureLevel( int firstIndexValue )
{
  float  myLevelValue = level( cPressureCoordinate, firstIndexValue );

  return myLevelValue == kBufrMissingValue ? kBufrMissingValue : myLevelValue / 100.;
}
//______________________________________________________________ level
float
MvObs :: level( long levelDescriptor, int firstIndexValue )
{
  if( ! msg_ok() )
     return kBufrMissingValue;

  fortfloat myLevelValue = kFortranBufrMissingValue;

  if( _bufrIn->Value( levelDescriptor, _subsetNr, myLevelValue, firstIndexValue ) )
    _currentLevelIndex = _bufrIn->_currentDescrInd;
  else
    _currentLevelIndex = -1;

  return myLevelValue == kFortranBufrMissingValue ? kBufrMissingValue : myLevelValue;
}

//______________________________________________________________ specifierIndex
int
MvObs :: specifierIndex( long  aSpecifierDescriptor
                   , float aSpecifierValue
                   , int   firstIndexValue )
{
   if( ! msg_ok() )
      return -1;

   if( _bufrIn->_inState != kBufrIn_DataAndDescriptorsDecoded )
      _bufrIn->ExpandDescriptors();

   if( _bufrIn->_inState == kBufrIn_DataAndDescriptorsDecoded )
   {
      //-- search for a specifier data with specified value --
      for( int index=firstIndexValue; index < In_KTDEXL; index++ )
       if( In_KTDEXP[ index ] == aSpecifierDescriptor
           && _bufrIn->DataValue( index, _subsetNr ) == aSpecifierValue )
       {
          _lastSpecifierIndex = index;
          return index;
       }
   }
   return -1;
}
//____________________________________________________________ valueBySpecifier
// A generic function to retrieve repeating data
// specified by some other data
// (e.g.  temperature at a certain pressure level)
//--------------------------------------------------------------------
float
MvObs :: valueBySpecifier( long  aSpecifierDescriptor
                   , float aSpecifierValue
                   , long  aDescriptor
                   , int   firstIndexValue )
{
   int index = specifierIndex( aSpecifierDescriptor, aSpecifierValue, firstIndexValue );
   if( index > 0 )
   {
     //-- search real data before next specifier data --
     for( int ind=index+1; ind < In_KTDEXL; ind++ )
     {
       if( In_KTDEXP[ ind ] == aDescriptor )
       {
         fortfloat myVal = _bufrIn->DataValue( ind, _subsetNr );
         return myVal == kFortranBufrMissingValue ? kBufrMissingValue : myVal;
       }

       //-- not found if specifier data again --
       if( In_KTDEXP[ ind ] == aSpecifierDescriptor )
         break;
     }
   }
   return kBufrMissingValue;   //-- Not Found or Troubled Msg --
}
//________________________________________________________ valueByPressureLevel
float
01991 MvObs :: valueByPressureLevel( float aLevelValue        // in 'hPa'
                       , long  aDescriptor )
{
   return valueBySpecifier( cPressureCoordinate, aLevelValue*100., aDescriptor );
}
//________________________________________________________ valueByLevel
float
01998 MvObs :: valueByLevel( long  aLevelDescriptor
                     , float aLevelValue
                 , long  aDescriptor )
{
   return valueBySpecifier( aLevelDescriptor, aLevelValue, aDescriptor );
}
//________________________________________________________________ valueByLayer
float
02006 MvObs :: valueByLayer( float firstLevel
                 , float secondLevel
                 , long aDescriptor )
{
  int firstLevelIndex = specifierIndex( cPressureCoordinate, firstLevel*100., 0 );
  int secondLevelIndex = -1;

  while( firstLevelIndex > 0 )          //-- loop candidates --
  {
    //-- try to find the second level next to the current first one --

    if( In_KTDEXP[ firstLevelIndex - 1 ] == cPressureCoordinate &&
        _bufrIn->DataValue( firstLevelIndex - 1, _subsetNr ) == secondLevel*100. )
    {
      secondLevelIndex = firstLevelIndex - 1;
      break;
    }
    else
      if( In_KTDEXP[ firstLevelIndex + 1 ] == cPressureCoordinate &&
          _bufrIn->DataValue( firstLevelIndex + 1, _subsetNr ) == secondLevel*100. )
      {
        secondLevelIndex = firstLevelIndex + 1;
        break;
      }

    //-- no match, let's find the next candidate --

    firstLevelIndex = specifierIndex( cPressureCoordinate
                            , firstLevel*100.
                            , firstLevelIndex + 1 );
  }

  if( firstLevelIndex < 0 )
    return kBufrMissingValue;  //-- levels were not found!!!

  //-- search real data before next specifier data --

  int maxim = firstLevelIndex > secondLevelIndex ? firstLevelIndex : secondLevelIndex;
  for( int ind = maxim + 1; ind < In_KTDEXL; ind++ )
  {
    if( In_KTDEXP[ ind ] == aDescriptor )
    {
      fortfloat myValue = _bufrIn->DataValue( ind, _subsetNr );
      return myValue == kFortranBufrMissingValue ? kBufrMissingValue : myValue;
    }


    //-- not found if specifier data again --

    if( In_KTDEXP[ ind ] == cPressureCoordinate )
      break;
  }
  return kBufrMissingValue;   //-- Not Found or Troubled Msg --
}


//______________________________________________________________ printAllValues
boolean
02064 MvObs :: printAllValues()
{
   ostream* myStream = &cout;
   return writeAllValues( *myStream );
}
//_______________________________________________________________ writeAllValues
boolean
02071 MvObs :: writeAllValues( ostream& aStream )
{
  if( ! msg_ok() )
    return false;

  if( _bufrIn->_inState != kBufrIn_DataAndDescriptorsDecoded )
    _bufrIn->ExpandDescriptors();

  if( _bufrIn->_inState == kBufrIn_DataAndDescriptorsDecoded )
    {
      long  myEndingIndex = _confidence->hasConfidences() ?
      _confidence->lastDataIndex()+1 : In_KTDEXL;
      writeValues(aStream,0, myEndingIndex);
      return true;
   }
   return false;
}

boolean
MvObs::writeValues(ostream& aStream, int firstIndex, int lastIndex)
{
   if( ! msg_ok() )
      return false;

   if( _bufrIn->_inState != kBufrIn_DataAndDescriptorsDecoded )
      _bufrIn->ExpandDescriptors();

   if( _bufrIn->_inState == kBufrIn_DataAndDescriptorsDecoded )
   {
      fortfloat myValue;
      if ( firstIndex < 0 )
      firstIndex = 0;
      if (lastIndex > In_KTDEXL )
      lastIndex = In_KTDEXL;

      for( int i = firstIndex; i < lastIndex; i++ )
      {
       aStream.width( 3 ); aStream.fill( ' ' );      // index
       aStream << i+1 << ".  ";

       myValue = _bufrIn->DataValue( i, _subsetNr ); // get parameter value
                                                     // = set current parameter!
       switch( elementValueType() )                    // print parameter value
       {
         case kEVT_unknown:
            aStream << " ?????";
            break;

         case kEVT_missing:
            aStream << "   ~~~";
            break;

         case kEVT_numeric:
            aStream.width( 6 ); aStream.fill( ' ' );
            aStream << myValue;
            break;

         case kEVT_string:
            aStream.width( 6 ); aStream.fill( ' ' );
            aStream << stringValue( In_KTDEXP[ i ] );
            break;
       }

       aStream << " " << name( In_KTDEXP[ i ] );           // parameter name
       aStream << " [" << unit( In_KTDEXP[ i ] ) << "] ("; // parameter unit
       aStream.width( 5 ); aStream.fill( '0' );            // parameter descriptor
       aStream << In_KTDEXP[ i ] << ")";
       aStream << endl;
      }
      return true;
   }
   return false;
}

//_______________________________________________________________ writeAllValues
boolean
02147 MvObs :: writeAllValues( const char* aPathName )
{
  ofstream myStream( aPathName, ios::out );
  if( ! myStream )
  {
    cerr << " >>> MvObs::writeAllValues(char*): error in creating file " << aPathName << endl;
#ifdef METVIEW
    marslog( LOG_EROR, "MvObs::writeAllValues: error in creating file %s", aPathName );
#endif
    return false;
  }

  return writeAllValues( myStream );
}
//_______________________________________________________________ writeBufrBox
boolean
02163 MvObs :: writeBufrBox( ostream& aStream )
{
   boolean return_value = true;

   boolean b_ret = _bufrIn->writeBufrBox( _subsetNr );
   if( ! b_ret )
   {
      aStream << "\n   >>> Problems encountered!!! <<<\n" << endl;
      return_value = false;
   }
   else
     {
       return_value = file_to_stream(BBOXNAME.c_str(),aStream,0);
       delete_print_file(BBOXNAME.c_str());
     }
   return return_value;
}
//______________________________________________________________ WmoIdentNumber
long
02182 MvObs :: WmoIdentNumber()
{
  return msg_ok() ? WmoBlockNumber()*1000 + WmoStationNumber() : kBufrMissingIntValue;
}
//______________________________________________________________ WmoBlockNumber
int
02188 MvObs :: WmoBlockNumber()
{
   fortfloat myValue;

   if( msg_ok() && _bufrIn->Value( 1001L, _subsetNr, myValue ) )
      return (long)myValue;
   else
      return 0;
}
//____________________________________________________________ WmoStationNumber
int
02199 MvObs :: WmoStationNumber()
{
   fortfloat myValue;

   if( msg_ok() && _bufrIn->Value( 1002L, _subsetNr, myValue ) )
      return (long)myValue;
   else
      return 0;
}
//____________________________________________________________ findSomeIdent
string
02210 MvObs::findSomeIdent()
{
  if( ! msg_ok() )
    return string( "???" );

                            //-- 5-digit WMO identifier available?
  if( WmoIdentNumber() > 0 )
    {
      ostringstream oss;
      oss << setw(5) << setfill('0') << WmoIdentNumber();
      return oss.str();
    }
                            //-- No WMO id found, thus look for other candidates,
                            //-- this is a list of known identifier candidates.
  const long idList[] =
    {
      1011L,    //-- Ship or mobile land station identifier
      1005L,    //-- Buoy/platform identifier
      1006L,    //-- Aircraft flight number
      1007L,    //-- Satellite identifier
      1008L,    //-- Aircraft registration number
      1010L,    //-- Stationary buoy platform identifier
      1025L,    //-- Storm identifier
      1026L,    //-- WMO storm name
      1027L     //-- WMO long storm name
    };

  int idVals = sizeof(idList)/sizeof(idList[0]);

  for( int i=0; i<idVals; ++i )
    {
      long descr = idList[i];
      fortfloat myValue = value( descr );

      if( myValue != kBufrMissingValue )
      {
        return stringValue( descr );
      }
    }

  return string( "id???" );
}
//____________________________________________________________________ location
MvLocation
02254 MvObs :: location()
{
   MvLocation myLocation( value( 5001L ), value( 6001L ) ); //-- "high accuracy"

   if( myLocation.latitude() == kBufrMissingValue ||
       myLocation.longitude() == kBufrMissingValue )
   {
      myLocation.set( value( 5002L ), value( 6002L ) );     //-- "coarse accuracy"
   }                                                        //-- hopefully not missing

   return myLocation;
}
//____________________________________________________________________ unit
string
02268 MvObs :: unit( long aDescriptor )
{
  return msg_ok() ? _bufrIn->unit( aDescriptor ) : MESSED_UP;
}
//____________________________________________________________________ unit
string
02274 MvObs :: unit()
{
  return msg_ok() ? _bufrIn->unit() : MESSED_UP;
}
//____________________________________________________________________ name
string
02280 MvObs :: name( long aDescriptor )
{
  return msg_ok() ? _bufrIn->name( aDescriptor ) : MESSED_UP;
}
//____________________________________________________________________ name
string
02286 MvObs :: name()
{
  return msg_ok() ? _bufrIn->name() : MESSED_UP;
}
//________________________________________________________________ subsetOffset
int
MvObs :: subsetOffset()
{
  return ( _subsetNr - 1 ) * In_KELEM;
}
//________________________________________________________________ writeConfidenceValues
bool
02298 MvObs::writeConfidenceValues(ostream& aStream)
{
  if( ! msg_ok() || ! _confidence->hasConfidences() )
    return false;

  if( _bufrIn->_inState != kBufrIn_DataAndDescriptorsDecoded )
    _bufrIn->ExpandDescriptors();

  if( _bufrIn->_inState == kBufrIn_DataAndDescriptorsDecoded )
    {
      long  myStartingIndex = _confidence->lastDataIndex()+1;
      long  myEndingIndex =  In_KTDEXL;
      writeValues(aStream,myStartingIndex, myEndingIndex);
      return true;
   }
   return false;
}

//=============================================================================
//                                                                 vk April -95
// Quick&Dirty hack to access Feed Back Quality Control Confidence info:
//  * works only for QC operator 222000
//  * uses Data Present Descriptors (031031) and Confidence Descriptors (033007)
//  * presumes following structure:
//     - 222000 descriptor exists (and is followed by:)
//     - 031031 descriptors are all in one group (only first one is used!)
//     - 033007 descriptors are all in one group (only first one is used!)
//     - Extended Delayed Descr Replication Factors (031002) are not checked!
//  * Data Present group is used to define index into Confidence group
//____________________________________________________________ MvBufrConfidence

MvBufrConfidence :: MvBufrConfidence( MvBufr* aBufr, int aSubsetNr )
{
  _bufr = aBufr;
  if( _bufr )
    _bufr->attach();
  _subsetNr = aSubsetNr;
  _state = kBCS_unknown;
  _startOfDataPresent = -2;
  _startOfConfidences = -2;
}
//___________________________________________________________ ~MvBufrConfidence

MvBufrConfidence :: ~MvBufrConfidence()
{
  if( _bufr )
    _bufr->detach();
}
//______________________________________________________________ hasConfidences
bool
MvBufrConfidence :: hasConfidences()
{
  if( ! _bufr )
    return false;

  if( _state == kBCS_unknown )
    _state = _bufr->descriptorToFortranIndex( 222000L ) > 0 ? kBCS_exists : kBCS_missing;

  return _state == kBCS_exists ? true : false;
}
//_______________________________________________________________ confidence
int
MvBufrConfidence :: confidence( long aDescr )
{
  int myDataIndex = _bufr->descriptorToFortranIndex( aDescr );
  return myDataIndex > -1 ? confidenceByIndex( myDataIndex ) : -1;
}
//___________________________________________________________ confidenceByIndex
int
MvBufrConfidence :: confidenceByIndex( int aDataInd )
{
  int myConfidenceInd = -1;

  if( hasConfidences() )
  {
     //--    case a:        case b:
     //--        . . .          . . .
     //--       0xxyyy         0xxyyy    <- 0xxyyy: element descriptors
     //--       0xxyyy         222000
     //--       222000         03100x
     //--       031031         031031    <- startOfDataPresent()
     //--       031031         031031
     //--        . . .          . . .
     //--
     if( aDataInd < ( startOfDataPresent() - 1 ) &&  //-- skip 222000
         _bufr->CurrentDescriptor() != 222000L )     //-- if previous was 03100*
     {
        if( _bufr->DataValue( aDataInd, _subsetNr ) != kFortranBufrMissingValue )
           myConfidenceInd = startOfConfidences() + delta( aDataInd );
     }
  }

  return myConfidenceInd > -1 ?
            (int)(_bufr->PeekDataValue( myConfidenceInd, _subsetNr )) : -1;
}
//_______________________________________________________________ lastDataIndex
int
MvBufrConfidence :: lastDataIndex()
{
  return hasConfidences() ? _bufr->descriptorToFortranIndex( 222000L ) - 1 : -1;
}
//__________________________________________________________ startOfDataPresent
// Q&D hack !!!

int
MvBufrConfidence :: startOfDataPresent()
{
  if( _startOfDataPresent == -2 )
  {
    if( hasConfidences() )
    {
      _startOfDataPresent = _bufr->descriptorToFortranIndex( 31031L );
      if( _startOfDataPresent < 1 )
      {
      cerr << "[MvBufrConfidence::startOfDataPresent] Q&D hack does not work!!" << endl;
      _state = kBCS_missing;
      }
    }
  }

  return hasConfidences() ? _startOfDataPresent : -1;
}
//_______________________________________________________________ startOfConfidences
// Q&D hack !!!

int
MvBufrConfidence :: startOfConfidences()
{
  if( _startOfConfidences == -2 )
  {
    if( hasConfidences() )
    {
      _startOfConfidences = _bufr->descriptorToFortranIndex( 33007L );
      if( _startOfConfidences < 1 )
      {
      cerr << "[MvBufrConfidence::startOfConfidences] Q&D hack does not work!!" << endl;
      _state = kBCS_missing;
      }
    }
  }

  return hasConfidences() ? _startOfConfidences : -1;
}
//_______________________________________________________________ delta
int
MvBufrConfidence :: delta( int anInd )
{
  if( hasConfidences() )
  {
    int myDelta = 0;

    for( int i = 0; i < anInd; i++ )
      if( _bufr->PeekDataValue( startOfDataPresent()+i, _subsetNr ) == 0 )
      myDelta++;

    return myDelta;
  }
  else
    return -1;
}

//________________________________________________________________________
//======================================================================== MvBufrParam
//________________________________________________________________________

MvBufrParam :: MvBufrParam( const char *aParamName )
{
   descriptorStruct *par = knownParams;
   while( par->descriptor != 0 )
   {
      if( strcmp( aParamName, par->name ) == 0 )
      {
         fDescriptor = par->descriptor;
       return;
      }
      ++par;
   }
   cerr << " >>> MvBufrParam::MvBufrParam: param not defined: " << aParamName << endl;
   fDescriptor = 0;
}
//_____________________________________________________________ PrintAllKnownParameters

void
MvBufrParam :: PrintAllKnownParameters() const
{
   descriptorStruct *par = knownParams;
   cout << " The Known Parameters of class MvBufrParam and the corresponding Descriptors:\n";
   while( par->descriptor != 0 )
   {
      cout << "\n";
      cout.width( 16 );
      cout.fill( ' ' );
      cout << par->name << " = ";
      cout.width( 6 );
      cout.fill( '0' );
      cout << par->descriptor;
      ++par;
   }
   cout << endl;
}

//-------------------- Helper functions to redirect stdout ----------------
// This function will duplicate the file descriptor for stdout, and keep
// it for later. Then stdout is connected to the file given as arg.
// The first time the function is run, it tries to find a temporary dir.
// to use ( class could be used outside metview ).

boolean redirect_6(const char *fname)
{
  cout << " redirect_6: redirect stdout into file " << fname << endl;
  char *tmp_dir;
  // Set the output dir. if it's not set.
  if ( redirect_dir == string("") )
    {
      tmp_dir = getenv("METVIEW_TMPDIR");
      if ( !tmp_dir )
      {
        tmp_dir = getenv("TMPDIR");
        if ( !tmp_dir )
          redirect_dir = "/usr/tmp";
        else
          redirect_dir = tmp_dir;
      }
      else
      redirect_dir = tmp_dir;
    }

  // Flush stdout before redirecting, to get rid of any pending output.
  fflush(stdout);

  new_fd = dup(STDOUT_FILENO);
  close(STDOUT_FILENO);

  string tmp_name;
  tmp_name = redirect_dir + "/" + fname;
  // As 1 is just closed, it will be the fd used.
  // Will fail if stdin is explicitly closed and no fopens are done
  if ( ! (fopen(tmp_name.c_str(),"w")) )
    {
          cerr << "Problems opening file " << (const char*)tmp_name.c_str() << " for writing" << endl;
      return false;
    }

  else
    return true;
}

//
// Will reconnect stdout by using a file descriptor saved from earlier.
//
boolean reconnect_6()
{
  // Make sure we get everything before closing.
  fflush(NULL);
  close(STDOUT_FILENO);

  int ret = dup2( new_fd, STDOUT_FILENO );
  if( ret < 0 )
    {
      cerr << " reconnect_6: reconnecting into stdout FAILED!" << endl;
      cout << " reconnect_6: reconnecting into stdout FAILED!" << endl;
      return false;
    }
  cout << " reconnect_6: reconnected into stdout!" << endl;
  return ret > 0 ;
}

//
// Read a file and write the contents to given stream
//
boolean file_to_stream(const char *fname,ostream &aStream,int skip)
{
  const int MAX_LINE_LEN = 512;
  char      supposedToBeANewLine;
  string    myTmpFileName;

  myTmpFileName = redirect_dir + "/" + fname;

  ifstream myTmpFile( myTmpFileName.c_str() );

  if ( ! myTmpFile )
    {
          aStream << "Can not read file " << (const char*)myTmpFileName.c_str() << endl;
      return false;
    }

  char     myLine[ MAX_LINE_LEN ];

  myTmpFile.get( myLine, MAX_LINE_LEN, '\n' );
  myTmpFile.get( supposedToBeANewLine );
  int i = 0;
  while( myTmpFile && !myTmpFile.eof() )
    {
      if ( i++ >= skip )
      aStream << myLine << endl;

      myTmpFile.get( myLine, MAX_LINE_LEN, '\n' );
      myTmpFile.get( supposedToBeANewLine );
    }

  myTmpFile.close();

  return true;
}

void delete_print_file(const char *name)
{
  string fname = redirect_dir + "/" + name;
  unlink(fname.c_str());
}

Generated by  Doxygen 1.6.0   Back to index