// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2010 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WRASTER_IMAGE_H_
#define WRASTER_IMAGE_H_

#include <Wt/WPaintDevice>
#include <Wt/WResource>

#include <list>

typedef struct _DrawContext *DrawContext;
typedef struct _Image Image;

namespace Wt {

class FontSupport;
class WTransform;

/*! \class WRasterImage Wt/WRasterImage Wt/WRasterImage
 *  \brief A paint device for rendering to a raster image.
 *
 * A %WRasterImage paint device provides support for creating raster
 * images (such as PNG or GIF images).
 *
 * It implements two main use-cases:
 *
 *  - When used either in conjunction with a WPainter, it supports
 *    vector graphics operations, and can be used to make a PNG or GIF
 *    version of a WPaintedWidget's contents.
 *
 *  - It also provides a low-level API to color individual pixels using
 *    setPixel(), which directly sets the raster pixels.
 *
 * The rendering is provided by <a
 * href="http://www.graphicsmagick.org/">GraphicsMagick</a>, and this
 * class is included in the library only if <tt>libgraphicsmagick</tt>
 * was found during the build of the library. If %Wt is built to use
 * <tt>libpango</tt> for font support, then text rendering is done
 * using this library. Otherwise, you may want to configure TrueType
 * font search directories using addFontCollection().
 *
 * You can use the image as a resource and specialize handleRequest()
 * to paint the contents on the fly. Alternatively can also use
 * write() to serialize to an image file (std::ostream).
 *
 * The latter usage is illustrated by the code below:
 * \code
 * Wt::Chart::WCartesianChart *chart = ...
 *
 * Wt::WRasterImage pngImage("png", 600, 400);
 * {
 *   Wt::WPainter p(&pngImage);
 *   chart->paint(p);
 * }
 * std::ofstream f("chart.png", std::ios::out | std::ios::binary);
 * pngImage.write(f);
 * \endcode
 *
 * This paint device has the following limitations:
 * - drop shadows are (not yet?) supported.
 * 
 * \ingroup painting
 */
class WT_API WRasterImage : public WResource, public WPaintDevice
{
public:
  /*! \brief Creates a raster image.
   * 
   * \p type indicates an image type. The mime type of the resource is
   * <tt>"image/"</tt> \p type.
   *
   * %Wt supports the following image types (amongst others):
   * - png: Portable Network Graphics
   * - gif: Graphics Interchange Format
   * - bmp: Microsoft windows bitmap
   * - jpeg: Joint Photographic Experts Group JFIF format
   */
  WRasterImage(const std::string& type,
	       const WLength& width, const WLength& height,
	       WObject *parent = 0);

  /*! \brief Destructor.
   */
  ~WRasterImage();

  /*! \brief Adds a font collection.
   *
   * If %Wt has been configured to use <tt>libpango</tt>, then font
   * matching and character selection is done by libpango, which is
   * seeded with information on installed fonts by fontconfig. In that
   * case, invocations for this method is ignored.
   * 
   * If %Wt has not been configured to use <tt>libpango</tt>, then
   * this method may be used to indicate the location of true type
   * fonts. The main drawback compared to libpango is that font
   * selection is not steered by the need for particular characters,
   * i.e. font selection is independent from the text's need for
   * specific characters. Most truetype fonts provided only partial
   * unicode support. The provided \p directory will be searched for
   * fonts (currently only TrueType ".ttf" or ".ttc" fonts).
   */
  void addFontCollection(const std::string& directory, bool recursive=true);

  virtual WFlags<FeatureFlag> features() const;
  virtual void setChanged(WFlags<ChangeFlag> flags);
  virtual void drawArc(const WRectF& rect, double startAngle, double spanAngle);
  virtual void drawImage(const WRectF& rect, const std::string& imgUri,
			 int imgWidth, int imgHeight, const WRectF& sourceRect);
  virtual void drawLine(double x1, double y1, double x2, double y2);
  virtual void drawPath(const WPainterPath& path);

  virtual void drawText(const WRectF& rect, 
			WFlags<AlignmentFlag> alignmentFlags,
			TextFlag textFlag,
			const WString& text);
  virtual WTextItem measureText(const WString& text, double maxWidth = -1,
				bool wordWrap = false);
  virtual WFontMetrics fontMetrics();
  virtual void init();
  virtual void done();
  virtual bool paintActive() const { return painter_ != 0; }

  virtual WLength width() const { return width_; }
  virtual WLength height() const { return height_; }

  virtual void handleRequest(const Http::Request& request,
			     Http::Response& response);

  /*! \brief Low-level paint method.
   *
   * Use this method to directly set colors for individual pixels, when
   * using the paint device without a painter.
   */
  void setPixel(int x, int y, const WColor& color);

  /*! \brief Low-level paint method.
   *
   * Use this method to directly get the color for an individual pixel, when
   * using the paint device without a painter.
   */
  WColor getPixel(int x, int y);

  /*! \brief Clears the image.
   *
   * Fills the image with a white background.
   */
  void clear();

protected:
  virtual WPainter *painter() const { return painter_; }
  virtual void setPainter(WPainter *painter) { painter_ = painter; }

private:
  WLength width_, height_;
  std::string type_;
  WPainter *painter_;
  FontSupport *fontSupport_;
  bool renderText_;

  unsigned long w_, h_;
  unsigned char *pixels_;
  DrawContext context_;
  Image *image_;
  double fontSize_;

  typedef std::list< std::pair<WPainterPath, int> > PathCache;
  PathCache clipPathCache_;
  int currentClipPath_;
  int currentClipPathRendered_;

  void internalInit(bool applyChanges = true);
  void internalDone();
  void paintPath();
  void drawPlainPath(const WPainterPath& path);
  void setTransform(const WTransform& t);
  void applyTransform(const WTransform& f);
  std::string currentClipPathName() const;
};

}

#endif // WRASTER_IMAGE_H_
