
/******************************** 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,
 WITHvisitor 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 EpsGraph.cc
    \brief Implementation of the Template class EpsGraph.
    
    Magics Team - ECMWF 2004
    
    Started: Wed 5-May-2004
    
    Changes:
    
*/



#include "EpsGraph.h"
#include "PointsHandler.h"
#include "DateTime.h"
#include "Text.h"
#include "LegendVisitor.h"

//#include "InteractiveSet.h"
#include <cfloat>
#include <locale>

using namespace magics;

string writeDate(DateTime& date, const string& format)
{
	std::locale loc("");

	ostringstream visitor;
	visitor.imbue(loc);

	const std::time_put<char>& facet = std::use_facet<std::time_put<char> >(loc); 

	tm convert = date;
	facet.put(visitor, visitor, ' ', &convert, format.c_str(), format.c_str()+format.length());    

	return visitor.str();
}

void tick(double min, double max, vector<double>& ticks)
{
	float inc;
	int nb = 7;
	float step;
	float log, ws;

	double wmax = std::max(min, max);
	double wmin = std::min(min, max);
	
  //cvisitor << "min=" << min << " max=" << max << endl;
	
	while (nb < 20)
	{
		step = (wmax-wmin)/nb;
		log = log10(step);
		ws = pow(10., int(log));
		inc = ceil(step/ws)*ws;
		//MagLog::dev() << "Automatic method ---> increment = " << inc << " ---> try base=" << inc/ws << endl;
			
		if ( wmax-wmin != inc && (inc/ws == 1 || inc/ws == 2 || inc/ws == 5 || inc/ws == 10) ) {
			//MagLog::dev() << "Automatic method ---> increment " << inc << " OK! " << endl;
			break;
		}
		nb++;	
	}
	
	float first = floor(min/inc) *inc; 
	double val = first > min ? first-inc : first;
        bool last = true;
        while (  last )
	{ 
		if (val >= max ) last = false;
		ticks.push_back(val);

		//cvisitor << "val->" << val << endl;
		 val+=inc;
	}
}
class EmptyEntry : public LegendEntry
{
public:
	EmptyEntry() : LegendEntry(" ") {}
    void set(const PaperPoint&, BasicGraphicsObjectContainer&) {}
};

class EpsEntry : public LegendEntry
{
public:
	EpsEntry() : LegendEntry(" ") {}
	void colour(const Colour& colour) { colour_ = colour; }
	void borderColour(const Colour& colour) { border_colour_ = colour; }
	void font(const MagFont& font) { font_ = font; }
	void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{

		double x = point.x();
		double y = point.y() - 0.125 ;

	
		Polyline* box  = new Polyline();
		box->setColour(border_colour_);
		box->setFilled(true);
		box->setShading(new FillShadingProperties());
		box->setFillColour(colour_);
		
        

		double width = 0.15;
		double height = 1.5; 
		double top = y+height;
		double bottom = y-height;
		box->push_back(PaperPoint(x-width, y));
		box->push_back(PaperPoint(x-width, top));
		box->push_back(PaperPoint(x+width, top));
		box->push_back(PaperPoint(x+width, y));
		box->push_back(PaperPoint(x-width, y));
		box->push_back(PaperPoint(x-width, bottom));
		box->push_back(PaperPoint(x+width, bottom));
		box->push_back(PaperPoint(x+width, y));
		box->push_back(PaperPoint(x-width, y));
		visitor.push_back(box);
		Polyline* up  = new Polyline();
		up->setColour(border_colour_);
		(*up).push_back(PaperPoint(x, top+height));
		(*up).push_back(PaperPoint(x, top));
		visitor.push_back(up);
		Polyline* down  = new Polyline();
		down->setColour(border_colour_);
		(*down).push_back(PaperPoint(x, bottom));
		(*down).push_back(PaperPoint(x, bottom-height));
		visitor.push_back(down);
		
		// Now the text...
		Text* max  = new Text();
		max->setText("max");
		max->setFont(font_);		
		max->setJustification(MLEFT);
		(*max).push_back(PaperPoint(x + 1*.2, bottom-height));
		visitor.push_back(max);
		
		Text* min  = new Text();
		min->setText("min");
		min->setFont(font_);
		min->setJustification(MLEFT);		
		(*min).push_back(PaperPoint(x + 1*.2, top+height));
		visitor.push_back(min);
        
       
		Text* seventyfive  = new Text();
		seventyfive->setText("75%");
		seventyfive->setFont(font_);
		seventyfive->setJustification(MLEFT);		
		seventyfive->push_back(PaperPoint(x + 1*0.3, bottom));
		visitor.push_back(seventyfive);
		
		Text* fifty  = new Text();
		fifty->setText("median");
		fifty->setFont(font_);
		fifty->setJustification(MLEFT);
		(*fifty).push_back(PaperPoint(x + 1*0.3, y));
		visitor.push_back(fifty);
		
		Text* twentyfive  = new Text();
		twentyfive->setText("25%");
		twentyfive->setFont(font_);
		twentyfive->setJustification(MLEFT);
		twentyfive->push_back(PaperPoint(x + 1*0.3, top));
		visitor.push_back(twentyfive);
	}
	
protected:
	Polyline*  box_;
	Colour colour_;
	Colour border_colour_;
	MagFont font_;
};


class FullEpsEntry : public EpsEntry
{
public:
	FullEpsEntry() {}

	virtual void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{
		

		double x = point.x();
		double y = point.y() ;

		MagLog::dev() << "FulleEps Entry->  [" << x << ", " << y << "]" << endl;
	
		Polyline* box  = new Polyline();
		box->setColour(border_colour_);
		box->setFilled(true);
		box->setFillColour(colour_);
		box->setShading(new FillShadingProperties());

		double width = 1*0.2;
		double height = 1*0.2; 
		double top1 = y+height;
		double bottom1 = y-height;
		double top2 = y+height+height;
		double bottom2 = y-height-height;
		box->push_back(PaperPoint(x-width, y));
		box->push_back(PaperPoint(x-width, top1));
		box->push_back(PaperPoint(x+(width/2), top1));
		box->push_back(PaperPoint(x+(width/2), top2));
		box->push_back(PaperPoint(x-(width/2), top2));
		box->push_back(PaperPoint(x-(width/2), top1));
		box->push_back(PaperPoint(x+width, top1));
		box->push_back(PaperPoint(x+width, y));
		box->push_back(PaperPoint(x-width, y));
		box->push_back(PaperPoint(x-width, bottom1));
		box->push_back(PaperPoint(x+(width/2), bottom1));
		box->push_back(PaperPoint(x+(width/2), bottom2));
		box->push_back(PaperPoint(x-(width/2), bottom2));
		box->push_back(PaperPoint(x-(width/2), bottom1));
		box->push_back(PaperPoint(x+width, bottom1));
		box->push_back(PaperPoint(x+width, y));
		box->push_back(PaperPoint(x-width, y));
		visitor.push_back(box);
		Polyline* up  = new Polyline();
		up->setColour(border_colour_);
		(*up).push_back(PaperPoint(x, top2+height));
		(*up).push_back(PaperPoint(x, top2));
		visitor.push_back(up);
		Polyline* down  = new Polyline();
		down->setColour(border_colour_);
		(*down).push_back(PaperPoint(x, bottom2));
		(*down).push_back(PaperPoint(x, bottom2-height));
		visitor.push_back(down);
		
		// Now the text...
		Text* max  = new Text();
		max->setText("max");
		max->setFont(font_);
		max->setJustification(MLEFT);
		max->push_back(PaperPoint(x + 0.5, bottom2-height));

		visitor.push_back(max);
		
		Text* min  = new Text();
		min->setText("min");
		min->setFont(font_);
		min->setJustification(MLEFT);
		min->push_back(PaperPoint(x + 1*0.5, top2+height));
		visitor.push_back(min);
        
		Text* ninety  = new Text();
		ninety->setText("90%");
		ninety->setFont(font_);
		ninety->setJustification(MLEFT);
		ninety->push_back(PaperPoint(x + 0.5, bottom2));
		visitor.push_back(ninety);
		
		Text* ten  = new Text();
		ten->setText("10%");
		ten->setFont(font_);
		ten->setJustification(MLEFT);
		ten->push_back(PaperPoint(x + 0.5, top2));
		visitor.push_back(ten);
		
		Text* seventyfive  = new Text();
		seventyfive->setText("75%");
		seventyfive->setFont(font_);
		seventyfive->setJustification(MLEFT);
		seventyfive->push_back(PaperPoint(x + 0.75, bottom1));
		visitor.push_back(seventyfive);
		
		Text* fifty  = new Text();
		fifty->setText("median");
		fifty->setFont(font_);
		fifty->setJustification(MLEFT);
		(*fifty).push_back(PaperPoint(x + 0.75, y));
		visitor.push_back(fifty);
		
		Text* twentyfive  = new Text();
		twentyfive->setText("25%");
		twentyfive->setFont(font_);
		twentyfive->setJustification(MLEFT);
		twentyfive->push_back(PaperPoint(x + 0.75, top1));

		visitor.push_back(twentyfive);
	}
};

class WindRoseEntry : public EpsEntry
{
public:
	WindRoseEntry(const Colour& colour) { colour_ = colour; }

	virtual void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{
		

		double x = point.x()-0.5;
		double y = point.y() ;

		MagLog::dev() << "FulleEps Entry->  [" << x << ", " << y << "]" << endl;
	
		
	MagFont font("sansserif", "normal", 0.25);
	font.colour(Colour("Rgb(0.2, 0.2, 0.2)"));
	
	float start = x;
	
	for ( int i = 0; i != 100; i ++ ) { 
	    
		Hsl hsl = colour_.hsl();    
        float light = hsl.light_;        
        hsl.light_ += (0.99 - light)*((100-i)/100.);
    	Colour colour(hsl);
		
		Polyline* box  = new Polyline();
		box->setColour(colour);
		box->setFilled(true);
		box->setFillColour(colour);
		box->setShading(new FillShadingProperties());
		
		double width = 0.0225;
		double height = 1*0.25; 
		box->push_back(PaperPoint(start, y));
		box->push_back(PaperPoint(start, y+height));
		box->push_back(PaperPoint(start+width, y+height));
		box->push_back(PaperPoint(start+width, y));
		box->push_back(PaperPoint(start, y));		
		visitor.push_back(box);
		
		start+=width;
		
	}
		
		Polyline* box  = new Polyline();
		box->setColour(border_colour_);
		box->setFilled(false);
		
		
		double height = 1*0.25; 
		box->push_back(PaperPoint(x, y));
		box->push_back(PaperPoint(x, y+height));
		box->push_back(PaperPoint(start, y+height));
		box->push_back(PaperPoint(start, y));
		box->push_back(PaperPoint(x, y));		
		visitor.push_back(box);
		
		// Now the text...
		Text* text  = new Text();
		text->setText("0%");
		text->setFont(font_);
		text->setJustification(MLEFT);
		text->push_back(PaperPoint(x, y-0.2));
		visitor.push_back(text);
		text  = new Text();
		text->setText("25%");
		text->setFont(font_);
		text->setJustification(MLEFT);
		text->push_back(PaperPoint(x+0.5, y-0.2));
		visitor.push_back(text);	
		text  = new Text();
		text->setText("50%");
		text->setFont(font_);
		text->setJustification(MLEFT);
		text->push_back(PaperPoint(x+1, y-0.2));
		visitor.push_back(text);	
		text  = new Text();
		text->setText("75%");
		text->setFont(font_);
		text->setJustification(MLEFT);
		text->push_back(PaperPoint(x+1.5, y-0.2));
		visitor.push_back(text);
		text  = new Text();
		text->setText("100%");
		text->setFont(font_);
		text->setJustification(MLEFT);
		text->push_back(PaperPoint(x+2, y-0.2));
		visitor.push_back(text);		
		
		
		
		
	}
	string text_;
	
};


class WaveRoseEntry : public EpsEntry
{
public:
	WaveRoseEntry(vector<Colour>& colour) { colours_ = colour; }

	virtual void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{

		double x = point.x();
		double y = point.y() ;

		MagLog::dev() << "FulleEps Entry->  [" << x << ", " << y << "]" << endl;
	
		
	MagFont font("sansserif", "normal", 0.25);
	font.colour(Colour("Rgb(0.2, 0.2, 0.2)"));
	
	float start = x;
	
	
	for ( vector<Colour>::const_iterator colour = colours_.begin(); colour != colours_.end(); ++colour) { 
		
		Polyline* box  = new Polyline();
		box->setColour(*colour);
		box->setFilled(true);
		box->setShading(new FillShadingProperties());
		box->setFillColour(*colour);
		double width = 0.4;
		double height = 1*0.25; 
		box->push_back(PaperPoint(start, y));
		box->push_back(PaperPoint(start, y+height));
		box->push_back(PaperPoint(start+width, y+height));
		box->push_back(PaperPoint(start+width, y));
		box->push_back(PaperPoint(start, y));		
		visitor.push_back(box);
		
		start+=width;
		
	}
		
		Polyline* box  = new Polyline();
		box->setColour(border_colour_);
		box->setFilled(false);
		
		double height = 1*0.25; 
		box->push_back(PaperPoint(x, y));
		box->push_back(PaperPoint(x, y+height));
		box->push_back(PaperPoint(start, y+height));
		box->push_back(PaperPoint(start, y));
		box->push_back(PaperPoint(x, y));		
		visitor.push_back(box);
		
		// Now the text...
		Text* text  = new Text();
		text->setText("1");
		text->setFont(font_);
		text->setJustification(MCENTRE);
		text->push_back(PaperPoint(x+0.35, y-0.2));
		visitor.push_back(text);
		
		text  = new Text();
		text->setText("2.5");
		text->setFont(font_);
		text->setJustification(MCENTRE);
		text->push_back(PaperPoint(x+0.8, y-0.2));
		visitor.push_back(text);	

		text  = new Text();
		text->setText("4");
		text->setFont(font_);
		text->setJustification(MCENTRE);
		text->push_back(PaperPoint(x+1.2, y-0.2));
		visitor.push_back(text);	
		
		text  = new Text();
		text->setText("6");
		text->setFont(font_);
		text->setJustification(MCENTRE);
		text->push_back(PaperPoint(x+1.6, y-0.2));
		visitor.push_back(text);
		
		text  = new Text();
		text->setText("9 m");
		text->setFont(font_);
		text->setJustification(MLEFT);
		text->push_back(PaperPoint(x+2.0, y-0.2));
		visitor.push_back(text);		
		
		
		
		
	}
	string text_;
	vector<Colour> colours_;
	
};


class EpsControl : public LegendEntry
{
public:
	EpsControl(double resolution, const string& type, double height) : 
			LegendEntry(" "), legend_size_(height)
	{
		ostringstream title;
		// carefull here this text is depending of the resolution! 
		MagLog::dev() << "EpsControl=>resolution" << resolution << endl; 
        int km = maground(40000/(2*(resolution+1)+2));  
		title << "ENS Control(" + tostring(km) + " km)";
		title_ = title.str();
	}
	EpsControl(const string& title, double height) : LegendEntry(" "), legend_size_(height)
	{
		
		title_ = title;
	}
	void font_size(double height) { legend_size_ = height; }	
	void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{
		

		double x = point.x();
		double y = point.y() - 0.125;
		

		MagLog::dev() << "Legend at Point[" << point.x() << ", " << point.y() << "]" << endl;
	
		Text* text  = new Text();
		text->addText(title_, Colour("red"),  legend_size_); // should be customisable
		text->setJustification(MLEFT);
		(*text).push_back(PaperPoint(x + 1*0.04, y));
		visitor.push_back(text);
	}
	
protected:
	string title_;
	double legend_size_;
};


class EpsForecast : public LegendEntry
{
public:
	EpsForecast(double resolution, const string& type, double height) : 
		LegendEntry(" "), legend_size_(height)
	{
		MagLog::dev() << "EpsForecsat=>resolution" << resolution << endl; 
		ostringstream title;
        int km = maground(40000/(2*(2*resolution+1)+2));        
		title << "High Resolution (" + tostring(km) + " km)";
		title_ = title.str();
	}
	
	EpsForecast(const string& title, double height) : 
		LegendEntry(" "), legend_size_(height)

		{
			
			title_ = title;
		}	
	void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{
	
		

		double x = point.x();
		double y = point.y()- 0.125;

		
		Text* text  = new Text();
		text->addText(title_, Colour("blue"),  legend_size_); // should be customisable
		text->setJustification(MLEFT);
		(*text).push_back(PaperPoint(x + 1*0.04, y));
		visitor.push_back(text);
	}
	
protected:
	string title_;
	double legend_size_;
};


class EpsCalval1 : public LegendEntry
{
public:
	EpsCalval1(double) : LegendEntry(" ")
	{
		ostringstream title;
		//title << "T" << (2*resolution)-1 << " OPS";
        title << "CAL/VAL 1";
		title_ = title.str();
	}
		
	void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{
		
	
		
	
		double x = point.x();
		double y = point.y()- 0.125;
		Polyline* line  = new Polyline();
		line->setColour(Colour("green"));
		
		line->setLineStyle(M_SOLID);
		line->setThickness(2);
		line->push_back(PaperPoint(x-1*0.025, y));
		line->push_back(PaperPoint(x+1*0.025, y));
		visitor.push_back(line);
		
		Text* text  = new Text();
		text->setText(title_);
		text->setJustification(MLEFT);
		(*text).push_back(PaperPoint(x + 1*0.04, y));
		visitor.push_back(text);
	}
	
protected:
	string title_;
};

class EpsCalval2 : public LegendEntry
{
public:
	EpsCalval2(double, double height) : LegendEntry(" "), legend_size_(height)
	{
		ostringstream title;
		//title << "T" << (2*resolution)-1 << " OPS";
        title << "CAL/VAL 2";
		title_ = title.str();
	}
		
	void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{
		
		
		
	
		double x = point.x();
		double y = point.y()- 0.125;
		Polyline* line  = new Polyline();
		line->setColour(Colour("magenta"));
		
		
		line->setThickness(2);
		line->push_back(PaperPoint(x-1*0.025, y));
		line->push_back(PaperPoint(x+1*0.025, y));
		visitor.push_back(line);
		
		Text* text  = new Text();
		text->addText(title_, Colour("blue"), legend_size_ ); // should be customisable
		text->setJustification(MLEFT);
		(*text).push_back(PaperPoint(x + 1*0.04, y));
		visitor.push_back(text);
	}
	
protected:
	string title_;
	double legend_size_;
};


EpsGraph::EpsGraph() : forecast_(false), control_(false), eps_(true)
{
}


EpsGraph::~EpsGraph() 
{}

/*!
 Class information are given to the visitorput-stream.
*/		
void EpsGraph::print(ostream& visitor)  const
{
	visitor << "EpsGraph[";
	visitor << "]";
}



void EpsGraph::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{
	
	CustomisedPointsList points; 
	std::set<string> request;

	const Transformation& transformation = visitor.transformation();
	
	data.customisedPoints(transformation, request, points, true); // we want all the points!

	
	if (points.empty()) return;
	


	
	Polyline* control  = new Polyline();
	control->setColour(*control_colour_);
	control->setLineStyle(control_style_);
	control->setThickness(control_thickness_);
	
	Polyline* forecast  = new Polyline();
	forecast->setColour(*deterministic_colour_);
	forecast->setThickness(deterministic_thickness_);
	forecast->setLineStyle(deterministic_style_);
    
   
	
	

	resolution_ = (*points.front())["resolution"];
	
	
	
		
		DateTime base = points.front()->base();
		
	
    vector<BasicGraphicsObject*> list, list2;
    
    
    
    if ( points.size() < 2 ) return;
    fullEps_ = false;
    
    Colour colour = *colour_;
    
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {
		resolution_ = (**point)["resolution"];
		
		double x = (**point)["step"] + box_shift_ *3600;
		double width = (box_width_ == -1) ? (**point)["width"] : box_width_ * 3600;
		
		if ( (**point)["right"] ) colour = *right_colour_;
		if ( (**point)["left"] )  colour = *left_colour_;
		

		double max = ((*point)->find("max") != (*point)->end()) ? (*point)->find("max")->second : (*point)->find("maximum")->second;
		double min = ((*point)->find("min") != (*point)->end()) ? (*point)->find("min")->second : (*point)->find("minimum")->second;


		CustomisedPoint::const_iterator ten   = (*point)->find("ten");
                CustomisedPoint::const_iterator ninty = (*point)->find("ninty");



		
        

        if ( (*point)->find("control") != (*point)->end() &&  (**point)["control"]!= 9999.  )
        	control->push_back(PaperPoint(x, (**point)["control"]));		
		if ( (*point)->find("forecast") != (*point)->end() &&  (**point)["forecast"] != 9999.)
            forecast->push_back(PaperPoint(x, (**point)["forecast"]));
        if ( (*point)->find("median") == (*point)->end() )  {        	
            eps_ = false;  
            continue;
        }
        if (  (**point)["median"] == 9999. ) {        	
                   eps_ = false;  
                   continue;
               }
     
	vector<double> eps;
	eps.push_back( (**point)["min"]);
	eps.push_back( (**point)["ten"]);
	eps.push_back( (**point)["twentyfive"]);
	eps.push_back( (**point)["median"]);
	eps.push_back( (**point)["seventyfive"]);
	eps.push_back( (**point)["ninty"]);
	eps.push_back( (**point)["max"]);

	std::sort(eps.begin(), eps.end());

	for (vector<double>::iterator e = eps.begin(); e != eps.end(); ++e)
		if ( same(*e, 0) ) *e = 0;

        double epsmin, eps10, eps25,  eps50, eps75, eps90, epsmax;
        if ( ninty != (*point)->end() ) {
        	epsmin = eps[0];
        	eps10 = eps[1];
       		eps25 = eps[2];
        	eps50 = eps[3];
        	eps75 = eps[4];
        	eps90 = eps[5];
        	epsmax = eps[6];
	}
	else {
        	epsmin = eps[0];
       		eps25 = eps[1];
        	eps50 = eps[2];
        	eps75 = eps[3];
        	epsmax = eps[4];
	}

		Polyline* box  = new Polyline();
		box->setColour(*border_colour_);
		box->setThickness(border_thickness_);

		box->setColour(*border_colour_);
		box->setFilled(true);
		box->setThickness(border_thickness_);
		box->setFillColour(colour);
		box->setShading(new FillShadingProperties());
      
        Polyline* median  = new Polyline();
        median->setColour(*median_colour_);
        
        Polyline* bar1  = new Polyline();
        bar1->setColour(*border_colour_);
        bar1->setThickness(border_thickness_);

        Polyline* bar2  = new Polyline();
        bar2->setColour(*border_colour_);
        bar2->setThickness(border_thickness_);

        box->push_back(PaperPoint(x-width, eps50));
		box->push_back(PaperPoint(x-width, eps75));
        
        if ( ninty != (*point)->end() ) {
        	fullEps_ = true;
            box->push_back(PaperPoint(x-(width/2), eps75));
            box->push_back(PaperPoint(x-(width/2), eps90) );
            box->push_back(PaperPoint(x+(width/2), eps90));
            box->push_back(PaperPoint(x+(width/2), eps75));
            
        }
		box->push_back(PaperPoint(x+width, eps75));
		box->push_back(PaperPoint(x+width, eps25));

        if ( ten != (*point)->end() ) {
            box->push_back(PaperPoint(x+(width/2), eps25));
            box->push_back(PaperPoint(x+(width/2),eps10));
            box->push_back(PaperPoint(x-(width/2), eps10));
            box->push_back(PaperPoint(x-(width/2), eps25));
            
        }
        box->push_back(PaperPoint(x-width, eps25));
        box->push_back(PaperPoint(x-width, eps50));

    	bar1->push_back(PaperPoint(x+width, eps25));
    	bar1->push_back(PaperPoint(x-width, eps25));

    	bar2->push_back(PaperPoint(x+width, eps75));
    	bar2->push_back(PaperPoint(x-width, eps75));

    	median->push_back(PaperPoint(x+width, eps50));
		median->push_back(PaperPoint(x-width, eps50));
		
		
		Polyline* top  = new Polyline();
		top->setColour(*border_colour_);
		top->setThickness(border_thickness_);
		
	     
		(*top).push_back(PaperPoint(x, epsmax > transformation.getMaxY() ? transformation.getMaxY() : epsmax));
		
		if ( ninty != (*point)->end() ) 
            (*top).push_back(PaperPoint(x, eps90));
        else 
            (*top).push_back(PaperPoint(x, eps75));
		Polyline* bottom  = new Polyline();
		bottom->setColour(*border_colour_);
		bottom->setThickness(border_thickness_);
		(*bottom).push_back(PaperPoint(x, epsmin));
        if ( ten != (*point)->end() ) 
            (*bottom).push_back(PaperPoint(x, eps10));
		else 
           (*bottom).push_back(PaperPoint(x, eps25));
		
		if (whisker_) {
            transformation(*box, visitor);
            transformation(*top, visitor);
            transformation(*bottom, visitor);
            transformation(*median, visitor);
            transformation(*bar1, visitor);
            transformation(*bar2, visitor);
		}
		
		// find the max! 
		vector<double> ypos;
		 for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {
		   		double max = ((*point)->find("max") != (*point)->end()) ? (*point)->find("max")->second : (*point)->find("maximum")->second;
				double min = ((*point)->find("min") != (*point)->end()) ? (*point)->find("min")->second : (*point)->find("minimum")->second;
		        ypos.push_back(max);
				ypos.push_back(min);
				if ( (*point)->find("control") != (*point)->end() )
					ypos.push_back((**point)["control"]);
			    if ( (*point)->find("forecast") != (*point)->end() )
				    ypos.push_back((**point)["forecast"]);
		    
		    }
		
		    double maxy = *std::max_element(ypos.begin(), ypos.end());
		    maxy = ( max_ > INT_MIN ) ? max_ : maxy;
		    double maxlabel = DBL_MIN;
		   		        if (max > maxy) 
		   		        		maxlabel = max;
		   		        if (min > maxy) 
		   		        		maxlabel = min; 
       
       
       if ( max > transformation.getMaxY() ) {
       	 Text* label = new Text();
		 MagFont font(max_font_name_, max_font_style_, max_font_size_);
		 font.colour(*max_font_colour_);		
		 label->setText(tostring(maground(max)));
		 label->setFont(font);
		 label->push_back(PaperPoint(x, transformation.getMaxY()*1.05));
		 visitor.push_back(label);
       }

		 
       }
		
	
	
	if ( !control->empty() && whisker_) {		
		transformation(*control, visitor);
		control_ = true;
	}
	else 
		control_ = false;
	if ( !forecast->empty() && deterministic_) {					
		transformation(*forecast, visitor);
		forecast_ = true;
	}
	else
		forecast_ = false;
	
	

     	
		

}

void EpsGraph::visit(LegendVisitor& legend)
{
	
    if ( !legend_ ) return;
	EpsEntry* entry = fullEps_ ? new FullEpsEntry() : new EpsEntry();
	
	if ( grey_legend_ ) {
		entry->colour(Colour("grey"));
		entry->borderColour(Colour("charcoal"));
	}
	else {
		entry->colour(*colour_);
		entry->borderColour(*border_colour_);
	}
    MagFont font(font_);
    font.style(font_style_);
	font.size(legend_size_);
	font.colour(*font_colour_);
	if ( grey_legend_ ) {
		font.colour( Colour("charcoal"));
	}

	entry->font(font);
	if ( whisker_ && eps_ )	
        legend.add(entry);
	
     
    if ( control_  )   {
    	MagLog::dev() << "LEGEND-> " << legend_control_text_ << endl;
    	if (legend_control_text_.empty() )
    		legend.add(new EpsControl(resolution_, legend_resolution_, legend_size_));
    	else 
    		legend.add(new EpsControl(legend_control_text_, legend_size_));
    }
    if ( forecast_  ) {
    	if (legend_forecast_text_.empty() )
    	    legend.add(new EpsForecast(resolution_, legend_resolution_, legend_size_));
    	else 
    	    legend.add(new EpsForecast(legend_forecast_text_, legend_size_));
    }
    	
   
}



void triangle2(const pair<string, float>& direction, CustomisedPoint& point, BasicGraphicsObjectContainer& visitor, double pos, double max)
{

	
	double shift = 3.14*0.125;
	
	Polyline* poly = new Polyline();

	poly->setThickness(2);
	
	double c = 1 - point[direction.first]/200;
	
	ostringstream colour;
	colour << "Rgb(" << c << ", " << c << ", " << c << ")" << endl; 
	
	poly->setFillColour(colour.str());	
	poly->setColour(Colour("Rgb(0.5, 0.5, 0.5)"));
	
	double length = 9*3600;
	double x0 = length;
//	double y0 = 0;
//	double a = length *tan(shift);
//	double b = length *tan(-shift);
	
	double x = x0 * cos(direction.second);
	double y = x0 * sin(direction.second);
	double x1 = x0 * cos(direction.second - shift);
	double y1 = x0 * sin(direction.second - shift);
	double x2 = x0 * cos(direction.second + shift);
	double y2 = x0 * sin(direction.second + shift);
	
	double xs = 0;
	double ys = 0;
	
	if ( point[direction.first] == max) {
		xs = 3*3600 * cos(direction.second);
		ys = 3*3600 * sin(direction.second);
	}
	
	poly->push_back(PaperPoint(pos + xs , ys ));	
	poly->push_back(PaperPoint(pos + xs + x1, ys + y1));
	poly->push_back(PaperPoint(pos + xs + x, ys + y));
	poly->push_back(PaperPoint(pos + xs + x2, ys + y2));
	poly->push_back(PaperPoint(pos + xs, ys));	
	
	poly->setFilled(true);
	poly->setShading(new FillShadingProperties());
	
	visitor.push_back(poly);

    if ( int(point[direction.first]/2) < 5 ) return;
    Text* text = new Text();
	MagFont font("sansserif", "normal", 0.25);
	font.colour(Colour("Rgb(0.2, 0.2, 0.2)"));
	text->setFont(font);
	text->setText( tostring(int(point[direction.first]/2)) );
		
		text->push_back(PaperPoint(pos + 11*3600 * cos(direction.second), 11.5*3600 * sin(direction.second)));
		visitor.push_back(text);
		
    
}

void triangle3(const Colour& colour, const Colour& border, const pair<string, float>& direction, CustomisedPoint& point, BasicGraphicsObjectContainer& visitor, double pos, double max)
{
    
    Hsl hsl = colour.hsl();
    
    float light = hsl.light_;
   
    hsl.light_ += (0.99 - light)*((point["total"]- point[direction.first])/point["total"]);
     
	
	double shift = 3.14*0.125;
	
	Polyline* poly = new Polyline();
	poly->setThickness(1);
	
	
	poly->setFillColour(Colour(hsl));	
	poly->setColour(border);
	
	double length =  (point[direction.first]*(12*3600)/max);
	double x0 = length;
//	double y0 = 0;
//	double a = length *tan(shift);
//	double b = length *tan(-shift);
	
	double x = x0 * cos(direction.second);
	double y = x0 * sin(direction.second);
	double x1 = x0 * cos(direction.second - shift);
	double y1 = x0 * sin(direction.second - shift);
	double x2 = x0 * cos(direction.second + shift);
	double y2 = x0 * sin(direction.second + shift);
	
	double xs = 0;
	double ys = 0;
	
	
	poly->push_back(PaperPoint(pos + xs , ys ));	
	poly->push_back(PaperPoint(pos + xs + x1, ys + y1));
	poly->push_back(PaperPoint(pos + xs + x, ys + y));
	poly->push_back(PaperPoint(pos + xs + x2, ys + y2));
	poly->push_back(PaperPoint(pos + xs, ys));	
	
	poly->setFilled(true);
	poly->setShading(new FillShadingProperties());
	
	visitor.push_back(poly);

    if ( int(point[direction.first]/2) < 5 ) return;
    Text* text = new Text();
	MagFont font("sansserif", "normal", 0.25);
	font.colour(Colour("Rgb(0.2, 0.2, 0.2)"));
	text->setFont(font);
	text->setText( tostring(int(point[direction.first]/2)) );
		
		text->push_back(PaperPoint(pos + 11*3600 * cos(direction.second), 11.5*3600 * sin(direction.second)));
		visitor.push_back(text);
		
    
}

void EpsCloud::triangle(const pair<string, float>& direction, CustomisedPoint& point, BasicGraphicsObjectContainer& visitor, double pos)
{
    
	 Hsl hsl = colour_->hsl();
    
    float light = hsl.light_;
   
    hsl.light_ += (0.99 - light)*((100- point[direction.first])/100);
     
	
	double shift = 3.14*0.125;
	
	Polyline* poly = new Polyline();
	poly->setStroke(true);
	
	
	poly->setFillColour(Colour(hsl));	
	poly->setColour(Colour(hsl));
	
	double x0= 12*3600;
	
	
	double x = x0 * cos(direction.second);
	double y = x0 * sin(direction.second);
	double x1 = x0 * cos(direction.second - shift);
	double y1 = x0 * sin(direction.second - shift);
	double x2 = x0 * cos(direction.second + shift);
	double y2 = x0 * sin(direction.second + shift);
	
	double xs = 0;
	double ys = 0;
	
	
	poly->push_back(PaperPoint(pos + xs , ys ));	
	poly->push_back(PaperPoint(pos + xs + x1, ys + y1));
	poly->push_back(PaperPoint(pos + xs + x, ys + y));
	poly->push_back(PaperPoint(pos + xs + x2, ys + y2));
	poly->push_back(PaperPoint(pos + xs, ys));	
	
	poly->setFilled(true);
	poly->setShading(new FillShadingProperties());
	
	visitor.push_back(poly);

	
    
}




void triangle(const pair<string, float>& direction, CustomisedPoint& point, BasicGraphicsObjectContainer& visitor, double pos, double)
{

	if ( !point[direction.first] ) return; 
	double shift = 3.14*0.125;
	
	//cvisitor << "Triangle---->" << direction.first << "=" << point[direction.first] << " " << scale << endl;
	Polyline* poly = new Polyline();

	poly->setThickness(2);
	poly->setFillColour(Colour("Rgb(0.7, 0.7, 0.7)"));	
		poly->setColour(Colour("Rgb(0.5, 0.5, 0.5)"));
	
	double length = point[direction.first];
	
	if ( length > 100) 
		length = ((3 * length /100 ) + 6 )*3600;
	else 
		if ( length >  50 )
			length = ((3 *length/50) + 3 ) *3600;
		else
			length = (6*length/50) *3600;
	
		

	double x0 = length;

	
	double x = x0 * cos(direction.second);
	double y = x0 * sin(direction.second);
	double x1 = x0 * cos(direction.second - shift);
	double y1 = x0 * sin(direction.second - shift);
	double x2 = x0 * cos(direction.second + shift);
	double y2 = x0 * sin(direction.second + shift);
	
	poly->push_back(PaperPoint(pos, 0));	
	poly->push_back(PaperPoint(pos + x1, y1));
	poly->push_back(PaperPoint(pos + x, y));
	poly->push_back(PaperPoint(pos + x2, y2));
	poly->push_back(PaperPoint(pos, 0));	
	
	poly->setFilled(true);
	poly->setShading(new FillShadingProperties());
	
	Polyline* median = new Polyline();
	median->setColour(Colour("black"));
	median->setThickness(1);
	median->push_back(PaperPoint(pos, 0));	
	median->push_back(PaperPoint(pos+x, y));	
	
	
	visitor.push_back(poly);
	
    
}


void EpsWind::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{ 
	CustomisedPointsList points; 
	std::set<string> request;

	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!

	if (points.empty()) return;
	

	

	
	
	DateTime base = points.front()->base();

	
    
	
	
	map<string, float> directions;
	if ( magCompare(convention_, "oceanographic" ) ) {
		directions["east"] = 0 + 3.14;
		directions["nord"] = 3.14 * 0.5 +3.14;
		directions["nord_east"] = 3.14*0.25  +3.14;
		directions["nord_west"] = 3.14*0.75 +3.14;
		directions["south"] = 3.14*1.5 +3.14;
		directions["south_east"] = 3.14*1.75 +3.14;
		directions["south_west"] = 3.14*1.25 +3.14;
		directions["west"] = 3.14 +3.14;
	}
	else {
		directions["east"] = 0;
		directions["nord"] = 3.14 * 0.5;
		directions["nord_east"] = 3.14*0.25;
		directions["nord_west"] = 3.14*0.75;
		directions["south"] = 3.14*1.5;
		directions["south_east"] = 3.14*1.75;
		directions["south_west"] = 3.14*1.25;
		directions["west"] = 3.14;
	}
	
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {		
		double total = 0;
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction) {
			
			if ( (*point)->find(direction->first) == (*point)->end() ) {
				vector<string> classification;
				classification.push_back("one");
				classification.push_back("two");
				classification.push_back("three");
				classification.push_back("four");
				classification.push_back("five");
				classification.push_back("six");
				double val = 0;
				for ( vector<string>::const_iterator key = classification.begin(); key != classification.end(); ++key) {
					CustomisedPoint::const_iterator value = (*point)->find(direction->first + "_" + *key);
					if ( value != (*point)->end() ) 
						val += ( value->second == 9999.) ? 0 :  value->second;
				}			
				(**point)[direction->first] = val;
				
				
			}
			total += (**point)[direction->first];
		}
		(**point)["total"] = total;
		
		
		//InteractiveSet* iset = new InteractiveSet();
		//iset->addAction("onmouseover", new InteractiveMagnify(4));
		vector<double> values;
		double scale = 0;	
	    
		
    
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction)
			values.push_back((**point)[direction->first]);
			
		double ms = *std::max_element(values.begin(), values.end());
		double x = (**point)["step"] + (**point)["shift"];
	
		
			Polyline* grid = new Polyline();
			grid->setColour(Colour("grey"));
			grid->setThickness(2);
			grid->setLineStyle(M_DOT);		
			scale = 200;
			double l100 = 12*3600;
			for (float angle = 0; angle <= 2; angle+=0.1) 	
				grid->push_back(PaperPoint(x +(l100 * cos(3.14*angle)) , l100 * sin(3.14*angle)));					
			//iset->push_back(grid);
			
		
		


		visitor.push_back(grid);
		
		
		
	
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction)
				triangle(*direction, **point, visitor, x, ms);
		
	}
	

}

void EpsWave::visit(LegendVisitor& legend)
{
	MagFont font("sansserif", "normal", 0.25);
	font.colour(Colour("Rgb(0.2, 0.2, 0.2)"));
	vector<Colour> colours;
	colours.push_back(Colour("greenish_blue"));
	colours.push_back(Colour("yellow_green"));
	colours.push_back(Colour("greenish_yellow"));
	colours.push_back(Colour("orangish_yellow"));
	colours.push_back(Colour("yellowish_orange"));
	colours.push_back(Colour("reddish_orange"));
	
	WaveRoseEntry* wave = new WaveRoseEntry(colours);
	wave->borderColour(Colour("grey"));		
	wave->font(font);
		
	legend.add(wave);
}

void EpsWind::visit(LegendVisitor& legend)
{
	if ( !legend_ ) return;
	MagFont font("sansserif", "normal", 0.25);
	font.colour(Colour("Rgb(0.2, 0.2, 0.2)"));
	
       WindRoseEntry* wind = new WindRoseEntry(*colour_);
		
		
		
		
		wind->borderColour(*border_colour_);		
		wind->font(font);
		
		legend.add(wind);
    
}
void EpsCloud::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{ 
	CustomisedPointsList points; 
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!

	map<string, float> directions;
	
				directions["1"] = 3.14 * 3/8;
				directions["2"] = 3.14 * 1/8;
				directions["3"] =  -3.14*1/8;
				directions["4"] = -3.14* 3/8;
				directions["5"] = -3.14* 5/8;
				directions["6"] = -3.14* 7/8.;
				directions["7"] = -3.14 *9/8;
				directions["8"] =-3.14 *11/8; ;
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {	

		(**point)["total"] = 100;
		double x = (**point)["step"] + (**point)["shift"];
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction)
				triangle(*direction, **point, visitor, x);
	
	Polyline* grid = new Polyline();
				grid->setColour(Colour("grey"));
				grid->setThickness(2);
				grid->setLineStyle(M_DOT);		
			
				double l100 = 12*3600;
				for (float angle = 0; angle <= 2; angle+=0.1) 	
					grid->push_back(PaperPoint(x +(l100 * cos(3.14*angle)) , l100 * sin(3.14*angle)));					
			
					visitor.push_back(grid);
	}		
			


		
}

void EpsBar::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{
	CustomisedPointsList points;
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!

	map<string, float> directions;

				directions["1"] = 1;
				directions["2"] = 2;
				directions["3"] = 3;
				directions["4"] = 4;
				directions["5"] = 5;
				directions["6"] = 6;
				directions["7"] = 7;
				directions["8"] = 8;
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {

		(**point)["total"] = 100;
		double x = (**point)["step"] + (**point)["shift"];
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction) {
			 Hsl hsl = colour_->hsl();
			 float light = hsl.light_;
			 hsl.light_ += (0.99 - light)*((100- (**point)[direction->first])/100);
			 Polyline* poly = new Polyline();
			 poly->setThickness(1);
			 poly->setFillColour(Colour(hsl));
			 poly->setColour(Colour(hsl));
			 x = x*3600;
			 double width = 3 * 3600;
			 poly->push_back(PaperPoint(x-width, direction->second-1));
			 poly->push_back(PaperPoint(x+width, direction->second-1));
			 poly->push_back(PaperPoint(x+width, direction->second));
			 poly->push_back(PaperPoint(x-width, direction->second));
			 poly->push_back(PaperPoint(x-width, direction->second-1));
			 visitor.push_back(poly);

		}
	}





}

void EpsBar::visit(LegendVisitor& legend)
{

	MagLog::dev() << " EpsBar::visit(LegendVisitor&) --> to be implemented! " << endl;
}

void EpsCloud::visit(LegendVisitor& legend)
{
	
	MagFont font("sansserif", "normal", 0.25);
	font.colour(Colour("Rgb(0.2, 0.2, 0.2)"));
	
       WindRoseEntry* wind = new WindRoseEntry(*colour_);
		
		
		
		
		wind->borderColour(*border_colour_);		
		wind->font(font);
		
		legend.add(wind);
    
}
void EpsWind::print(ostream&) const
{
}
void EpsCloud::print(ostream&) const
{
}
void EpsBar::print(ostream&) const
{
}
void EpsWave::print(ostream&) const
{
}

void triangle5(const pair<string, float>& direction, CustomisedPoint& point, BasicGraphicsObjectContainer& visitor, double pos, double max)
{
	
	vector<Colour> colours;
	colours.push_back(Colour("greenish_blue"));
	colours.push_back(Colour("yellow_green"));
	colours.push_back(Colour("greenish_yellow"));
	colours.push_back(Colour("orangish_yellow"));
	colours.push_back(Colour("yellowish_orange"));
	colours.push_back(Colour("reddish_orange"));
	
	vector<string> forces;
	forces.push_back(direction.first + "_one");
	forces.push_back(direction.first + "_two");
	forces.push_back(direction.first + "_three");
	forces.push_back(direction.first + "_four");
	forces.push_back(direction.first + "_five");
	forces.push_back(direction.first + "_six");
	double total = 0;
	Polyline* poly;
	vector<Colour>::iterator colour = colours.begin();
	Colour border("grey");
	
	double r = 12*3600;
	double factor = r*r/max;
	
	double previous = 0;
	double shift = 3.14*0.125;
	
	for (vector<string>::const_iterator force = forces.begin(); force != forces.end(); ++ force) {
		double count =  point[*force];
		if ( !count ) {
			colour++; 
			continue;
		}
		
	    poly = new Polyline();
	    poly->setThickness(1);
		poly->setFillColour(*colour);	
	    poly->setColour(border);
		
		total += count;	    
		double length =  sqrt(total*factor);
		double x0 = length;
		
	
		double x = x0 * cos(direction.second);
		double y = x0 * sin(direction.second);
		double x1 = x0 * cos(direction.second - shift);
		double y1 = x0 * sin(direction.second - shift);
		double x2 = x0 * cos(direction.second + shift);
		double y2 = x0 * sin(direction.second + shift);
	   
	    double px = previous * cos(direction.second);
		double py = previous * sin(direction.second);
		double px1 = previous * cos(direction.second - shift);
		double py1 = previous * sin(direction.second - shift);
		double px2 = previous * cos(direction.second + shift);
		double py2 = previous * sin(direction.second + shift);
		
		previous = x0;
        colour++;
	
	    
	
		poly->push_back(PaperPoint(pos + px1 , py1 ));	
		poly->push_back(PaperPoint(pos + x1,  y1));
		poly->push_back(PaperPoint(pos + x,  y));
		poly->push_back(PaperPoint(pos +  x2,  y2));
		poly->push_back(PaperPoint(pos + px2, py2));
		poly->push_back(PaperPoint(pos + px, py));	
		poly->push_back(PaperPoint(pos + px1, py1));	
	
		poly->setFilled(true);
		poly->setShading(new FillShadingProperties());
	
		visitor.push_back(poly);
	}
	
	

        
	
}

void EpsWave::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{ 
	CustomisedPointsList points; 
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!

	if (points.empty()) return;
	

	vector<double> xpos;
	

	
	
	DateTime base = points.front()->base();

	 for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {  	
		xpos.push_back((**point)["last"]);		  
    }
    
	
	
	map<string, float> directions;
	//if ( magCompare(convention_, "oceanographic" ) ) {
		directions["east"] = 0 + 3.14;
		directions["nord"] = 3.14 * 0.5 +3.14;
		directions["nord_east"] = 3.14*0.25  +3.14;
		directions["nord_west"] = 3.14*0.75 +3.14;
		directions["south"] = 3.14*1.5 +3.14;
		directions["south_east"] = 3.14*1.75 +3.14;
		directions["south_west"] = 3.14*1.25 +3.14;
		directions["west"] = 3.14 +3.14;
//	}
//	else {
//		directions["east"] = 0;
//		directions["nord"] = 3.14 * 0.5;
//		directions["nord_east"] = 3.14*0.25;
//		directions["nord_west"] = 3.14*0.75;
//		directions["svisitorh"] = 3.14*1.5;
//		directions["svisitorh_east"] = 3.14*1.75;
//		directions["svisitorh_west"] = 3.14*1.25;
//		directions["west"] = 3.14;
//	}
	
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {		
		double total = 0;
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction) {
			
			if ( (*point)->find(direction->first) == (*point)->end() ) {
				vector<string> classification;
				classification.push_back("one");
				classification.push_back("two");
				classification.push_back("three");
				classification.push_back("four");
				classification.push_back("five");
				classification.push_back("six");
				double val = 0;
				for ( vector<string>::const_iterator key = classification.begin(); key != classification.end(); ++key) {
					CustomisedPoint::const_iterator value = (*point)->find(direction->first + "_" + *key);
					if ( value != (*point)->end() ) 
						val += (value->second == 9999) ? 0 : value->second;
				}			
				(**point)[direction->first] = val;
				
			}
			total += (**point)[direction->first];
		}
		(**point)["total"] = (total) ? total : 50;
		
		
		//InteractiveSet* iset = new InteractiveSet();
		//iset->addAction("onmouseover", new InteractiveMagnify(4));
		vector<double> values;
		double scale = 0;	
	    
		
    
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction)
			values.push_back((**point)[direction->first]);
			
		double ms = *std::max_element(values.begin(), values.end());
		double x = (**point)["step"] + (**point)["shift"];
	
		
			Polyline* grid = new Polyline();
			grid->setColour(Colour("grey"));
			grid->setThickness(2);
			grid->setLineStyle(M_DOT);		
			scale = 200;
			double l100 = 12*3600;
			for (float angle = 0; angle <= 2; angle+=0.1) 	
				grid->push_back(PaperPoint(x +(l100 * cos(3.14*angle)) , l100 * sin(3.14*angle)));					
				visitor.push_back(grid);
			
	
		

		//visitor.push_back(iset);
		
		
		if (total == 0) continue;
	
		for ( map<string, float>::const_iterator direction = directions.begin(); direction != directions.end(); ++direction)
			{
				triangle5(*direction, **point, visitor, x, ms);
			}
	}
	

}




CdfGraph::CdfGraph() 
{
}

CdfGraph::~CdfGraph()
{
}
void CdfGraph::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{

	
	CustomisedPointsList points; 
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!
	
	//visitor << "CdfGraph::preparePlot(Data<PaperPoint>& data, visitor&)" << endl;
	
	if (points.empty()) return;
	
	vector<string>::iterator icolour = colour_.begin();
    // First make sure that we have enough colour/style/thicknes
    
    while (style_.size() < colour_.size()) 
        style_.push_back("solid");
    while (thickness_.size() < colour_.size()) 
        thickness_.push_back(2);    
    
	
	
    // First set some defaults!
	



    
    	
    	
    	Polyline* efi  = new Polyline();
	    efi->setColour(*clim_colour_);
	    efi->setLineStyle(clim_style_);
	    efi->setThickness(clim_thickness_);
	    vector<double> clim;
		for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {		
			
			vector<double> steps;
			for ( int i = 0; i <=100; i++) {		    
				ostringstream key;
				key << "clim_" << i;
				map<string, double>::const_iterator step = (*point)->find(key.str());
				if (step != (*point)->end() ) {
                    MagLog::dev() << key.str() << ":" << step->second << "-->" << i << endl;
					efi->push_back(PaperPoint(step->second, i));
					clim.push_back(step->second);
                }
			}			
		
		}
		
		visitor.push_back(efi);
		

		Polyline* box = new Polyline();
		box->setColour(Colour("navy"));
		box->setFilled(true);      
		box->setFillColour(Colour("white"));      
			
		FillShadingProperties* shading = new FillShadingProperties();          

		box->setShading(shading);
		
		double w = 1.5*( transformation.getMaxX() - transformation.getMinX() )/ visitor.absoluteWidth();
		
		box->push_back(PaperPoint(transformation.getMaxX(), 43));
		box->push_back(PaperPoint(transformation.getMaxX()-w, 43));
		box->push_back(PaperPoint(transformation.getMaxX()-w, 57));
		box->push_back(PaperPoint(transformation.getMaxX(), 57));
		box->push_back(PaperPoint(transformation.getMaxX(), 43));
		
		
		
		Text* mint = new Text();
		mint->setJustification(MLEFT);		
		mint->push_back(PaperPoint(transformation.getMaxX()-(w*.95), 46));
		
		Text* maxt = new Text();
		maxt->push_back(PaperPoint(transformation.getMaxX()-(w*0.95), 52));
		maxt->setJustification(MLEFT);
		
		if ( !clim.empty() ) {
			vector<double>::const_iterator min = std::min_element(clim.begin(), clim.end());
			vector<double>::const_iterator max = std::max_element(clim.begin(), clim.end());
			maxt->addText("Max: " +  tostring(maground(*max)) , Colour("navy"), 0.3);
			mint->addText("Min : " +  tostring(maground(*min)) , Colour("navy"), 0.3);
		}
		else {
			maxt->addText("Max: ?" , Colour("navy"), 0.3);
			mint->addText( "Min : ?", Colour("navy"), 0.3);
		}
        
		
	vector<string>::iterator style = style_.begin();
	vector<int>::iterator thickness = thickness_.begin();
   
	vector<BasicGraphicsObject*> sorter;
	int step = 1;
    while ( icolour != colour_.end() ) {
    	Colour colour(*icolour);
      
    	
    
    	
    	Polyline* efi  = new Polyline();
	    efi->setColour(colour);
	    efi->setLineStyle(MagTranslator<string, LineStyle>()(*style));
	    efi->setThickness(*thickness);
	    ++thickness;
        ++style;
		for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {		
			
			vector<double> steps;
			for ( int i = 0; i <=100; i++) {		    
				ostringstream key;
				key << step << "_" << i;
				map<string, double>::const_iterator step = (*point)->find(key.str());
				if (step != (*point)->end() ) {
                    MagLog::dev() << key.str() << ":" << step->second << "-->" << i << endl;
					efi->push_back(PaperPoint(step->second, i));
                }
			}	
			ostringstream key;
			key << step << "_step";
			map<string, double>::const_iterator info = (*point)->find(key.str());
			int s = info->second;
			ostringstream legend;
			legend << "Eps t+ [" << s - 24 << "-" << s <<"h] " ;
			legend_.push_back(legend.str());
			
		}
		
		if ( !efi->empty() ) {		
			sorter.push_back(efi);
			usedColours_.push_back(*icolour);
		}
		else 
			delete efi;
		
	
		// go to next step!
		    ++icolour;
		    step++;
		}
    
    // Here we revert the curve to have the fisrt plotted last! 
        for ( vector<BasicGraphicsObject*>::reverse_iterator object = sorter.rbegin(); object != sorter.rend(); ++object) 
        	visitor.push_back(*object);
            
//        visitor.push_back(box);
//		visitor.push_back(mint);
//		visitor.push_back(maxt);/

}


void CdfGraph::visit(LegendVisitor& legend)

{

	
	vector<string>::reverse_iterator style = style_.rbegin();
	vector<int>::reverse_iterator thickness = thickness_.rbegin();
	vector<string>::reverse_iterator text = legend_.rbegin();
    
   
	for (vector<string>::reverse_iterator colour = usedColours_.rbegin(); colour != usedColours_.rend(); ++colour) {
		Polyline* efi  = new Polyline();
		efi->setColour(Colour(*colour));
		
       
        efi->setLineStyle(MagTranslator<string, LineStyle>()(*style));
		efi->setThickness(*thickness);
		LineEntry* entry = new LineEntry(*text, efi);

		legend.add(entry);
        ++thickness;
        ++style;
        ++text;
	}
	 Polyline* efi  = new Polyline();
			efi->setColour(*clim_colour_);
			efi->setLineStyle(clim_style_);
			efi->setThickness(clim_thickness_);
			LineEntry* entry = new LineEntry("Climate t+[24-48h]", efi);
			
			legend.add(entry);    

}

void EpsShade::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{
	CustomisedPointsList points; 
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!
	
	if (points.empty()) return;

    
	Polyline* first  = new Polyline();	
	first->setLineStyle(line_style_);
	first->setThickness(line_thickness_);
	first->setFilled(true);
	first->setShading(new FillShadingProperties());
    
    Polyline* firstmin = first->getNew();
    Polyline* firstmax = first->getNew();
    
    Colour cmin = Colour("sky");
    Colour cmax = Colour("RGB(1.0, 0.222, 0.222)");
    
    Polyline* second  = new Polyline();
	
	second->setLineStyle(line_style_);
	second->setThickness(line_thickness_);
	second->setFilled(true);
	second->setShading(new FillShadingProperties());
	Polyline* secondmin = second->getNew();
    Polyline* secondmax = second->getNew();
    
    
	Polyline* median  = new Polyline();
	median->setLineStyle(line_style_);
	median->setThickness(line_thickness_);
    
    Polyline* medianmin = median->getNew();
    Polyline* medianmax = median->getNew();
   
	Polyline* backtop  = new Polyline();
	//backtop->setLineStyle(M_DASH);
	backtop->setThickness(2);
    backtop->setColour(*colour_);
    Polyline* backtopmin = backtop->getNew();
    Polyline* backtopmax = backtop->getNew();
    backtopmin->setColour(cmin);
    backtopmax->setColour(cmax);
   
    Polyline* backbottom  = new Polyline();
	//backbottom->setLineStyle(M_DOT);
	backbottom->setThickness(2);
    backbottom->setColour(*colour_);
    
    Polyline* backbottommin = backbottom->getNew();
    Polyline* backbottommax = backbottom->getNew();
    
    backbottommin->setColour(cmin);
    backbottommax->setColour(cmax);
    
    Hsl hsl = colour_->hsl();  
    Hsl hslmin = cmin.hsl(); 
    Hsl hslmax = cmax.hsl(); 
    
    float step = (0.9 - hsl.light_)/3.;
    median->setColour(Colour(hsl));
    medianmin->setColour(Colour(hslmin));
    medianmax->setColour(Colour(hslmax));
    
    hsl.light_ += 2*step;     
    hslmin.light_ += 2*step; 
    hslmax.light_ += 2*step; 
    second->setFillColour(Colour(hsl));
    second->setColour(Colour(hsl));
    secondmin->setFillColour(Colour(hslmin));
    secondmin->setColour(Colour(hslmin));
    secondmax->setFillColour(Colour(hslmax));
    secondmax->setColour(Colour(hslmax));
    
    hsl.light_ += step;
    hslmin.light_ += step; 
    hslmax.light_ += step; 
    first->setFillColour(Colour(hsl));   
    first->setColour(Colour(hsl));
    firstmin->setFillColour(Colour(hslmin));   
    firstmin->setColour(Colour(hslmin));
    firstmax->setFillColour(Colour(hslmax));   
    firstmax->setColour(Colour(hslmax));
    
	
	
		

	DateTime base = points.front()->base();
   
    
    
    
    
	vector<PaperPoint> ten, tenmin, tenmax;
	vector<PaperPoint> ninty, nintymin, nintymax;;
	vector<PaperPoint> twentyfive, twentyfivemin, twentyfivemax;
	vector<PaperPoint> seventyfive, seventyfivemin, seventyfivemax;
    vector<PaperPoint> one, onemin, onemax;
	vector<PaperPoint> ninetynine, ninetyninemin, ninetyninemax;
    
    
    
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {
		
		double x = (**point)["step"];
		
        
		
		CustomisedPoint::const_iterator y1 = (*point)->find("1");       
		CustomisedPoint::const_iterator y10 = (*point)->find("10");
        CustomisedPoint::const_iterator y90 = (*point)->find("90");
        CustomisedPoint::const_iterator y99 = (*point)->find("99");  
		CustomisedPoint::const_iterator y50 = (*point)->find("50");
		CustomisedPoint::const_iterator y25 = (*point)->find("25");
		CustomisedPoint::const_iterator y75 = (*point)->find("75");
        if ( (**point)["tmin"] ) {		
            tenmin.push_back(PaperPoint(x, y10->second));
		    nintymin.push_back(PaperPoint(x, y90->second));
		    twentyfivemin.push_back(PaperPoint(x, y25->second));
		    seventyfivemin.push_back(PaperPoint(x, y75->second));
		    medianmin->push_back(PaperPoint(x, y50->second));
            onemin.push_back(PaperPoint(x, y1->second));
            ninetyninemin.push_back(PaperPoint(x, y99->second));
        }
        else if ( (**point)["tmax"] ) {
            tenmax.push_back(PaperPoint(x, y10->second));
		    nintymax.push_back(PaperPoint(x, y90->second));
		    twentyfivemax.push_back(PaperPoint(x, y25->second));
		    seventyfivemax.push_back(PaperPoint(x, y75->second));
		    medianmax->push_back(PaperPoint(x, y50->second));
            onemax.push_back(PaperPoint(x, y1->second));
            ninetyninemax.push_back(PaperPoint(x, y99->second));
        }
        else {
            ten.push_back(PaperPoint(x, y10->second));
		    ninty.push_back(PaperPoint(x, y90->second));
		    twentyfive.push_back(PaperPoint(x, y25->second));
		    seventyfive.push_back(PaperPoint(x, y75->second));
		    median->push_back(PaperPoint(x, y50->second));
            one.push_back(PaperPoint(x, y1->second));
            ninetynine.push_back(PaperPoint(x, y99->second));
        }
     }
        
     
	
     for (vector<PaperPoint>::iterator point = one.begin(); point != one.end(); ++point) 
     	backbottom->push_back(*point); 
     for (vector<PaperPoint>::reverse_iterator point = ninetynine.rbegin(); point != ninetynine.rend(); ++point)
     	backtop->push_back(*point);
     for (vector<PaperPoint>::iterator point = ten.begin(); point != ten.end(); ++point)
     	first->push_back(*point);
     for (vector<PaperPoint>::reverse_iterator point = ninty.rbegin(); point != ninty.rend(); ++point)
     	first->push_back(*point);     
     if ( !first->empty() )
        first->push_back(first->front());      
	 for (vector<PaperPoint>::iterator point = twentyfive.begin(); point != twentyfive.end(); ++point)
     	second->push_back(*point);
     for (vector<PaperPoint>::reverse_iterator point = seventyfive.rbegin(); point != seventyfive.rend(); ++point)
     	second->push_back(*point);     	
     if ( !second->empty() )
        second->push_back(second->front());
     
     for (vector<PaperPoint>::iterator point = onemin.begin(); point != onemin.end(); ++point) 
     	backbottommin->push_back(*point); 
     for (vector<PaperPoint>::reverse_iterator point = ninetyninemin.rbegin(); point != ninetyninemin.rend(); ++point)
     	backtopmin->push_back(*point);
     for (vector<PaperPoint>::iterator point = tenmin.begin(); point != tenmin.end(); ++point)
     	firstmin->push_back(*point);
     for (vector<PaperPoint>::reverse_iterator point = nintymin.rbegin(); point != nintymin.rend(); ++point)
     	firstmin->push_back(*point);     
     if ( !firstmin->empty() ) 
        firstmin->push_back(firstmin->front());      
	 for (vector<PaperPoint>::iterator point = twentyfivemin.begin(); point != twentyfivemin.end(); ++point)
     	secondmin->push_back(*point);
     for (vector<PaperPoint>::reverse_iterator point = seventyfivemin.rbegin(); point != seventyfivemin.rend(); ++point)
     	secondmin->push_back(*point);     	
     if ( !secondmin->empty() )
        secondmin->push_back(secondmin->front());
     
     for (vector<PaperPoint>::iterator point = onemax.begin(); point != onemax.end(); ++point) 
     	backbottommax->push_back(*point); 
     for (vector<PaperPoint>::reverse_iterator point = ninetyninemax.rbegin(); point != ninetyninemax.rend(); ++point)
     	backtopmax->push_back(*point);
     for (vector<PaperPoint>::iterator point = tenmax.begin(); point != tenmax.end(); ++point)
     	firstmax->push_back(*point);
     for (vector<PaperPoint>::reverse_iterator point = nintymax.rbegin(); point != nintymax.rend(); ++point)
     	firstmax->push_back(*point);     
     if ( !firstmax->empty() ) 
        firstmax->push_back(firstmax->front());      
	 for (vector<PaperPoint>::iterator point = twentyfivemax.begin(); point != twentyfivemax.end(); ++point)
     	secondmax->push_back(*point);
     for (vector<PaperPoint>::reverse_iterator point = seventyfivemax.rbegin(); point != seventyfivemax.rend(); ++point)
     	secondmax->push_back(*point);     	
     if ( !secondmax->empty() ) 
        secondmax->push_back(secondmax->front());
     
   
   
    if ( !first->empty() ) visitor.push_back(first);
	if ( !second->empty() ) visitor.push_back(second);
	
    if ( !firstmin->empty() ) visitor.push_back(firstmin);
	if ( !secondmin->empty() ) visitor.push_back(secondmin);
    
	
    if ( !firstmax->empty() ) visitor.push_back(firstmax);
	if ( !secondmax->empty() ) visitor.push_back(secondmax);
    
	if ( !median->empty() ) visitor.push_back(median);
    if ( !medianmin->empty() ) visitor.push_back(medianmin);
    if ( !medianmax->empty() ) visitor.push_back(medianmax);
    
    if ( !backbottom->empty() ) visitor.push_back(backbottom);
    if ( !backtop->empty() ) visitor.push_back(backtop);
    if ( !backbottommin->empty() ) visitor.push_back(backbottommin);
    if ( !backtopmin->empty() ) visitor.push_back(backtopmin);
    if ( !backbottommax->empty() ) visitor.push_back(backbottommax);
    if ( !backtopmax->empty() ) visitor.push_back(backtopmax);
    
	
}
class EpsShadeEntry : public LegendEntry
{
public:
	EpsShadeEntry() : LegendEntry(" ")
	{
		
	}
		
	void set(const PaperPoint& point, BasicGraphicsObjectContainer& visitor)
	{
        if (!first_) return;
		
        first_ = false;
        double x = point.x();
		double y = point.y();
        
      
        double height1=0.6;
        double height2=0.4;
        double height3=0.2;
        double width = 0.4;
        double xtext= x+0.7;
        
        
		
	
		
        Colour colour("grey");
        Polyline* median  = new Polyline();
		median->setColour(colour);		
		median->setLineStyle(M_SOLID);
		median->setThickness(4);
		median->push_back(PaperPoint(x-width, y));
		median->push_back(PaperPoint(x+width, y));
        
        Polyline* top  = new Polyline();
		top->setColour(colour);		
		top->setLineStyle(M_DASH);
		top->setThickness(2);
		top->push_back(PaperPoint(x-width, y+height1));
		top->push_back(PaperPoint(x+width, y+height1));
        
        Polyline* bottom  = new Polyline();
		bottom->setColour(colour);		
		bottom->setLineStyle(M_DASH);
		bottom->setThickness(2);
        bottom->push_back(PaperPoint(x-width, y-height1));
		bottom->push_back(PaperPoint(x+width, y-height1));
        
        Hsl hsl = colour.hsl();
        float step = (0.9 - hsl.light_)/3.;
        
       
        hsl.light_ += 2*step;
        
        Polyline* second  = new Polyline();       
	    second->setFilled(true);
	    second->setShading(new FillShadingProperties());
        second->setFillColour(Colour(hsl));
        second->setColour(Colour(hsl));
        second->push_back(PaperPoint(x-width, y-height3));
		second->push_back(PaperPoint(x+width, y-height3));
        second->push_back(PaperPoint(x+width, y+height3));
		second->push_back(PaperPoint(x-width, y+height3));
        
        hsl.light_ += step;
        
        Polyline* first  = new Polyline();       
	    first->setFilled(true);
	    first->setShading(new FillShadingProperties());
        first->setFillColour(Colour(hsl));
        first->setColour(Colour(hsl));
        first->push_back(PaperPoint(x-width, y-height2));
		first->push_back(PaperPoint(x+width, y-height2));
        first->push_back(PaperPoint(x+width, y+height2));
		first->push_back(PaperPoint(x-width, y+height2));
        
    
    
	
	   
   
	
		
        visitor.push_back(first);
        visitor.push_back(second);
        
		visitor.push_back(top);
        visitor.push_back(bottom);
		visitor.push_back(median);
        
        Text* text  = new Text();
		text->setText("M-Climate");
        text->setFont(font_);
		
		text->push_back(PaperPoint(x+0.4, y-0.8));
		visitor.push_back(text);
        
        Text* text99  = new Text();
		text99->setText("99%");
		text99->setFont(font_);
		text99->setJustification(MLEFT);
		text99->push_back(PaperPoint(xtext, y-height1));
		visitor.push_back(text99);  
        
        Text* text90  = new Text();
		text90->setText("90%");
		text90->setFont(font_);
		text90->setJustification(MLEFT);
		text90->push_back(PaperPoint(xtext, y-height2));
		visitor.push_back(text90);
        
        Text* text75  = new Text();
		text75->setText("75%");
		text75->setFont(font_);
		text75->setJustification(MLEFT);
		text75->push_back(PaperPoint(xtext, y-height3));
		visitor.push_back(text75);
        
		Text* text50  = new Text();
		text50->setText("median");
		text50->setFont(font_);
		text50->setJustification(MLEFT);
		text50->push_back(PaperPoint(xtext, y));
		visitor.push_back(text50);
        
        Text* text25  = new Text();
		text25->setText("25%");
		text25->setFont(font_);
		
		text25->setJustification(MLEFT);
		text25->push_back(PaperPoint(xtext, y+height3));
		visitor.push_back(text25);
        
        Text* text10  = new Text();
		text10->setText("10%");
		text10->setFont(font_);
	
		text10->setJustification(MLEFT);
		text10->push_back(PaperPoint(xtext, y+height2));
		visitor.push_back(text10);
        
        Text* text1  = new Text();
		text1->setText("1%");
        text1->setFont(font_);
	
		text1->setJustification(MLEFT);
		text1->push_back(PaperPoint(xtext, y+height1));
		visitor.push_back(text1);
      
	}
    
    MagFont font_;
	
protected:
	static bool first_;
};

bool EpsShadeEntry::first_ = true;

void EpsShade::visit(LegendVisitor& legend)
{
    EpsShadeEntry *entry = new EpsShadeEntry();
    entry->font_ = MagFont("sansserif");
    entry->font_.size(0.4);
    entry->font_.colour(legend.colour_->name());
    legend.add(entry);
}

EpsShade::EpsShade()
{
}

EpsShade::~EpsShade()
{
}

bool alldigit(const string& name)
{
	for (string::const_iterator c = name.begin(); c != name.end(); ++c)
		if ( !isdigit(*c) ) return false;
	return true;
} 

void EpsDirection::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{
    CustomisedPointsList points; 
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!

	if (points.empty()) return;
		

	DateTime base = points.front()->base();
	
	
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {		
	
        
		
		
		
		//InteractiveSet* iset = new InteractiveSet();
		//iset->addAction("onmouseover", new InteractiveMagnify(4));
			
			
		
		    double x = (**point)["step"] + (**point)["shift"];
		    
		    if ( (**point)[keyword_] == 9999 ) continue;
		    
	        double angle = ((2*3.14) - (((**point)[keyword_]-90)/180) * 3.14) + 3.14;
		
			Polyline* grid = new Polyline();
			grid->setColour(*line_colour_);
			grid->setThickness(line_thickness_);
			grid->setLineStyle(line_style_);		
			
			double l100 = 12*3600;
            grid->push_back(PaperPoint(x +(l100 * cos(angle)) , l100 * sin(angle)));	
            
            grid->push_back(PaperPoint(x, 0));	
			
            			
			visitor.push_back(grid); //iset->push_back(grid);
			
		
		

		

		//visitor.push_back(iset);
		
		
		
		
	}
	
}
void EpsWind::triangle(const pair<string, float>& direction, CustomisedPoint& point, BasicGraphicsObjectContainer& visitor, double pos, double max)
{
    
    Hsl hsl = colour_->hsl();
    
    float light = hsl.light_;
   
    hsl.light_ += (0.99 - light)*((point["total"]- point[direction.first])/point["total"]);
     
	
	double shift = 3.14*0.125;
	
	Polyline* poly = new Polyline();
	poly->setThickness(1);
	
	
	poly->setFillColour(Colour(hsl));	
	poly->setColour(*border_colour_);
	
	double r = 12*3600;
	double val = point[direction.first];
	double factor = r*r/max;
	
	
	
	double length =  sqrt(val*factor);
	double x0 = length;
//	double y0 = 0;
//	double a = length *tan(shift);
//	double b = length *tan(-shift);
	
	double x = x0 * cos(direction.second);
	double y = x0 * sin(direction.second);
	double x1 = x0 * cos(direction.second - shift);
	double y1 = x0 * sin(direction.second - shift);
	double x2 = x0 * cos(direction.second + shift);
	double y2 = x0 * sin(direction.second + shift);
	
	double xs = 0;
	double ys = 0;
	
	
	poly->push_back(PaperPoint(pos + xs , ys ));	
	poly->push_back(PaperPoint(pos + xs + x1, ys + y1));
	poly->push_back(PaperPoint(pos + xs + x, ys + y));
	poly->push_back(PaperPoint(pos + xs + x2, ys + y2));
	poly->push_back(PaperPoint(pos + xs, ys));	
	
	poly->setFilled(true);
	poly->setShading(new FillShadingProperties());
	
	visitor.push_back(poly);


   
}
EpsPlume::EpsPlume()
{
	methods_["time_serie"] = &EpsPlume::timeserie;
	methods_["vertical_profile"] = &EpsPlume::verticalprofile;
}

void EpsPlume::visit(LegendVisitor& legend)
{
	if ( shading_ )
	{
		for ( vector<Colour>::iterator entry = shading_legend_.begin(); entry != shading_legend_.end(); ++entry) {
			 Polyline* box = new Polyline();




			        	box->setShading(new FillShadingProperties());
			        box->setFillColour(*entry);
			        box->setFilled(true);
			        box->setStroke(true);
			        box->setColour(Colour("black"));
			        legend.add(new BoxEntry("", box));
		}
	}
	if ( forecast_) {
		Polyline* forecast  = new Polyline();
		forecast->setColour(*forecast_line_colour_);
		forecast->setThickness(forecast_line_thickness_);
		forecast->setLineStyle(forecast_line_style_);
		legend.add(new LineEntry("Oper", forecast));
	}
	if ( control_) {
		Polyline* control  = new Polyline();
		control->setColour(*control_line_colour_);
		control->setThickness(control_line_thickness_);
		control->setLineStyle(control_line_style_);
		legend.add(new LineEntry("Ctrl", control));
	}
	if ( line_ ) {
		Polyline* line  = new Polyline();
		line->setColour(*line_colour_);
		line->setThickness(line_thickness_);
		line->setLineStyle(line_style_);
		legend.add(new LineEntry("EMem", line));
	}
	if (median_) {
		Polyline* median  = new Polyline();
		median->setColour(*median_line_colour_);
		median->setThickness(median_line_thickness_);
		median->setLineStyle(median_line_style_);
		legend.add(new LineEntry("Median", median));
	}
}

void EpsPlume::timeserie(Data& data, BasicGraphicsObjectContainer& visitor)
{
	CustomisedPointsList points; 
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!


	if (points.empty()) return;



	map<string, Polyline* > lines;
	Polyline* control  = new Polyline();
	control->setColour(*control_line_colour_);
	control->setThickness(control_line_thickness_);
	control->setLineStyle(control_line_style_);

	Polyline* forecast  = new Polyline();
	forecast->setColour(*forecast_line_colour_);
	forecast->setThickness(forecast_line_thickness_);
	forecast->setLineStyle(forecast_line_style_);

	Polyline* median  = new Polyline();
	median->setColour(*median_line_colour_);
	median->setThickness(median_line_thickness_);
	median->setLineStyle(median_line_style_);
	map<double, vector<PaperPoint> > shading;
	if ( shading_ ) {
		for ( vector<double>::iterator level = shading_levels_.begin(); level != shading_levels_.end(); ++level)
			shading.insert(make_pair(*level, vector<PaperPoint>()));
	}
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {

		double x = (**point)["step"] + (**point)["shift"];
		double missing = (**point)["missing"];

		vector<double> members;
		for ( map<string, double>::const_iterator value = (*point)->begin(); value != (*point)->end(); ++value) {

			if ( alldigit(value->first) ) {
				if ( line_ ) {
					map<string, Polyline* >::iterator  iline = lines.find(value->first);
					if ( iline == lines.end() ) {
						Polyline* line  = new Polyline();
						line->setColour(*line_colour_);
						line->setThickness(line_thickness_);
						line->setLineStyle(line_style_);
						lines[value->first] = line;
						iline = lines.find(value->first);
					}
					if (  value->second != missing )
						(iline->second)->push_back(PaperPoint(x, value->second));
				}
				members.push_back(value->second);
			}

			if ( forecast_ ) {
			if ( value->first == "forecast" &&  value->second != missing )
				forecast->push_back(PaperPoint(x, value->second));
			}
			if ( control_ ) {
			if ( value->first == "control" &&  value->second != missing)
				control->push_back(PaperPoint(x, value->second));
			}


		}
		if ( median_ ) {
					std::sort(members.begin(), members.end());
					median->push_back(PaperPoint(x, members[25]));
		}
		if ( shading_ ) {
			for ( vector<double>::iterator level = shading_levels_.begin(); level != shading_levels_.end(); ++level) {
				int i = *level/2;
				if ( i >= members.size() )
					i = members.size() -1; ;
				shading[*level].push_back(PaperPoint(x, members[i]));
			}

		}



	}


	vector<string>::iterator colour = shading_colours_.begin();

	for (int i = 0; i < shading_levels_.size()/2; i++) {

		double bottom = shading_levels_[i];
		double top  = shading_levels_[shading_levels_.size() - 1 - i];
		Colour col =  ( colour == shading_colours_.end() ) ? Colour("blue") : *colour;
		Polyline* line  = new Polyline();
		line->setColour(col);
		line->setFilled(true);
		line->setShading(new FillShadingProperties());
		line->setFillColour(col);
		visitor.push_back(line);
		for ( vector<PaperPoint>::iterator point = shading[bottom].begin();  point != shading[bottom].end(); ++point)
			line->push_back(*point);

		for ( vector<PaperPoint>::reverse_iterator point = shading[top].rbegin();  point != shading[top].rend(); ++point)
					line->push_back(*point);

		double grey = ((col.red()+col.blue()+col.green())/3.);

		col.setColour(grey, grey, grey);

		++colour;
		shading_legend_.push_back(col);
	}
	if ( line_)
			for ( map<string, Polyline* >::const_iterator line = lines.begin(); line != lines.end(); ++line) {
			visitor.push_back(line->second);
		}
		if (control_)
			visitor.push_back(control);
		if (forecast_)
			visitor.push_back(forecast);
		if (median_)
			visitor.push_back(median);

}

void EpsPlume::verticalprofile(Data& data, BasicGraphicsObjectContainer& visitor)
{
	CustomisedPointsList points;
	std::set<string> request;
	const Transformation& transformation = visitor.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!


	if (points.empty()) return;



	map<string, Polyline* > lines;
	Polyline* control  = new Polyline();
	control->setColour(*control_line_colour_);
	control->setThickness(control_line_thickness_);
	control->setLineStyle(control_line_style_);

	Polyline* forecast  = new Polyline();
	forecast->setColour(*forecast_line_colour_);
	forecast->setThickness(forecast_line_thickness_);
	forecast->setLineStyle(forecast_line_style_);


	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {
		double y = (**point)["y"];
		for ( map<string, double>::const_iterator value = (*point)->begin(); value != (*point)->end(); ++value) {
			if ( value->second == (**point)["missing"] )
				continue;
			if ( alldigit(value->first) ) {
				map<string, Polyline* >::iterator  iline = lines.find(value->first);
				if ( iline == lines.end() ) {
					Polyline* line  = new Polyline();
					line->setColour(*line_colour_);
					line->setThickness(line_thickness_);
					line->setLineStyle(line_style_);
					lines[value->first] = line;
					iline = lines.find(value->first);
				}
				(iline->second)->push_back(transformation(UserPoint(value->second, y)));
			}

			if ( value->first == "forecast" )
				forecast->push_back(transformation(UserPoint(value->second, y)));
			if ( value->first == "control" )
				control->push_back(transformation(UserPoint(value->second, y)));
		}
	}

	for ( map<string, Polyline* >::const_iterator line = lines.begin(); line != lines.end(); ++line) {
		visitor.push_back(line->second);
	}
	visitor.push_back(control);
	visitor.push_back(forecast);
}
void EpsPlume::operator()(Data& data, BasicGraphicsObjectContainer& visitor)
{
	method_ = lowerCase(method_);
	std::map<string, Method>::iterator method = methods_.find(method_);
	if ( method == methods_.end() ) {
		MagLog::warning() << "Could not find method [" << method_ << "] for plotting : no plot could be done." << endl;
		return;
	}
	(this->*method->second)(data, visitor);
	
	
}    
       

EfiGraph::EfiGraph() {}
EfiGraph::~EfiGraph() {}
    
    
    
void EfiGraph::operator()(Data& data, BasicGraphicsObjectContainer& out)
{
	CustomisedPointsList points;
	std::set<string> request;
	const Transformation& transformation = out.transformation();
	data.customisedPoints(transformation, request, points, true); // we want all the points!

	vector<string>::iterator colour = box_colour_.begin();


	Polyline* ref  = new Polyline();
	ref->setColour(*normal_colour_);
	ref->setThickness(normal_thickness_);
	ref->setLineStyle(normal_style_);
	ref->push_back(PaperPoint(0, 1));
	MagFont font(font_, font_style_, font_size_);
	font.colour(*font_colour_);

	out.push_back(ref);
	for (CustomisedPointsList::const_iterator point = points.begin(); point != points.end(); ++point) {

		ref->push_back(PaperPoint(0, (**point)["steps"]+1));
		for (int i = 1; i <= (**point)["steps"]; i++) {
			ostringstream key;
			key << "efi" << i << "_value";
			ostringstream step;
			step << "efi" << i << "_step";
			bool available = ((*point)->find(step.str()) != (*point)->end());

			int s = (**point)[step.str()];
			ostringstream legend;
			legend << "Eps t+ [" << s - 36 << "-" << s - 12 <<"h] " ;

			Polyline* box  = new Polyline();
			box->setColour(*border_colour_);
			box->setThickness(border_thickness_);
			box->setLineStyle(border_style_);
			box->setFilled(true);
			box->setShading(new FillShadingProperties());
			box->setFillColour(*colour);
			++colour;
			double val = (**point)[key.str()];
			box->push_back(PaperPoint(0, i ));
			box->push_back(PaperPoint(val, i ));
			box->push_back(PaperPoint(val, i +1));
			box->push_back(PaperPoint(0, i +1));
			box->push_back(PaperPoint(0, i ));
			out.push_back(box);
			if ( available ) {
				Text* text  = new Text();
				text->setText(legend.str());
				text->setJustification(MRIGHT);
				text->setFont(font);
				text->push_back(PaperPoint(-101 , i+0.5));
				out.push_back(text);
				Text* value  = new Text();
				value->setText(tostring(maground(val))+"%");
				value->setJustification(MLEFT);
				value->setFont(font);
				value->push_back(PaperPoint(101 , i+0.5));
				out.push_back(value);
			}
		}
	}
	Text* text  = new Text();
	text->setText("-100%");
	text->setJustification(MCENTRE);
	text->setFont(font);
	text->push_back(PaperPoint(-100 , 0.5));
	out.push_back(text);
	text  = new Text();
	text->setText("-50%");
	text->setJustification(MCENTRE);
	text->setFont(font);
	text->push_back(PaperPoint(-50 , 0.5));
	out.push_back(text);
	text  = new Text();
	text->setText("EFI");
	text->setJustification(MCENTRE);
	text->setFont(font);
	text->push_back(PaperPoint(0 , 0.5));
	out.push_back(text);
	text  = new Text();
	text->setText("50%");
	text->setJustification(MCENTRE);
	text->setFont(font);
	text->push_back(PaperPoint(50 , 0.5));
	out.push_back(text);
	text  = new Text();
	text->setText("100%");
	text->setJustification(MCENTRE);
	text->setFont(font);
	text->push_back(PaperPoint(100 , 0.5));
	out.push_back(text);
}
void EfiGraph::visit(LegendVisitor&)
{
}

	

	
