#ifndef DOC_SVG_H
#define DOC_SVG_H


#include <vector>
#include <map>
#include "tinyxml.h"
#include "DocStyle.h"
#include "DocTemplate.h"
#include "DocOutput.h"
#include "hpdf.h"


class SVGOperation
{
public:
	enum PathOperation {
		MoveToAbs,
		LineToAbs,
		HorizontalLineToAbs,
		VerticalLineToAbs,
		CurveToAbs,
		SmoothCurveToAbs,
		QuadraticBezierCurveToAbs,
		SmoothQuadraticBezierCurveToAbs,
		EllipticalArcToAbs,
		ClosePath,

		MoveToRel,
		LineToRel,
		HorizontalLineToRel,
		VerticalLineToRel,
		CurveToRel,
		SmoothCurveToRel,
		QuadraticBezierCurveToRel,
		SmoothQuadraticBezierCurveToRel,
		EllipticalArcToRel,
		AltClosePath,

		BadOperation,

		BeginPathOperation,
		EndPathOperation
	};

	static const char PathOperationChar[];
	static const int PathOperationArgs[];

	static PathOperation getOperationForChar(char a_ch)
  {
		for (int i = 0; i < BadOperation; i++)
			if (PathOperationChar[i] == a_ch)
				return (PathOperation)i;
		return BadOperation;
	}

	int getArgCount()
  {
		return PathOperationArgs[m_type];
	}

	void dump()
  {
		fprintf(stderr, " OP: -%c- ARGS: ", PathOperationChar[m_type]);
		for (int i = 0; i < PathOperationArgs[m_type]; i++)
			fprintf(stderr, " -%f- ", m_values[i]);
		fprintf(stderr, "\n");
	}

	void scale(double a_scale)
  {
		for (int i = 0; i < PathOperationArgs[m_type]; i++)
			m_values[i] *= a_scale;
	}

  void output(HPDF_Page page, float curPos[2], bool /*fill*/, PathOperation prevOp, float pathStartPos[2]);

	PathOperation  m_type;
	double         m_values[7];
};


class DocSVG : public TiXmlVisitor
{
public:
	DocSVG(double scale);
	virtual ~DocSVG();
	/// Visit a document.
	virtual bool VisitEnter( const TiXmlDocument& doc );
	/// Visit a document.
	virtual bool VisitExit( const TiXmlDocument& doc );
	/// Visit a declaration
	virtual bool Visit( const TiXmlDeclaration& declaration );
	/// Visit a stylesheet reference
	virtual bool Visit( const TiXmlStylesheetReference& stylesheet );
	/// Visit a comment node
	virtual bool Visit( const TiXmlComment& comment );
	/// Visit an unknow node
	virtual bool Visit( const TiXmlUnknown& unknown );
	
	/// Visit an element.
	virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
	/// Visit an element.
	virtual bool VisitExit( const TiXmlElement& element );
	/// Visit a text node
	virtual bool Visit( const TiXmlText& text );

	void DumpOperations()
	{
		for (size_t p = 0; p < paths.size(); ++p)
			for (size_t i = 0; i < paths[p].operations.size(); i++)
				paths[p].operations[i].dump();
	}

	void WriteTo(DocOutputPage* outputPage);

private:
	struct SVGStyle
  {
    float         opacity;

    float         fillOpacity;
    uint32_t		  fillColor;
    std::string   fillString;     // url/gradient etc

    std::string   strokeString;   // none | #color
    float         strokeOpacity;
    uint32_t		  strokeColor;
		float		  	  strokeWidth;
		uint32_t		  strokeLineCap;
		uint32_t		  strokeLineJoin;
	};

  struct SVGPath
  {
		std::vector<SVGOperation> operations;
		SVGStyle                  style;
	};

  struct SVGColorStop
  {
    float      offset;
    uint32_t   color;
    float      opacity;
  };

  struct SVGGradient
  {
    std::string               name;
		std::vector<SVGColorStop> stops;
    float                     x1, y1, x2, y2;
	};

	static SVGStyle parseStyle(const char* a_str);
  static uint32_t parseLineCap(const std::string& s);
  static uint32_t parseLineJoin(const std::string& s);
	static uint32_t parseColor(const char* a_str);
  static std::vector<SVGOperation> ParsePath(const char* a_pathData);

  SVGGradient*                       currentGradient;
	std::map<std::string, SVGGradient> gradients;
	std::vector<SVGPath>               paths;
	double m_scale;
};


#endif // DOC_SVG_H


