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

#include "ReprojectService.h"

#include <GeoRectangularProjection.h>
#include <LegendVisitor.h>
//#include <ImagePlotting.h>
#include <GribSatelliteInterpretor.h>
#include <PaperPoint.h>

ReprojectService::ReprojectService(string in,string out,double rx,double ry,double x1,double x2,double y1,double y2):
	gribIn_(in),
	gribOut_(out),
	resX_(rx),
	resY_(ry),
	x1_(x1),
	x2_(x2),
	y1_(y1),
	y2_(y2)
{
     //empty
}

bool
ReprojectService::execute()
{
     magics::GribDecoder grib;

//     magics::ParameterManager::set("subpage_lower_left_latitude",y1_);
//     magics::ParameterManager::set("subpage_upper_right_latitude",y2_);
//     magics::ParameterManager::set("subpage_lower_left_longitude",x1_);
//     magics::ParameterManager::set("subpage_upper_right_longitude",x2_);
//     magics::GeoRectangularProjection projection; // fixed for now!
       
//     magics::ImagePlotting tool;
     grib.file_name_ = gribIn_;
     grib.open(NULL);  // it's not clear what purpose the NULL has here - it should be a grib handle, but it seems to be unused
     magics::GribSatelliteInterpretor gribInterpreter;
//     magics::GeoRectangularProjection transformation;
//     magics::RasterData rdin;  //input data
//     gribInterpreter.interpretAsRaster(grib, rdin, transformation);
//     RasterData<GeoPoint>& rdin = grib.raster();  //input data
//     RasterData  rdout;                 //output data

//     if ( !tool.reproject(rdin,rdout, projection, resX_, resY_) )
//     {
//	      MagLog::dev() << "ERROR: ImagePlotting<P>::createOutputRaster:" << tool << "\n";
//	      return false;
//     }


    magics::Matrix *matrix = 0;
    gribInterpreter.interpretAsMatrix(grib, &matrix);
    if (!matrix)
    {
        MagLog::dev() << "ERROR: interpretAsMatrix failed on file " << gribIn_ << "\n";
        return false;
    }

     if ( !gribit(*matrix, grib) ) {
            cout << "Grib OK!\n";
	    return true;
     }
     else {
            cout << "request failed!\n";
	    return false;
     }
}

int
ReprojectService::gribit(magics::Matrix& matrix, magics::GribDecoder& sourceGrib)
{
    // copy from examples of the grib_api!
    int ret=0;
    double* values;
    long numberOfPointsAlongAParallel,numberOfPointsAlongAMeridian,numberOfPoints,i,j,k;
    grib_handle *hnew;

    //int option_flags = GRIB_DUMP_FLAG_VALUES | 
    //    //GRIB_DUMP_FLAG_OPTIONAL | 
    //    GRIB_DUMP_FLAG_READ_ONLY;

    double missingValueInGrib;
    const double missingValueInImage = 65535;  // -1 as an unsigned short.
                                               // Set in TeDecoderMemory::resetMemory()
                                               // and TeRasterParams.h. Missing values in the
                                               // 'image' variable will be set to this.
                                               // NOTE: this could change if the data type
                                               // in ImagePlotting is changed from TeUNSIGNEDSHORT.
    {
        grib_handle* h;

        h = grib_handle_new_from_samples(0,"GRIB1");
        if(!h) {
            printf("ERROR: Unable to create grib handle\n");
            return 1;
        }

        // set date, time, parameter, etc
        hnew = grib_util_sections_copy(sourceGrib.id(), h, GRIB_SECTION_PRODUCT, &ret);

        if (ret)
        {
            perror("Error when copying GRIB product section.");
            return 1;
        }

        grib_handle_delete(h);
    }

    grib_get_double(hnew, "missingValue", &missingValueInGrib);
    grib_set_long  (hnew, "bitmapPresent", 1); // tell the GRIB that it will contain missing values

    // Set bounding box
    grib_set_double(hnew,"latitudeOfFirstGridPointInDegrees", matrix.minY());//getUpperRightCorner().y());
    grib_set_double(hnew,"longitudeOfFirstGridPointInDegrees",matrix.minX());//getLowerLeftCorner().x());

    grib_set_double(hnew,"latitudeOfLastGridPointInDegrees", matrix.maxY());//getLowerLeftCorner().y());
    grib_set_double(hnew,"longitudeOfLastGridPointInDegrees",matrix.maxX());//getUpperRightCorner().x()); 

    grib_set_double(hnew,"jDirectionIncrementInDegrees", resX_);
    grib_set_double(hnew,"iDirectionIncrementInDegrees", resY_);

    //Set matrix size
    numberOfPointsAlongAParallel = matrix.columns();
    numberOfPointsAlongAMeridian = matrix.rows();
    grib_set_long( hnew,"numberOfPointsAlongAParallel",numberOfPointsAlongAParallel);
    grib_set_long( hnew,"numberOfPointsAlongAMeridian",numberOfPointsAlongAMeridian);

    numberOfPoints=numberOfPointsAlongAMeridian*numberOfPointsAlongAParallel;
    values=(double*)malloc(numberOfPoints*sizeof(double));
    for (j=0;j < numberOfPointsAlongAMeridian;j++) {
        for (i=0;i < numberOfPointsAlongAParallel;i++) {
            k=i+numberOfPointsAlongAParallel*j;
            if (matrix[k] != missingValueInImage)
                values[k]=matrix[k];
            else
                values[k]=missingValueInGrib;
        }
    }

    grib_set_double_array( hnew,"values",values,numberOfPoints);

    if (hnew)
    { 
        // grib_dump_content(h,stdout,"serialize",option_flags, 0);
        FILE* out = fopen(gribOut_.c_str(),"w");
        if(out)
        {
            const void* mesg;
            size_t mesg_len;
            grib_get_message(hnew,&mesg,&mesg_len);
            fwrite(mesg,1,mesg_len,out);
            fclose(out);
        }
        else
        {
            perror(gribOut_.c_str());
            return 1;
        }
        grib_handle_delete(hnew);
    }
    else
    {
        printf("Error: unable to create grib_handle\n");
        return 1;
    }

    return 0;
}
