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

#include <Wt/WBrush>
#include <Wt/WFont>
#include <Wt/WPen>
#include <Wt/WPointF>
#include <Wt/WResource>
#include <Wt/WShadow>
#include <Wt/WStringStream>
#include <Wt/WTransform>
#include <Wt/WVectorImage>

namespace Wt {

class ServerSideFontMetrics;

/*! \class WSvgImage Wt/WSvgImage Wt/WSvgImage
 *  \brief A paint device for rendering using Scalable Vector Graphics (SVG).
 *
 * The %WSvgImage is primarily used by WPaintedWidget to render to the
 * browser in Support Vector Graphics (SVG) format.
 *
 * \if cpp
 * You may also use the %WSvgImage as an independent resource, for example
 * in conjunction with a WAnchor or WImage, or to make a hard copy of an
 * image in SVG format, using write():
 * \code
 * Wt::Chart::WCartesianChart *chart = ...
 *
 * Wt::WSvgImage svgImage(800, 400);
 * Wt::WPainter p(&svgImage);
 * chart->paint(p);
 * p.end();
 * std::ofstream f("chart.svg");
 * svgImage.write(f);
 * \endcode
 * \endif
 *
 * \ingroup painting
 */
class WT_API WSvgImage : public WResource, public WVectorImage
{
public:
  /*! \brief Create an SVG paint device.
   *
   * If \p paintUpdate is \c true, then only an SVG fragment will be
   * rendered that can be used to update the DOM of an existing SVG
   * image, instead of a full SVG image.
   */
  WSvgImage(const WLength& width, const WLength& height, WObject *parent = 0,
	    bool paintUpdate = false);

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

  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 std::string rendered();

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

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

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

private:
  WLength   width_, height_;
  WPainter *painter_;
  bool      paintUpdate_;
  WFlags<ChangeFlag> changeFlags_;

  bool        newGroup_;
  bool        newClipPath_;
  bool        busyWithPath_;
  int         currentClipId_;
  static int  nextClipId_;
  int         currentFillGradientId_;
  int         currentStrokeGradientId_;
  static int  nextGradientId_;

  WTransform  currentTransform_;
  WBrush      currentBrush_;
  WFont       currentFont_;
  WPen        currentPen_;
  WShadow     currentShadow_;
  int         currentShadowId_, nextShadowId_;

  WPointF     pathTranslation_;

  WStringStream shapes_;
  ServerSideFontMetrics *fontMetrics_;

  void finishPath();
  void makeNewGroup();
  std::string fillStyle() const;
  std::string strokeStyle() const;
  std::string fontStyle() const;
  std::string clipPath() const;
  int createShadowFilter(WStringStream& out);
  void defineGradient(const WGradient& gradient, int id);

  std::string fillStyle_, strokeStyle_, fontStyle_;

  static std::string quote(double s);
  static std::string quote(const std::string& s);

  void drawPlainPath(WStringStream& s, const WPainterPath& path);

  void streamResourceData(std::ostream& stream);
};

}

#endif // WSVG_IMAGE_H_
