/***************************** 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 *************************************/

// grib_to_geo.cc,  020722/vk
//
//   Dumps all grid point values into a geopoints file.
//
//   User can select either the minimum XYV format
//   (lon-lat-value, the default) or the traditional
//   full format (lat-lon-height-date-time-value).
//

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

//_________________________________________________________________

class GribToGeo : public MvService {
public:
	GribToGeo() : MvService("GRIB_TO_GEO") {};
	void serve(MvRequest&,MvRequest&);
};
//_________________________________________________________________

void GribToGeo::serve( MvRequest& in, MvRequest& out )
{
  const char cTAB = '\t';

  in.print();

  MvRequest grb;                           //-- data request => fieldset
  in.getValue( grb, "DATA" );

  fieldset* fs = request_to_fieldset( (request*)grb );
  field*    f  = get_field(fs,0,expand_mem);
  //gribsec1* s1 = (gribsec1*)&f->ksec1[0];

  MvField field(f); // create MvField object
  MvGridBase *grd = field.mvGrid();  // be careful with this pointer because MvField is in charge!

  if( ! grd->hasIterator() )           //-- check that it is ok
    {
      setError( 13, "Unimplemented or spectral data - unable to extract location data" );
      return;
    }



  if( fs->count > 1 )                      //-- warning if several fields
    {
      marslog( LOG_INFO, "Info: only first field will be converted" );
    }


  //double height = grd->getDouble("heightPressureEtcOfLevels");//aki always // s1->top_level;
  double height = field.level();
  MvDate vDate(field.yyyymmddFoh());


  //long timePeriod = grd->getLong("periodOfTimeIntervals");//aki grib2//
  long step = field.stepFoh();
  if( step != LONG_MAX && step != 0 ) // s1->p1 > 0 )
  {
      vDate += step;
  }
  long  dat = vDate.YyyyMmDd();
  long  tim = 100*vDate.Hour() + vDate.Minute();
  //cout << height << cTAB << dat << cTAB << tim << cTAB << step << endl;



  bool formatXYV = true;                   //-- which geopoints file format ?
  const char* fmt = in( "GEOPOINTS_FORMAT" );
  if( fmt && strcmp( fmt, "TRADITIONAL" ) == 0 )
    {
      formatXYV = false;
    }


  string tmp = marstmp();                  //-- open output file
  ofstream fout( tmp.c_str() );

  //long paramNumber   = grd->getLong("indicatorOfParameter");//aki grib2//
  //long table2Version = grd->getLong("gribTablesVersionNo");//aki grib2//
  string paramNumber = grd->getString("mars.param");

  fout << "#GEO\n"                         //-- write geopoints header, with a comment
       << "#  extracted from GRIB data, on " << MvDate().YyyyMmDd() << ", by grib_to_geo\n"
       << "#  original parameter " << paramNumber
//           << ", in GRIB Table 2 Version " << table2Version
       << endl;

  if( formatXYV )                          //-- add more comment lines
    {
      fout << "#FORMAT XYV\n"              //-- geopoints file format is "XYV"
	   << "#  warning: XYV is not suitable for some macro computations!\n"
	   << "#  X=lon Y=lat\tV=val" << endl;
    }
  else
    {
      fout << "# lat\tlon\theight\tdate\ttime\tvalue" << endl;
    }

  fout << "#DATA" << endl;                 //-- start-of-data line



  MvGridPoint gp;                          //-- extract all grid points
  int cnt = 0;

  do
    {
      gp = grd->gridPoint();
      ++cnt;

      if( formatXYV )                      //-- XYV format
	{
	  fout << gp.loc_.longitude() << cTAB
	       << gp.loc_.latitude()  << cTAB;
	}
      else                                 //-- traditional format
	{
	  fout << gp.loc_.latitude()  << cTAB
	       << gp.loc_.longitude() << cTAB
	       << height << cTAB
	       << dat    << cTAB
	       << tim    << cTAB;
	}

      if ( gp.value_ != grd->missingValue() )
	fout << gp.value_ << endl;
      else
	fout << GEOPOINTS_MISSING_VALUE << endl;

    }
  while( grd->advance() );

  cout << cnt << " points!" << endl;



  MvRequest gpts    = "GEOPOINTS";          //-- return reply request
  gpts("PATH")      = tmp.c_str();
  gpts("TEMPORARY") = 1;

  out = gpts;
}
//_________________________________________________________________

int main( int argc, char** argv )
{
    MvApplication theApp( argc, argv );
    GribToGeo tool;
    theApp.run();
}
