/*
 * (C) Copyright 1996-2016 ECMWF.
 * 
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. 
 * In applying this licence, ECMWF does not waive the privileges and immunities 
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

/*!
    \file CairoDriver.h
    \brief Definition of CairoDriver.
    \author Meteorological Visualisation Section, ECMWF

    Started: Mon Oct 15 20:49:32 2007
*/

#ifndef _CairoDriver_H
#define _CairoDriver_H

#include <BaseDriver.h>
#include <CairoDriverAttributes.h>
#include <XmlNode.h>

#ifdef _AIX
#undef HAVE_STDLIB_H
#endif
#include <cairo.h>

namespace magics
{

/*! \class CairoDriver
    \brief This driver produces output for Cairo
    \ingroup drivers

    This driver ...
*/
class CairoDriver: public BaseDriver, public CairoDriverAttributes
{

public:
	CairoDriver();
	~CairoDriver();
	void open();
	void close();

	/*!
	  \brief sets a new XML node
	*/
	void set(const XmlNode& node)
	{
		if ( magCompare(node.name(), "png") ||
		     magCompare(node.name(), "pdf") ||
		     magCompare(node.name(), "cairo_ps") ||
		     magCompare(node.name(), "cairo_svg") ||
		//     magCompare(node.name(), "x") ||
		     magCompare(node.name(), "cairo_eps") ||
		     magCompare(node.name(), "geotiff") )
		{
			XmlNode basic = node;
			basic.name("driver");
			BaseDriver::set(basic);
			basic.name("cairo");
			CairoDriverAttributes::set(basic);
		}
	}

	/*!
	  \brief sets a new map
	*/
	void set(const map<string, string>& map)
	{
		BaseDriver::set(map);
		CairoDriverAttributes::set(map);
	}

	void setPNG() const {backend_ = "png";}
	void setPDF() const {backend_ = "pdf";}
	void setPS () const {backend_ = "ps";}
	void setEPS() const {backend_ = "eps";}
	void setSVG() const {backend_ = "svg";}
//	void setX()   const {backend_ = "x";}
	void setGEOTIFF() const {backend_ = "geotiff";}
	void setCairo() const {backend_ = "cairo";}

private:
	MAGICS_NO_EXPORT void startPage() const;
    MAGICS_NO_EXPORT void endPage() const;
	MAGICS_NO_EXPORT void project(const Layout& lay) const;
	MAGICS_NO_EXPORT void unproject() const;
	void newLayer(Layer&) const;
	void closeLayer(Layer&) const;
	MAGICS_NO_EXPORT void setupNewSurface() const;

	MAGICS_NO_EXPORT void setNewLineWidth(const MFloat) const;
	MAGICS_NO_EXPORT void setNewColour(const Colour &col) const;
	MAGICS_NO_EXPORT void setColour(cairo_t* ct, const Colour &col) const;
	MAGICS_NO_EXPORT int  setLineParameters(const LineStyle style, const MFloat w) const;

	MAGICS_NO_EXPORT void renderPolyline(const int, MFloat *, MFloat *) const;
	MAGICS_NO_EXPORT void renderPolyline2(const int n, MFloat *x, MFloat *y) const;
	MAGICS_NO_EXPORT void renderSimplePolygon(const int, MFloat *, MFloat *) const;
	MAGICS_NO_EXPORT void renderSimplePolygon(const Polyline& line) const;
	MAGICS_NO_EXPORT void renderSimplePolygon() const;
	MAGICS_NO_EXPORT void renderText(const Text& text) const;
	MAGICS_NO_EXPORT void circle(const MFloat x, const MFloat y, const MFloat r, const int) const;
	MAGICS_NO_EXPORT bool renderPixmap(MFloat,MFloat,MFloat,MFloat,int,int,unsigned char*,int,bool) const;
	MAGICS_NO_EXPORT bool renderCellArray(const Image& obj) const;
	MAGICS_NO_EXPORT void renderImage(const ImportObject& obj) const;
	MAGICS_NO_EXPORT void renderSymbols(const Symbol& symbol) const;
	MAGICS_NO_EXPORT bool convertToPixmap(const string &fname, const GraphicsFormat format, const int reso,
			     const MFloat wx0, const MFloat wy0,const MFloat wx1,const MFloat wy1) const;
	//! Method to print string about this class on to a stream of type ostream (virtual).
	void print(ostream&) const;
	MAGICS_NO_EXPORT void debugOutput(const string &s) const;

	mutable string	filename_;

	mutable cairo_t*	cr_;
	mutable cairo_t*	tmp_cr_;
	mutable cairo_surface_t* surface_;
	//mutable cairo_surface_t* surfaceBackground_;
	mutable cairo_surface_t* tmp_surface_;

	MAGICS_NO_EXPORT MFloat projectX(const MFloat x) const {return offsetX_+(x*coordRatioX_);}
	MAGICS_NO_EXPORT MFloat projectY(const MFloat y) const {return offsetY_+(y*coordRatioY_);}
	MAGICS_NO_EXPORT MFloat setAngleY(const MFloat y) const {return -y;}
	MAGICS_NO_EXPORT MFloat setSymbolY(const MFloat y) const {return -y;}
	MAGICS_NO_EXPORT MFloat setFlagY(const MFloat y) const {return -y;}
	MAGICS_NO_EXPORT MFloat setY(const MFloat y) const {return y;}
#ifdef HAVE_GEOTIFF
	MAGICS_NO_EXPORT void write_tiff() const;
#endif
	MAGICS_NO_EXPORT bool write_8bit_png() const;
	mutable MFloat offsetX_;
	mutable MFloat offsetY_;
	mutable stack<MFloat> offsetsX_;
	mutable stack<MFloat> offsetsY_;

	mutable string backend_;
	mutable int dimensionXglobal_;
	mutable int dimensionYglobal_;

	//! Copy constructor - No copy allowed
	CairoDriver(const CairoDriver&);
	//! Overloaded << operator to copy - No copy allowed
	CairoDriver& operator=(const CairoDriver&);

	// -- Friends
	//! Overloaded << operator to call print().
	friend ostream& operator<<(ostream& s,const CairoDriver& p)
		{ p.print(s); return s; }
};

} // namespace magics
#endif
