/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

// CleanFile.cc, vk Dec-98
//
// Remove rubbish octets before the first GRIB or BUFR message
// (normally cursed by Fortran binary I/O) i.e. clean the file
// for Metview to recognise the correct file type.
//
// March 2002: added parameter SKIP_HIRLAM_CUSTOM_RECORD to be
// able to remove the custom Hirlam GRIB msg (1st msg),
// and removed MAX_RUBBISH_OCTETS parameter (now dynamic).
//

#include <inc_iostream.h>
#include "Metview.h"

//__________________________________________________________ CleanFile

class CleanFile : public MvService
{
 private:
    CleanFile( const CleanFile& anOther );
    void operator= ( const CleanFile& anOther );

 public:
    CleanFile( void );
    ~CleanFile( void );
 
    void  serve( MvRequest&, MvRequest& );

 private:
    bool  findNextMsg( ifstream& ifs, int& skipped, char& msgType );
};


//_________________________________________________________

CleanFile::CleanFile( void ) : MvService( "CLEANFILE" )
{ 
}
//_________________________________________________________

CleanFile::~CleanFile( void )
{
}
//_________________________________________________________

void 
CleanFile :: serve( MvRequest& in, MvRequest& out )
{
	cout << "\n--> entering CleanFile::serve..." << endl;
	in.print();

	const char *data = in( "DATA" );
	const char *path = in( "PATH" );

	if( data && path )                    //-- do not allow two data sources
	{
		setError( 13, "Only one input allowed: both Path and Data have values!" );
		return;
	}
	if( ( ! data ) && ( ! path ) )        //-- one data source required
	{
		setError( 13, "No input file: both Path and Data are empty!" );
		return;
	}

	if( data )
	{
		MvRequest icon;
		in.getValue(icon,"DATA");
		path = icon("PATH");
	}

                                               //-- open file
	ifstream myStream( path, ios::in );
	if( ! myStream )
	{
		setError( 13, "Cannot open file '%s'!", path );
		return;
	}

                                               //-- search for real data start
	char myMsgType   = '?';
	int  mySkipCount = 0;

	bool found = findNextMsg( myStream, mySkipCount, myMsgType );

                                               //-- did we find real data?
	if( ! found )
	  {
	    setError( 13, "No messages found in %s, searched %d octets!"
		    , path, mySkipCount );
	    return;
	  }

        sendProgress( "Removed %d bytes before the first %s msg"
                    , mySkipCount, (myMsgType == 'G' ? "GRIB" : "BUFR") );

                                               //-- skip 1st record too?

	const char* skipFirstMsg = in( "SKIP_HIRLAM_CUSTOM_RECORD" );

	if( skipFirstMsg && strcmp( skipFirstMsg, "YES" ) == 0 )
	  {

	    int mySkipCount2 = 0;
	    found = findNextMsg( myStream, mySkipCount2, myMsgType );

                                               //-- still data after 1st msg?
	    if( ! found )
	      {
		setError( 13, "'Custom Record' removed, but no more msgs found!" );
		return;
	      }

	    mySkipCount2 += 4; //-- +4: 1st "GRIB"/"BUFR" was already past

	    sendProgress( "Removed 'Custom Record' (first msg, %d octets more)"
			, mySkipCount2 );

	    mySkipCount += mySkipCount2;
	  }

                                               //-- create output file
	char* myFileOut = marstmp();
	ofstream myStreamOut( myFileOut, ios::out );

                                               //-- skip rubbish
	myStream.seekg( 0 ); // rewind
	int myCount = mySkipCount;
	while( myCount-- > 0 )
	{
		myStream.get();
	}
                                               //-- create a clean file
	myCount     = 0;
	int myOctet = myStream.get();
	while( ! myStream.eof() )
	  {
	    ++myCount;
	    myStreamOut.put( myOctet );
	    myOctet = myStream.get();
	  }
                                               //-- create return request
	MvRequest myOutReq( (myMsgType == 'G' ? "GRIB" : "BUFR") );
	myOutReq( "TEMPORARY" ) = 1;
	myOutReq( "PATH" ) = myFileOut;
	out = myOutReq;

        sendProgress( "Created %d clean octets", myCount );
}
//_________________________________________________________

bool
CleanFile::findNextMsg( ifstream& ifs, int& skipCount, char& msgType )
{ 
  const int BUFR[5] = { 'B','U','F','R', '+' };
  const int GRIB[5] = { 'G','R','I','B', '+' };

  int iB = 0;                      //-- indices to BUFR[5] and GRIB[5]
  int iG = 0;

  int myOctet = ifs.get();
  while( ! ifs.eof() )
    {
      ++skipCount;

      if( myOctet == BUFR[iB] )
	++iB;                      //-- advance in finding "BUFR"
      else
	iB = 0;                    //-- revert back to the 1st char

      if( myOctet == GRIB[iG] )
	++iG;                      //-- advance in finding "GRIB"
      else
	iG = 0;                    //-- revert back to the 1st char

      if( iB == 4 )
	{
	  msgType = 'B';           //-- we have found "BUFR"
	  skipCount -= 4;
	  return true;
	}
      else if( iG == 4 )
	{
	  msgType = 'G';           //-- we have found "GRIB"
	  skipCount -= 4;
	  return true;
	}

      myOctet = ifs.get();         //-- not yet => get next char
    }

  return false;
}
//_________________________________________________________

int 
main( int argc, char **argv )
{
  MvApplication  myApp( argc, argv );
  CleanFile      myProfessional;

  myApp.run();
}
