/******************************** LICENSE ********************************

 Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at 

    http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.

 ******************************** LICENSE ********************************/

/*! \file GribDecoder.cc
    \brief Implementation of the Template class GribDecoder.
    
    Magics Team - ECMWF 2004
    
    Started: Tue 16-Mar-2004
    
    Changes:
    
*/
 
#include "GribDecoder.h"
#include "Factory.h"
#include <limits>
#include "TitleTemplate.h"
#include "LocalTable.h"
#include "DateTime.h"
#include "GribTables.h"
#include <locale>
#include "GribInterpretor.h"
#include "XmlReader.h"
#include "TextVisitor.h"
#include "Timer.h"
#include "VisualAction.h"
#include "AnimationRules.h"
#include "Transformation.h"


using namespace magics;
grib_context* GribDecoder::context_ = 0;
int  GribDecoder::count_ = 0;

GribDecoder::GribDecoder() :  matrix_(0),  xComponent_(0), yComponent_(0), handle_(0)
{
	count_++;
	title_ = "grib_" + tostring(count_);
	version();
}

void GribDecoder::version()
{
	static bool done = false;
	if ( done ) return;
	done = true;
	MagLog::info() << "GribAPI Version :" << grib_get_api_version() << endl;
}

GribDecoder::~GribDecoder() 
{
	if ( matrix_) delete matrix_;
	if ( xComponent_ ) delete xComponent_;
	if ( yComponent_ ) delete yComponent_;
	if ( handle_ ) grib_handle_delete (handle_);
	//context is a reference to a global context and should not be deleted
}

void GribDecoder::set(const GribLoop& loop)
{
	// Copy the information about scaling...
	scaling_         = loop.getScaling();
	derived_scaling_ = loop.getDerived_scaling();
	scaling_offset_  = loop.getScaling_offset();
	scaling_factor_  = loop.getScaling_factor();
}

long GribDecoder::getLong(const string& key, bool warnIfKeyAbsent) const
{
	assert (context_);
	long val;
	int err = grib_get_long(handle_, key.c_str(), &val);
	if ( err )
	{
		if (warnIfKeyAbsent)
		{
			MagLog::warning() << "Grib API: can not find key [" << key << "]\n"
			               << grib_get_error_message(err) <<"\n";
		}
		return 0;
	}
	return val;
}


string GribDecoder::getString(const string& key, bool warnIfKeyAbsent) const
{
	assert (context_); 
	char val[1024];
	size_t length = 1024;
	int err = grib_get_string(handle_, key.c_str(), val, &length);
	if ( err )
	{
		if (warnIfKeyAbsent)
		{
			MagLog::warning() << "Grib API: can not find key [" << key << "]\n"
			               << grib_get_error_message(err) <<"\n";
		}
		return "";
	}
	return string(val);
}


double GribDecoder::getDouble(const string& key, bool warnIfKeyAbsent) const
{
	assert (context_); 
	double val;
	int err = grib_get_double(handle_, key.c_str(), &val);
	if ( err )
	{
		if (warnIfKeyAbsent)
		{
			MagLog::warning() << "Grib API: can not find key [" << key << "]\n"
			               << grib_get_error_message(err) <<"\n";
		}
		return 0;
	}
	return val;
}


void   GribDecoder::setDouble(const string& key, double val) const
{
	assert (context_);
	int err = grib_set_double(handle_, key.c_str(), val);
	if ( err )
	{
		MagLog::warning() << "Grib API: can not find key [" << key << "]\n"
		               << grib_get_error_message(err) <<"\n";
	}
}


void GribDecoder::read(Matrix **matrix)
{
	long repres;
	grib_get_long(handle_,"dataRepresentationType",&repres);
	const string representation = getString("typeOfGrid");

	try {
		auto_ptr<GribInterpretor> interpretor(SimpleObjectMaker<GribInterpretor>::create(representation));
		interpretor->interpretAsMatrix(*this, matrix);
		interpretor->scaling(*this, matrix);
	}
	catch (NoFactoryException&)
	{
		MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<<endl;;
		throw MagicsException("Grib Decoder: Representation [] not yet supported.");
	}
}


void GribDecoder::read(Matrix **matrix, const Transformation&  transformation)
{
	long repres;    
	grib_get_long(handle_,"dataRepresentationType",&repres);
	const string representation = getString("typeOfGrid");

	try {
		auto_ptr<GribInterpretor> interpretor(SimpleObjectMaker<GribInterpretor>::create(representation));
		interpretor->interpretAsMatrix(*this, matrix, transformation);
		interpretor->scaling(*this, matrix);
	}
	catch (NoFactoryException&)
	{
		MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<<endl;;
		throw MagicsException("Grib Decoder: Representation [] not yet supported.");
	}
}


/*!
 Class information are given to the output-stream.
*/		
void GribDecoder::print(ostream& out)  const
{
	out << "GribDecoder[";
	GribDecoderAttributes::print(out);
	out << "] ";
}

void GribDecoder::release()
{
	if ( matrix_ ) {
		delete matrix_;
		matrix_ = 0;
	}
	if ( xComponent_ ) {
		delete xComponent_;
		xComponent_ = 0;
	}
	if ( yComponent_ ) {
		delete yComponent_;
		yComponent_ = 0;
	}
}

void GribDecoder::decode2D() 
{
	if (xComponent_) return;
	Matrix     *w1 = 0;
	Matrix     *w2 = 0;

	openFirstComponent();
	read(&w1);
	openSecondComponent();
	read(&w2);

	wind_mode_->x(&xComponent_, &yComponent_, w1, w2);
}


void GribDecoder::customisedPoints(const AutomaticThinningMethod& thinning, const Transformation& transformation, const std::set<string>& request, CustomisedPointsList& points)
{
	int factor = thinning.points();
	
	openFirstComponent();
	long repres;    
	grib_get_long(handle_,"dataRepresentationType",&repres);
	const string representation = getString("typeOfGrid");
	try {
		auto_ptr<GribInterpretor> interpretor(SimpleObjectMaker<GribInterpretor>::create(representation));
		// Try to find the XResolution ...
		// Compute the thinning factor...
		double yres = interpretor->XResolution(*this);
		double height = transformation.height();
		factor = maground((height/factor) / yres);
		if (factor < 1) factor = 1;
		
		thinning.units(yres*factor);
		if ( factor == 1)
		{
			CustomisedPointsList xvalues, yvalues;
			string xc = "x_component";
			string yc = "y_component";
			interpretor->raw(*this, transformation, xc, xvalues);
			openSecondComponent();
			interpretor->raw(*this, transformation, yc, yvalues);
			CustomisedPointsList::iterator x = xvalues.begin();
			CustomisedPointsList::iterator y = yvalues.begin();
			while ( x != xvalues.end() && y!= yvalues.end() )
			{
				CustomisedPoint* point = new CustomisedPoint((*x)->longitude(), (*x)->latitude(), "");
				pair<double, double> val = (*wind_mode_)( (**x)[xc], (**y)[yc]);
				point->insert(make_pair(xc, val.first));
				point->insert(make_pair(yc, val.second));
				
				
				points.push_back(point);
				x++;
				y++;
			}
		}
		else {
			if ( thinning.rawOnly() == false ) {
				BasicThinningMethod basic;
				basic.factor(factor);
				thinning.units(yres*factor);
				customisedPoints(basic, transformation, request, points);
			}
		}
	}
	catch (NoFactoryException&)
	{
		MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<<endl;;
		throw MagicsException("Grib Decoder: Representation [] not yet supported.");
	}
}

void GribDecoder::customisedPoints(const BasicThinningMethod& thinning, const Transformation& transformation, const std::set<string>&, CustomisedPointsList& points)
{
	long type = getLong("uvRelativeToGrid");
	
	if ( type != 0 )
	{
		MagLog::warning() << "Rotaed grid: wind component are not relative to grid. The method is not yet implemented" << endl;
		return;
	}
	decode2D();
	MatrixHandler<GeoPoint> inx(*xComponent_);
	MatrixHandler<GeoPoint> iny(*yComponent_);

	vector<GeoPoint> thinx;
	vector<GeoPoint> thiny;
		
	int factor = thinning.factor();
	
	double xres = inx.XResolution();
	
	thinning.units(xres*factor);
	
	transformation.thin(inx, factor, factor, thinx);
	transformation.thin(iny, factor, factor, thiny);

	vector<GeoPoint>::const_iterator x = thinx.begin();
	vector<GeoPoint>::const_iterator y = thiny.begin();
	
	if (thinx.empty()) return;
	while (x->value() == inx.missing() ||   y->value() == iny.missing()) {
		++x;
		++y;
		if (x == thinx.end() || y == thiny.end()) 
			return;
	}
	CustomisedPoint *point = new CustomisedPoint(x->x(), x->y(), "");
	point->insert(make_pair("x_component", x->value()));
	point->insert(make_pair("y_component", y->value()));
	points.push_back(point);
	
	double lastx = x->x();
//	double lasty = x->x();
	x++;
	y++;
	while ( x != thinx.end() && y != thiny.end() )
	{			
		if ( x->value() != inx.missing() &&  y->value() != iny.missing() )
		{
			const double diff = (abs(x->x() - lastx));

			if ( diff >= xres *factor/2 || same(diff, xres *factor) )
			{
			    CustomisedPoint *point = new CustomisedPoint(x->x(), x->y(), "");
			    point->insert(make_pair("x_component", x->value()));
	                    point->insert(make_pair("y_component", y->value()));
			    points.push_back(point);
			}

		}
		lastx = x->x();
		x++;
		y++;
	} 
}

void GribDecoder::decode2D(const Transformation&) 
{	
	if (xComponent_) return;
	Matrix     *w1 = 0;
	Matrix     *w2 = 0;

	openFirstComponent();
	read(&w1);
	openSecondComponent();
	read(&w2);

	wind_mode_->x(&xComponent_, &yComponent_, w1, w2);
}


void GribDecoder::openFirstComponent() 
{
	grib_field_position_ =  position_1_;
	open();
}


void GribDecoder::openSecondComponent() 
{
	grib_field_position_ =  position_2_;
	open();
}


void  GribDecoder::open() 
{
	FILE* file = fopen(file_name_.c_str(),"r");
	if (!file)
	{
		MagLog::error() << "file can not be opened [" << file_name_ << "]" <<endl;
		throw GribFileMagException(file_name_, grib_field_position_);
	}
	if (!context_) 
		context_ =  grib_context_get_default();

	handle_ = (*address_mode_)(context_, file, grib_field_position_);

	if (handle_<=0)
	{
		MagLog::error() << "can not access position [" << grib_field_position_<<" in " << file_name_ << "]" <<endl;
		throw GribFileMagException(file_name_, grib_field_position_);
	}
}


bool GribDecoder::id(const string& id) const 
{
	return magCompare(id_, id);
}


void GribDecoder::decodePoints()
{
	if ( !points_.empty() ) return;
	open();
	
	unsigned long flags=0;
	int error;
	double scaling;
	double offset;
	const string representation = getString("typeOfGrid");
	try {
		auto_ptr<GribInterpretor> interpretor(SimpleObjectMaker<GribInterpretor>::create(representation));
		interpretor->scaling(*this, scaling, offset);
	}
	catch (NoFactoryException&)
	{
		MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<<endl;;
		scaling =1 ; offset =0;
	}

	grib_iterator* iter = grib_iterator_new(handle_, flags, &error);

	if (!iter)
	{
		MagLog::error() << "Grib Iterator not yet supported on this kind of grib\n";
		throw MagicsException("Grib Iterator not yet supported.");
	}

	double lat;
	double lon;
	double val;
	while (grib_iterator_next(iter,&lat,&lon,&val))
	{
		points_.push_back(GeoPoint(lon, lat, (val*scaling) + offset));
	}
}


grib_context* GribDecoder::gribContext() 
{
	if (!context_)
		context_ = grib_context_get_default();
	return context_;
}


GribLoop::~GribLoop()
{
    for (vector<GribDecoder*>::const_iterator g = gribs_.begin(); g != gribs_.end(); ++g)
    {
        delete *g;
    }
}


Data<GeoPoint>* GribLoop::current()
{
	return currentgrib_;
}


map<string, string> GribLoop::ids_;
int GribLoop::index_ = 0;
void GribLoop::next() {}


GribLoop::GribLoop():  currentgrib_(0), file_(0)
{
	current_ = dim_.begin();
	current1_ = dim_1_.begin();
	current2_ = dim_2_.begin();
	gribs_.clear();
}


void GribLoop::setToFirst() 
{
	current_ = dim_.begin();
	current1_ = dim_1_.begin();
	current2_ = dim_2_.begin();
}


bool  GribLoop::hasMore()
{
	if (file_ == 0 ) {
		file_ = fopen(path_.c_str(),"r");
		if (!file_) {
			MagLog::error() << "file can not be opened [" << path_ <<  "]" <<endl;
			throw GribFileMagException(path_, 0);
		}	
	}
	
    grib_context* context = GribDecoder::gribContext();
    
    // Now we have to find the right Entry!!! 
    
    //check the dimension 
    
    if ( dimension_ < 1 || dimension_ > 2 ) {
    	MagLog::warning() << " GribLoop setting grib_dimension reset to 1" << endl;
    }
    
   
    if ( dimension_ == 1 ) {   
    	if (  dim_.empty() ) {
    		 // case 1 dimension= 1 and loop on all the fields! 
    		int error;
    		grib_handle* handle = grib_handle_new_from_file(context, file_, &error) ; 
    		if (handle <=0)  return false;
    		currentgrib_ = new GribEntryDecoder(handle);
    		currentgrib_->set(*this);
            gribs_.push_back(currentgrib_);
    	}
    	else {
    		if ( current_ == dim_.end() )
    			return false;
    		 // Case 3 Dimension = 1 but we only used  a subset of fields
    		grib_handle* handle =  (*address_mode_)(context, file_, *current_);
    		current_++;
    		if (handle <=0)  
    			return false;
    		currentgrib_ = new GribEntryDecoder(handle);
    		currentgrib_->set(*this);
            gribs_.push_back(currentgrib_);
    	}
    }
    
   
	if ( dimension_ == 2)
	{
		if ( dim_1_.empty()  )
		{
			// case 2 Dimension = 2 and loop on all the field!
    			int error;
       			grib_handle* handle1 = grib_handle_new_from_file(context, file_, &error) ; 
       			if (handle1 <=0)  return false;	
       			grib_handle* handle2 = grib_handle_new_from_file(context, file_, &error) ; 
        		if (handle2 <=0)  return false;
        		currentgrib_ = new GribEntryDecoder(handle1, handle2);
        		currentgrib_->set(*this);
			gribs_.push_back(currentgrib_);
		}
		else {
        		// Case 4 Dimesnion = 2 and we only used a subset of fields! 
        		if ( current1_ ==  dim_1_.end() || current2_ ==  dim_2_.end() )
        			return false;

        		grib_handle* handle1 =  (*address_mode_)(context, file_, *current1_);
        		grib_handle* handle2 =  (*address_mode_)(context, file_, *current2_);
        		if ( handle1 <=0 )  
        			return false;
        		if ( handle2 <=0 )  
        		       return false;
        		currentgrib_ = new GribEntryDecoder(handle1, handle2);
        		currentgrib_->set(*this);
			gribs_.push_back(currentgrib_);
        		current1_++;
        		current2_++;
		}
	}

	currentgrib_->setFile_name(path_);
	if ( iconName_.empty() )
	{
    		map<string, string>::iterator id = ids_.find(path_);
    		if ( id == ids_.end() )
		{
    		    	iconName_ = "Grib" + tostring(index_);
    		    	index_++;
    		    	ids_.insert(make_pair(path_, iconName_));  		
    		 }
    		 else 
    		    	iconName_ = id->second;
	}
	currentgrib_->icon(*this);
	return true;
}

void GribLoop::print(ostream&) const {}



class GribTag: public XmlNodeVisitor
{
public:
	GribTag(GribDecoder& grib, TagHandler& title) : grib_(grib), title_(title) {
	}
	
	~GribTag() {}
	string baseDate(const XmlNode& node)
	{
		string format= node.getAttribute("format");
		if ( format.empty() )  
			format =  "%A %d %B %Y at %H UTC";
		const long day  = grib_.getLong("date");  
		const long hour = grib_.getLong("hour");  
		const long mn   = grib_.getLong("minute"); 
		Date part1 = Date(day);
		magics::Time part2 = magics::Time(hour, mn, 0);
		DateTime full(part1, part2);
		tm convert = full;
		try {
			locale loc("");
			ostringstream out;
			out.imbue(loc);   
			const std::time_put<char>& tfac = use_facet<time_put<char> >(loc); 
			tfac.put(out, out, ' ', &convert, format.c_str(), format.c_str()+format.length());       
			return out.str();
		}
		catch (...)
		{
			MagLog::error() << "Problem to setup the locale\n"
			             << "Check you LOCALE variable-->current value : " << getEnvVariable("LANG")<<endl;
			MagLog::broadcast();
			assert(false);
		}
	}

	string startDate(const XmlNode& node)
	{
			string format= node.getAttribute("format");
			if ( format.empty() )  
				format =  "%A %d %B %Y at %H UTC";
			const long day  = grib_.getLong("date");  
			const long hour = grib_.getLong("hour");  
			const long mn   = grib_.getLong("minute");
			const long step = grib_.getLong("startStep");  // default is in hours. Set 'stepUnits' to change.

			Date part1 = Date(day);
			magics::Time part2 = magics::Time(hour, mn, 0);
			DateTime full(part1, part2);	
			full = full + (step*3600);
			tm convert = full;
			try {
				locale loc("");
				ostringstream out;
				out.imbue(loc);   
				const std::time_put<char>& tfac = use_facet<time_put<char> >(loc); 
				tfac.put(out, out, ' ', &convert, format.c_str(), format.c_str()+format.length());       
				return out.str();
			}
			catch (...)
			{
				MagLog::error() << "Problem to setup the locale" << endl;
				MagLog::error() << "Check you LOCALE variable-->current value : " <<  getEnvVariable("LANG")<< endl;
				assert(false);
			}
	}

	string validDate(const XmlNode& node)
	{
			string format= node.getAttribute("format");
			if ( format.empty() )  
				format =  "%A %d %B %Y at %H UTC";
			const long day =  grib_.getLong("date");  
			const long hour = grib_.getLong("hour");  
			const long mn =  grib_.getLong("minute");
			const long step =  grib_.getLong("stepRange");  // default is in hours. Set 'stepUnits' to change.
			
						
			Date part1 = Date(day);
			magics::Time part2 = magics::Time(hour, mn, 0);
			DateTime full(part1, part2);	
			 full = full + (step*3600);
			tm convert = full;
			try {
				locale loc("");
				ostringstream out;
				out.imbue(loc);   
				const std::time_put<char>& tfac = use_facet<time_put<char> >(loc); 
				tfac.put(out, out, ' ', &convert, format.c_str(), format.c_str()+format.length());       
				return out.str();
			}
			catch (...)
			{
				MagLog::error() << "Problem to setup the locale" << endl;
				MagLog::error() << "Check you LOCALE variable-->current value : " <<  getEnvVariable("LANG")<< endl;
				assert(false);
			}
	}

	string endDate(const XmlNode& node)
	{
		string format=  node.getAttribute("format");
		if ( format.empty() )  
			format =  "%A %d %B %Y at %H UTC";
		const long day =  grib_.getLong("date");  
		const long hour = grib_.getLong("hour");  
		const long mn =  grib_.getLong("minute");
		const long step =  grib_.getLong("endStep");  // default is in hours. Set 'stepUnits' to change.

		Date part1 = Date(day);
		magics::Time part2 = magics::Time(hour, mn, 0);
		DateTime full(part1, part2);	
		 full = full + ( step*3600 );
		tm convert = full;
		try {
			locale loc("");
			ostringstream out;
			out.imbue(loc);   
			const std::time_put<char>& tfac = use_facet<time_put<char> >(loc); 
			tfac.put(out, out, ' ', &convert, format.c_str(), format.c_str()+format.length());       
			return out.str();
		}
		catch (...)
		{
			MagLog::error() << "Problem to setup the locale" << endl;
			MagLog::error() << "Check you LOCALE variable-->current value : " <<  getEnvVariable("LANG")<< endl;
			assert(false);
		}
	}

	void visit(const XmlNode& node)
	{
		if ( magCompare(node.name(), "grib_info") )
		{
			string grib = node.getAttribute("id");
					if ( !grib_.id(grib)) return;
			string def = node.getAttribute("key");
			if (def.empty()) {
				 def = node.getAttribute("definition");
				 // for backward compatibility with the first version! 
			}
			
			
			if ( def == "base-date" || def== "valid-date") {
				title_.update("grib"+grib, def, baseDate(node));
				return;
			}
			if ( def == "MV_Format" ) {
				title_.update("grib"+grib, def, "grib");
				return;
			}
			if ( def == "MV_Index"  || def == "MV_Frame" ||  def == "MV_Value" ) {
				// this is handled by Metview, so we just ignore it here
				return;
			}
			if ( def == "start-date" ) {
				title_.update("grib"+grib, def, startDate(node));
				return;
			}
			if ( def == "end-date" ) {
				title_.update("grib"+grib, def, endDate(node));
				return;
			}	
			string val; 
			string readAsLong = node.getAttribute("readAsLong");
			if(readAsLong != "yes")
			{
				val =  grib_.getString(def);
				string format = node.getAttribute("format"); 
				if ( !format.empty() ) {
					char tmp[256];
					sprintf(tmp, format.c_str(), val.c_str());
					val = tmp;
					
				}
			}
			else
			{
				long longVal = grib_.getLong(def);
				std::stringstream sst ;
				sst << longVal;
				val=sst.str(); 
			}
	
			if ( val.empty() ) 
				val =  node.getAttribute("default");
			title_.update("grib"+grib, def, val);
		}		
		
		if ( magCompare(node.name(), "magics_title") )
		{
			string grib = node.getAttribute("id");
			if ( !grib_.id(grib)) return;

			vector<string> lines;
			TitleTemplate::title(lines, grib_);
			for (unsigned int i = 0; i < lines.size(); i++)
			{
				string id = grib_.title() + "_" + tostring(i);
				title_.update("grib"+grib, id, lines[i]);		
				string entry = "<grib_info definition=\'" + id + "\'/>";
				title_.addToTags("<magics_title/>", entry);
			}
			//title_.addLines(lines.size());
		}
		node.visit(*this);	
	}
	
	void decode(const string& line)
	{
		XmlReader parser;
		XmlTree tree;
	
		ostringstream xml;
		xml << "<?xml version='1.0' ?> \n";		
		xml << "<xml> \n";
		xml << line;
		xml << "\n</xml>";

		try {
			parser.decode(xml.str(), &tree);		
			tree.visit(*this);
		}
		catch (MagicsException& e) {
			MagLog::debug() << e.what() << endl;
		}	
     } 
     string str() const { return out.str(); }
protected :
	GribDecoder& grib_;
	TagHandler& title_;
	ostringstream out;
};

void GribDecoder::visit(AnimationRules& )
{
}

void GribDecoder::visit(ValuesCollector& points)
{
	open();	
	const Transformation& transformation = points.transformation();
		
	points.setCollected(true);

	int nb = points.size();
	double inlats[nb];
	double inlons[nb];
	double outlats[nb];
	double outlons[nb];
	double values[nb];
	double distances[nb];
	int indexes[nb];
	double scaling, offset;
	string oriUnits, derivedUnits;
	string representation = getString("typeOfGrid");
	try 
	{
		auto_ptr<GribInterpretor> interpretor(SimpleObjectMaker<GribInterpretor>::create(representation));    	
		interpretor->scaling(*this, scaling, offset,oriUnits,derivedUnits); 
	}      
	catch (NoFactoryException&)
	{
		MagLog::warning() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n"<<endl;;
		scaling =1 ; offset =0;
	}
 	
	for (int i =0; i < nb; i++)
	{
		 inlats[i] = points[i].y();
		 inlons[i] = points[i].x();
		 i++;
	}
 
 	grib_nearest_find_multiple(handle_, 0, inlats, inlons, nb, outlats, outlons, values, distances, indexes);

	bool scaled=(scaling==1 && offset == 0)?false:true;
	points.setScaled(scaled);
	points.setUnits(oriUnits);
	points.setScaledUnits(derivedUnits);
	
	for (int i =0; i < nb; i++)
	{
		points[i].push_back(ValuesCollectorData(outlons[i],outlats[i],values[i],distances[i]));
							
		if(scaled)
			points[i].back().setScaledValue(scaling*values[i] + offset);  
							
	}
}

void GribDecoder::visit(MagnifierCollector& magnifier)
{
	const Transformation& transformation = magnifier.transformation(); 
	PointsHandler<GeoPoint>& points = this->points(transformation);
	points.setToFirst();

	while  ( points.more() )
	{
		magnifier.push_back(transformation(points.current()));
		points.advance();
	}
}


void GribDecoder::visit(MetaDataCollector& step)
{
	// Here we gather information for the label!
	const Transformation& transformation = step.transformation();
	
	open(); // just to be sure the file is opened!

	initInfo();

	 //Collect infos
	if(step.empty())
	{
		MetviewIcon::visit(step);
	   	return;
	}
	   
	try {	  
		bool members=false;
		vector<string> need;
		if(name_.empty())
		{
			members=true;
		  	need.push_back("<grib_info key='shortName'/>");
			need.push_back("<grib_info key='level'/>");
			need.push_back("<grib_info key='start-date' format='%Y-%m-%d %H:%M:00'/>");
			need.push_back("<grib_info key='end-date' format='%Y-%m-%d %H:%M:00'/>");
		}
		
		for(map<string, string>::iterator key = step.begin(); key != step.end(); ++key )
		{	    
			//If key is not found in information we use gribapi
		  	if(information_.find(key->first) == information_.end())
			{  
				//Compute stats
				if (step.attribute(key->first).group() == MetaDataAttribute::StatsGroup)
				{
					stats_.clear();
					
					MatrixHandler<GeoPoint> mh(*matrix_);
					BoxMatrixHandler<GeoPoint>* box = new BoxMatrixHandler<GeoPoint>(mh,transformation);
	

					PointsHandler<GeoPoint> points(*box);
					points.setToFirst();
	
					while( points.more() )
					{
						stats_["value"].push_back(points.current().value());						
						points.advance();
					}
					
					computeStats();
					
					delete box;
				}
				//We use gribapi
				else if(step.attribute(key->first).source() == MetaDataAttribute::AnySource ||
				   step.attribute(key->first).source() == MetaDataAttribute::GribApiSource)
				{  					  
					if(step.attribute(key->first).type() != MetaDataAttribute::NumberType)   
					{
						need.push_back("<grib_info key='"+key->first+ "'/>");
		   			}
					else
					{
						need.push_back("<grib_info key='"+key->first+ "' readAsLong='yes'/>");
					}

				}
			}	
			//If key is found in information_ we copy it
			else
			{
				  	key->second=information_[key->first];
			}	
		}
		
		
		if(!need.empty())	
		{
			TagHandler helper;
			GribTag tag1(*this, helper);
			for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t ) 
			{
	   			tag1.decode(*t);
			}	
				
	   		if(members)
			{  
	   			name_ = helper.get("grib", "shortName") +  " " +  helper.get("grib", "level");
	   			from_ = DateTime(helper.get("grib", "start-date"));
	   			to_ =  DateTime(helper.get("grib", "end-date"));
			}
			
			for(map<string, string>::iterator key = step.begin(); key != step.end(); ++key )
			{	    
				if(information_.find(key->first) == information_.end())
				{  
					if(step.attribute(key->first).source() == MetaDataAttribute::AnySource ||
				   	   step.attribute(key->first).source() == MetaDataAttribute::GribApiSource)
					{  					  
					 	key->second = helper.get("grib", key->first);
						setInfo(key->first,key->second);
					}	
				} 
			}	  
			
	   	}
	}

	catch (...) {}
}

void GribDecoder::decode(const Transformation& transformation) 
{
	if (matrix_) return;
	
	open();
	
	read(&matrix_, transformation);
	
	// here we build information for the layers!
	TagHandler helper; 
	vector<string> need;
	need.push_back("<grib_info id=\'" + id_ +"\' key='shortName'/>");
	need.push_back("<grib_info id=\'" + id_ +"\' key='level'/>");
	need.push_back("<grib_info id=\'" + id_ +"\'  key='start-date' format='%Y-%m-%d %H:%M:00'/>");
	need.push_back("<grib_info id=\'" + id_ +"\' key='end-date' format='%Y-%m-%d %H:%M:00'/>");
	GribTag tag1(*this, helper);

	for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
	{
		tag1.decode(*t);
	}

	name_ = helper.get("grib"+id_, "shortName") +  "-" +  helper.get("grib"+id_, "level");
	name_ = iconName_;
	layerId_ = name_ + file_name_;
	from_ = DateTime(helper.get("grib"+id_, "start-date"));
	to_ =  DateTime(helper.get("grib"+id_, "end-date"));	
}

void GribDecoder::decode() 
{
	if (matrix_) return;
	
	open();
	
	read(&matrix_);
	
	// here we build information for the layers!
	TagHandler helper; 
	vector<string> need;
	need.push_back("<grib_info id=\'" + id_ +"\' key='shortName'/>");
	need.push_back("<grib_info id=\'" + id_ +"\' key='level'/>");
	need.push_back("<grib_info id=\'" + id_ +"\'  key='start-date' format='%Y-%m-%d %H:%M:00'/>");
	need.push_back("<grib_info id=\'" + id_ +"\' key='end-date' format='%Y-%m-%d %H:%M:00'/>");
	GribTag tag1(*this, helper);

	for ( vector<string>::const_iterator t = need.begin(); t != need.end(); ++t )
	{
		tag1.decode(*t);
	}

	name_ = helper.get("grib"+id_, "shortName") +  "-" +  helper.get("grib"+id_, "level");
	name_ = iconName_;
	layerId_ = name_ + file_name_;
	from_ = DateTime(helper.get("grib"+id_, "start-date"));
	to_ =  DateTime(helper.get("grib"+id_, "end-date"));	
}

/*
void GribDecoder::visit(MagnifierVisitor& magnify) 
{
	
	vector<PaperPoint> thin;
	vector<PaperPoint> all;
	const Transformation& transformation = magnify.transformation();
	
	
	transformation.thin(matrix(), thin, all);
	
	for (vector<PaperPoint>::iterator point = thin.begin(); point != thin.end(); ++point) {
		 magnify.add(*point);
	}
	for (vector<PaperPoint>::iterator point = all.begin(); point != all.end(); ++point) {
			 magnify.addMore(*point);
	} 
}
*/

void GribDecoder::visit(TextVisitor& title) 
{
	try {
		open();	
	}
	catch ( ... )
	{
		return;
	}
	
	vector<string> titles;

	title.titles(titles);
	GribTag tag(*this, title);
	
	for ( vector<string>::const_iterator t = titles.begin(); t != titles.end(); ++t ) {
		tag.decode(*t);
	}
}



void GribDecoder::decodeRaster(const Transformation& transformation) 
{
	open();
	
	string representation = getString("typeOfGrid");
	
	try {
		GribInterpretor* interpretor = SimpleObjectMaker<GribInterpretor>::create(representation);
		interpretor->interpretAsRaster(*this, raster_, transformation);
	}
    
    catch (NoFactoryException&)
    {
    	MagLog::error() << "Grib Decoder: Representation [" << representation << "] not yet supported.\n";
    	throw MagicsException("Grib Decoder: Representation [] not yet supported.");
    }
}


void GribDecoder::initInfo()
{
	if(information_.find("_datatype") == information_.end())
	{
	  	setInfo("_datatype","GRIB");
		setInfo("path",getFile_name());
	}
}



namespace magics {

class GribInfo
{
public:
	GribInfo() {}
	virtual ~GribInfo() {}
	virtual void operator()(ostream&, const GribDecoder&) = 0;
};

class GribParameter : public GribInfo
{
public: 
	GribParameter() {}
	~GribParameter() {}
	void operator()(ostream& out, const GribDecoder& grib)
	{
		string val = grib.getString("name");
 		out << val;
	}
};

class GribParamCriter : public MatchCriteria<GribDecoder>
{
public:
	GribParamCriter() {}
	~GribParamCriter() {}
	bool verify(const GribDecoder& grib, const string&, const string& val)
	{
		long param = grib.getLong("paramId");
		return (tostring(param) == val);
	}
};

class GribLocalCriter : public MatchCriteria<GribDecoder>
{
public:
	GribLocalCriter() {}
	~GribLocalCriter() {}
	bool verify(const GribDecoder& grib, const string& param, const string& val)
	{
		string key = param;
		string criter = grib.getString(key, false); // 'false' to avoid warnings if key is absent
		MagLog::debug() << "I am verifing " << param << " for a GribDecoder : " << criter << " ==  " << val << "???" << "\n";
		return (criter == val);
	}
};

class GribObsDiagCriter : public MatchCriteria<GribDecoder>
{
public:
	GribObsDiagCriter() {}
	~GribObsDiagCriter() {}
	bool verify(const GribDecoder& grib, const string&, const string& )
	{
		string param = grib.getString("observationDiagnostic", false); // do not warn if the key is absent
		return (param != "");
	}
};


class GribLocalDefHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribLocalDefHandler() {}
	~GribLocalDefHandler() {}

	void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
	{
		if (!grib.getText()) return;      
		ostringstream out;
		string local = grib.getString("localDefinitionNumber");       
		out << "local definition =" << local << " ";        
		title.back() += out.str();
	}
};

class GribObsDiagHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribObsDiagHandler() {}
	~GribObsDiagHandler() {}

	void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
	{
        if (!grib.getText()) return;     
        ostringstream out;
		string local = grib.getString("observationDiagnostic");       
        out << "diagnostic =" << local << " ";   
        title.back() += out.str();
	}
};

class GribObstatHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribObstatHandler() {}
	~GribObstatHandler() {}

	void operator()(TitleField&, vector<string>& /*title*/, const GribDecoder& grib)
	{
        	if (!grib.getText()) return;      
		/*string type = grib.getString("codeType"); 
		string platform = grib.getString("platform"); 
      		string instrument = grib.getString("instrument");
		string selection = grib.getString("dataSelection");
		string diag = grib.getString("observationDiagnostic");
		string channel = grib.getString("scaledValueOfFirstFixedSurface");
		string min = grib.getString("min");
		string max = grib.getString("max");
		string mean = grib.getString("average");
		string units= grib.getString("units");
		string exp= grib.getString("experimentVersionNumber");
		string date= grib.getString("mars.date");
		string time= grib.getString("mars.time");
 
       		out << "Statistics for " << type << " from " << platform << "/" << instrument << "<br/>" << 
       			diag << " [" << units << "] (" << selection << ")" <<  "<br/>" << 
       			"Date = " << date << "  Time = " << time << "<br/>" <<
       			"Exp = " << exp << " Channel = " << channel << "<br/>" <<
       			"Min: "  << min << "    Max: " << max << " Mean: " << "mean";         
	
	*/
	}
};

class GribLocalHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribLocalHandler(const string& local) : local_(local) {}
	~GribLocalHandler() {}

	void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
	{
		if (!grib.getText()) return;
		ostringstream out;
		string code = grib.getString(local_);
		out << local_ << "=" << code  << " ";
		title.back()+= out.str();
	}
protected :
	string local_;
};

class GribStreamHandler : public GribLocalHandler 
{
public:
	GribStreamHandler() : GribLocalHandler("marsStream") {}
	~GribStreamHandler() {}
};

class GribClassHandler : public GribLocalHandler 
{
public:
	GribClassHandler() : GribLocalHandler("marsClass") {}
	~GribClassHandler() {}
};

class GribTypeHandler : public GribLocalHandler 
{
public:
	GribTypeHandler() : GribLocalHandler("marsType") {}
	~GribTypeHandler() {}
};


class GribParamHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribParamHandler() {}
	~GribParamHandler() {}
	virtual void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
	{
		if (!grib.getText()) return;
		string param = grib.getString("name");
 		title.back()+=param;
	}
};


class GribKeyHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribKeyHandler() {}
	~GribKeyHandler() {}
	void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
	{
		if (!grib.getText()) return;    
		
		char x[256];
		
		string key = field.attribute("key", ""); 	
		string value  = grib.getString(key);       
		string format = field.attribute("format", "%s");
		sprintf(x, format.c_str(), value.c_str());

	    title.back() += string(x);

	}
};

static locale& getLocale()
{
	static locale loc= locale::classic();
	try {
		loc = locale("");
	}
	catch (...)
	{
		MagLog::error() << "Problem to setup the locale" << endl;
		MagLog::error() << "Check you LANG variable-->current value : " <<  getEnvVariable("LANG")<<endl;
	
		loc= locale::classic();
	}
	return loc;
}


class GribBaseDateHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribBaseDateHandler() {}
	~GribBaseDateHandler() {}
	void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
	{
		if (!grib.getText()) return;
		ostringstream out;

		long date = grib.getLong("date");    
		long hour = grib.getLong("hour");  
		long mn =  grib.getLong("minute"); 
		Date part1 = Date(date);
		Time part2 = Time(hour, mn, 0);
		DateTime full(part1, part2);
		tm convert = full;

		out.imbue(getLocale());   
		const std::time_put<char>& tfac = use_facet<time_put<char> >(getLocale()); 
		string format = field.attribute("format", "%A %d %B %Y at %H UTC");
		tfac.put(out, out, ' ', &convert, format.c_str(), format.c_str()+format.length());        
	
		MagLog::dev() << "title--> " << out.str() << endl;
		title.back() += out.str();
	}	
};

class GribValidDateHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribValidDateHandler() {}
    ~GribValidDateHandler() {}
    void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
    {
	ostringstream out;
        long date = grib.getLong("date");    
        long hour = grib.getLong("hour");  
        long mn   = grib.getLong("minute"); 
        long step = grib.getLong("step") * 3600; // needs steps in second!   // default is in hours. Set 'stepUnits' to change.
       
        Date part1 = Date(date);
        Time part2 = Time(hour, mn, 0);
        DateTime full(part1, part2);
        full = full + step;

        tm convert = full;
        try {
	        locale loc("");
	        out.imbue(loc);

	        const time_put<char>& tfac = use_facet<time_put<char> >(loc); 
	        string format = field.attribute("format", "%A %d %B %Y %H UTC");
	        tfac.put(out, out, ' ', &convert, format.c_str(), format.c_str()+format.length());        
	        title.back() += out.str();
        }
    	catch (...)
    	{
    		MagLog::error() << "Problem to setup the locale" << endl;
    		MagLog::error() << "Check you LOCALE variable-->current value : " <<  getEnvVariable("LANG")<<endl;;
    		assert(false);
    	}

    }
};

class GribStepHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribStepHandler() {}
    ~GribStepHandler() {}
    void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
    {
//        if (!grib.getText()) return;
//        ostringstream out;
//        grib_int_t istep;
//        grib_get(grib.id(),(grib_string_t*)"forecastTime","i",&istep);
//        
//        ostringstream step;
//        step << istep;
//        string format = field.attribute("format", "t+%s");     
//        out << SimpleStringFormat(step.str(), format);
//        title.add(out.str());
	}
};


class GribLevelHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribLevelHandler() { 
    	if (map_.empty()) {
    		map_["Surface"] = &GribLevelHandler::surface;
    		map_["Unknown"] = &GribLevelHandler::surface;
    		map_["isobaricInhPa"] = &GribLevelHandler::isobaricInhPa;
    	}
    }
    
    ~GribLevelHandler() {}
    typedef string (GribLevelHandler::*Builder)(const string& def, const GribDecoder& grib) const;
    
    void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
    {
    	ostringstream out;
		if (!grib.getText()) return;       
        string level = grib.getString("typeOfLevel");
        
        map<string,  GribLevelHandler::Builder>::iterator help = map_.find(level);
        if ( help != map_.end() ) out << (this->*help->second)(level, grib) << " ";
        else out << level << " ";    
        
        title.back() +=  out.str();
        
    }
    
protected: 
	static map<string, GribLevelHandler::Builder> map_;
	
	string surface(const string&, const GribDecoder& ) const
	{
		return "";
	}	
	string unknown(const string& level, const GribDecoder& ) const
	{
		ostringstream out;
		out << "Unknown type of level[" << level << "]";
		return out.str();
	}	
	string isobaricInhPa(const string& , const GribDecoder& grib) const
	{
		ostringstream out;
		long level = grib.getLong("level");
		out  << level  <<  " " << "hPa";
		return out.str();
	}	
};
map<string, GribLevelHandler::Builder> GribLevelHandler::map_;


class GribTimeHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribTimeHandler() {}
    ~GribTimeHandler() {}
    void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
    {
//        if (!grib.getText()) return;
//        ostringstream out;
//        grib_int_t idate;
//        grib_get(grib.id(),(grib_string_t*)"time","I",&idate);      
//     
//        out << "Time:" << idate;
//        title.add(out.str());

          title.back() +=  "Time? ";
    }
};

class GribCentreHandler : public TitleFieldHandler<GribDecoder>
{
public:
	GribCentreHandler() {}
	~GribCentreHandler() {}
	void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
	{
		string format = field.attribute("format", "%s");
		string style = field.attribute("style", "short");
		long centre = grib.getLong("centre");	
		GeneralDef def = CentreTable::definition(centre);
		char x[256];
		string value = (style == "short") ?  def.shortTitle() : def.longTitle();
		sprintf(x, format.c_str(), value.c_str());

		title.back() += string(x);
	}
};

class GribProductHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribProductHandler() {}
    ~GribProductHandler() {}
    void operator()(TitleField&, vector<string>& title, const GribDecoder& grib)
    {
       if (!grib.getText()) return;     
       long type = grib.getLong("type");

       GeneralDef def = TypeTable::definition(type);
       title.back() += def.longTitle();
    }
};


class GribPlotTypeHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribPlotTypeHandler() {}
    ~GribPlotTypeHandler() {}
    void operator()(TitleField&, vector<string>&,const GribDecoder&)
    {
         //MagLog::warning() << "Plot Type: not implemented--> wait for the specification." << "\n";
    }
};


class NewLineHandler : public TitleFieldHandler<GribDecoder>
{
public:
    NewLineHandler() {}
    ~NewLineHandler() {}
    void operator()(TitleField&, vector<string>& title,const GribDecoder&)
    {
        title.push_back("");
    }
};


class SatelliteHandler : public TitleFieldHandler<GribDecoder>
{
public:
    SatelliteHandler()  {}
    ~SatelliteHandler() {}
    void operator()(TitleField&, vector<string>& title,const GribDecoder& grib)
    {
       ostringstream out;
       long ident =  grib.getLong("ident");

       out << "Sat:" << ident << " ";
       title.back() += out.str();
    }
};

class ChannelHandler : public TitleFieldHandler<GribDecoder>
{
public:
    ChannelHandler()  {}
    ~ChannelHandler() {}
    void operator()(TitleField&, vector<string>& title,const GribDecoder& grib)
    {       
    	ostringstream out;
        long band = grib.getLong("obstype");
        out << "Band:" << band << " ";
        title.back() += out.str();
    }
};


class GribExpverHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribExpverHandler() {}
    ~GribExpverHandler() {}
    void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
    {
       if (!grib.getText()) return;
       if ( !grib.getExpver() ) return; 
       ostringstream out;    
       string expver = grib.getString("mars.experimentVersionNumber");
       string format = field.attribute("format", "Expver=%s");          
       out << SimpleStringFormat(expver, format);
       title.back() += out.str();
   }
};


class GribEpsNumberInfoHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribEpsNumberInfoHandler() {}
    ~GribEpsNumberInfoHandler() {}
    void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
    {
	    
//       if (!grib.getText()) return;
//        ostringstream out;
//       grib_int_t local;
//       grib_get(grib.id(),(grib_string_t*)"localDefinition","I","localDefinitionNumber",&local);
//       if (local != 1) return;
//
//       char number[1024];
//       grib_get(grib.id(),(grib_string_t*)"localDefinition","s","total",number);
//       string format = field.attribute("format", "(%s members)");     
//      
//      out << SimpleStringFormat(number, format);
//        title.add(out.str());

    	 title.back() +=  "epsnumber?";

    }
};


class GribUnitHandler : public TitleFieldHandler<GribDecoder>
{
public:
    GribUnitHandler() {}
    ~GribUnitHandler() {}
    void operator()(TitleField& field, vector<string>& title, const GribDecoder& grib)
    {
/*
		if (!grib.getText()) return;
        if ( !grib.getUnits() ) return; 
        ostringstream out;      
     
        double id   = grib.getDouble("paramId");
        long centre  = grib.getLong("centre");
        				
        long param = (long) id;
        long table   = (id - param )*100;

          
        const ParamDef& parameter = LocalTable::localInfo(param, table, centre);
           
        string format = field.attribute("format", "Units:%s");           
        string unit = (grib.getScaling()) ? parameter.derivedUnit() :  parameter.originalUnit();
        out << SimpleStringFormat(unit, format);
      
        
        title.back() += out.str();
   */
    }
};

}// end namespace magics



static SimpleObjectMaker<GribParamCriter, MatchCriteria<GribDecoder> > gribparamcriter("parameter");
static SimpleObjectMaker<GribParamHandler, TitleFieldHandler<GribDecoder> > gribparamhandler("parameter");
static SimpleObjectMaker<GribBaseDateHandler, TitleFieldHandler<GribDecoder> > gribbasedatehandler("base_date");
static SimpleObjectMaker<GribValidDateHandler, TitleFieldHandler<GribDecoder> > gribvaliddatehandler("valid_date");
static SimpleObjectMaker<GribStepHandler, TitleFieldHandler<GribDecoder> > gribstephandler("step");
static SimpleObjectMaker<GribEpsNumberInfoHandler, TitleFieldHandler<GribDecoder> > gribepsnumberhandler("eps_number_info");

static SimpleObjectMaker<GribTimeHandler, TitleFieldHandler<GribDecoder> > gribTimehandler("time");
static SimpleObjectMaker<GribLevelHandler, TitleFieldHandler<GribDecoder> > gribLevelhandler("level");
static SimpleObjectMaker<NewLineHandler, TitleFieldHandler<GribDecoder> > newlinehandler("newline");
static SimpleObjectMaker<GribKeyHandler, TitleFieldHandler<GribDecoder> > gribkeyhandler("gribapi");

static SimpleObjectMaker<GribStreamHandler, TitleFieldHandler<GribDecoder> > gribstreamhandler("stream");
static SimpleObjectMaker<GribClassHandler, TitleFieldHandler<GribDecoder> > gribclasshandler("class");
static SimpleObjectMaker<GribTypeHandler, TitleFieldHandler<GribDecoder> > gribtypehandler("type");
static SimpleObjectMaker<GribLocalDefHandler, TitleFieldHandler<GribDecoder> > griblocaldefhandler("localdef");
static SimpleObjectMaker<GribCentreHandler, TitleFieldHandler<GribDecoder> > gribcentrehandler("centre");
static SimpleObjectMaker<GribProductHandler, TitleFieldHandler<GribDecoder> > gribproducthandler("product");
static SimpleObjectMaker<GribUnitHandler, TitleFieldHandler<GribDecoder> > gribunithandler("units");
static SimpleObjectMaker<GribExpverHandler, TitleFieldHandler<GribDecoder> > gribexpverhandler("expver");
static SimpleObjectMaker<GribPlotTypeHandler, TitleFieldHandler<GribDecoder> > gribplottypehandler("plot_type");
static SimpleObjectMaker<SatelliteHandler, TitleFieldHandler<GribDecoder> > satellitehandler("satellite");
static SimpleObjectMaker<ChannelHandler, TitleFieldHandler<GribDecoder> > channelhandler("channel");
static SimpleObjectMaker<GribBaseDateHandler, TitleFieldHandler<GribDecoder> > datehandler("date");


static SimpleObjectMaker<GribObsDiagCriter, MatchCriteria<GribDecoder> > gribobsdiagriter("observationDiagnostic");
static SimpleObjectMaker<GribObsDiagHandler, TitleFieldHandler<GribDecoder> > gribobsdiaghandler("observationDiagnostic");
static SimpleObjectMaker<GribObstatHandler, TitleFieldHandler<GribDecoder> > gribobstathandler("obstat");


static SimpleObjectMaker<GribLocalCriter, MatchCriteria<GribDecoder> > gribstreamcriter("stream");
static SimpleObjectMaker<GribLocalCriter, MatchCriteria<GribDecoder> > gribtypecriter("type");
static SimpleObjectMaker<GribLocalCriter, MatchCriteria<GribDecoder> > gribclasscriter("class");
static SimpleObjectMaker<GribLocalCriter, MatchCriteria<GribDecoder> > typeOfgeneratingProcess("typeOfGeneratingProcess");

#include "GribRegularInterpretor.h"
static SimpleObjectMaker<GribRegularInterpretor, GribInterpretor> regular_ll("regular_ll");
static SimpleObjectMaker<GribReducedLatLonInterpretor, GribInterpretor> reduced_ll("reduced_ll");
static SimpleObjectMaker<GribRegularGaussianInterpretor, GribInterpretor> regular_gg("regular_gg");
static SimpleObjectMaker<GribReducedGaussianInterpretor, GribInterpretor> reduced_gg("reduced_gg");
static SimpleObjectMaker<GribRotatedInterpretor, GribInterpretor> rotated_ll("rotated_ll");
static SimpleObjectMaker<GribLambertAzimutalInterpretor, GribInterpretor> lambert_azimuthal_equal_area("lambert_azimuthal_equal_area");


#include "GribSatelliteInterpretor.h"
static SimpleObjectMaker<GribSatelliteInterpretor, GribInterpretor> satellite("space_view");
