/* _backend_agg.h - A rewrite of _backend_agg using PyCXX to handle
   ref counting, etc..
*/

#ifndef __BACKEND_AGG_H
#define __BACKEND_AGG_H
#include <utility>
#include "CXX/Extensions.hxx"

#include "agg_arrowhead.h"
#include "agg_basics.h"
#include "agg_bezier_arc.h"
#include "agg_color_rgba.h"
#include "agg_conv_concat.h"
#include "agg_conv_contour.h"
#include "agg_conv_curve.h"
#include "agg_conv_dash.h"
#include "agg_conv_marker.h"
#include "agg_conv_marker_adaptor.h"
#include "agg_math_stroke.h"
#include "agg_conv_stroke.h"
#include "agg_ellipse.h"
#include "agg_embedded_raster_fonts.h"
#include "agg_path_storage.h"
#include "agg_pixfmt_rgb.h"
#include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_alpha_mask_u8.h"
#include "agg_pixfmt_amask_adaptor.h"
#include "agg_rasterizer_outline.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_renderer_outline_aa.h"
#include "agg_renderer_raster_text.h"
#include "agg_renderer_scanline.h"
#include "agg_rendering_buffer.h"
#include "agg_scanline_bin.h"
#include "agg_scanline_u.h"
#include "agg_scanline_p.h"
#include "agg_vcgen_markers_term.h"

#include "agg_py_path_iterator.h"

// These are copied directly from path.py, and must be kept in sync
#define STOP   0
#define MOVETO 1
#define LINETO 2
#define CURVE3 3
#define CURVE4 4
#define CLOSEPOLY 5

const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 1 };

typedef agg::pixfmt_rgba32 pixfmt;
typedef agg::renderer_base<pixfmt> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa;
typedef agg::renderer_scanline_bin_solid<renderer_base> renderer_bin;
typedef agg::rasterizer_scanline_aa<> rasterizer;

typedef agg::scanline_p8 scanline_p8;
typedef agg::scanline_bin scanline_bin;
typedef agg::amask_no_clip_gray8 alpha_mask_type;


typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base_alpha_mask_type;
typedef agg::renderer_scanline_aa_solid<renderer_base_alpha_mask_type> renderer_alpha_mask_type;

// a helper class to pass agg::buffer objects around.  agg::buffer is
// a class in the swig wrapper
class BufferRegion : public Py::PythonExtension<BufferRegion> {
public:
  BufferRegion(const agg::rect_i &r, bool freemem=true) :
  rect(r), freemem(freemem) {
    width = r.x2 - r.x1;
    height = r.y2 - r.y1;
    stride = width * 4;
    data = new agg::int8u[stride * height];
  }
  agg::int8u* data;
  agg::rect_i rect;
  int width;
  int height;
  int stride;

  bool freemem;

  // set the x and y corners of the rectangle
  Py::Object set_x(const Py::Tuple &args);
  Py::Object set_y(const Py::Tuple &args);

  Py::Object to_string(const Py::Tuple &args);
  Py::Object to_string_argb(const Py::Tuple &args);
  static void init_type(void);

  virtual ~BufferRegion() {
    if (freemem) {
      delete [] data;
      data = NULL;
    }
  };
};

class GCAgg {
public:
  GCAgg(const Py::Object& gc, double dpi);
  GCAgg(double dpi);

  double dpi;
  bool isaa;

  agg::line_cap_e cap;
  agg::line_join_e join;

  double linewidth;
  double alpha;
  agg::rgba color;

  Py::Object cliprect;
  Py::Object clippath;
  agg::trans_affine clippath_trans;

  //dashes
  typedef std::vector<std::pair<double, double> > dash_t;
  double dashOffset;
  dash_t dashes;

  enum {
    SNAP_AUTO,
    SNAP_FALSE,
    SNAP_TRUE
  } snap;

protected:
  agg::rgba get_color(const Py::Object& gc);
  double points_to_pixels( const Py::Object& points);
  void _set_linecap(const Py::Object& gc) ;
  void _set_joinstyle(const Py::Object& gc) ;
  void _set_dashes(const Py::Object& gc) ;
  void _set_clip_rectangle( const Py::Object& gc);
  void _set_clip_path( const Py::Object& gc);
  void _set_antialiased( const Py::Object& gc);
  void _set_snap( const Py::Object& gc);
};


//struct AMRenderer {
//
//}

// the renderer
class RendererAgg: public Py::PythonExtension<RendererAgg> {
  typedef std::pair<bool, agg::rgba> facepair_t;
public:
  RendererAgg(unsigned int width, unsigned int height, double dpi, int debug);
  static void init_type(void);

  unsigned int get_width() { return width;}
  unsigned int get_height() { return height;}
  // the drawing methods
  //Py::Object _draw_markers_nocache(const Py::Tuple & args);
  //Py::Object _draw_markers_cache(const Py::Tuple & args);
  Py::Object draw_markers(const Py::Tuple & args);
  Py::Object draw_text_image(const Py::Tuple & args);
  Py::Object draw_image(const Py::Tuple & args);
  Py::Object draw_path(const Py::Tuple & args);
  Py::Object draw_path_collection(const Py::Tuple & args);
  Py::Object draw_quad_mesh(const Py::Tuple& args);


  Py::Object write_rgba(const Py::Tuple & args);
  Py::Object tostring_rgb(const Py::Tuple & args);
  Py::Object tostring_argb(const Py::Tuple & args);
  Py::Object tostring_bgra(const Py::Tuple & args);
  Py::Object tostring_rgba_minimized(const Py::Tuple & args);
  Py::Object buffer_rgba(const Py::Tuple & args);
  Py::Object clear(const Py::Tuple & args);

  Py::Object copy_from_bbox(const Py::Tuple & args);
  Py::Object restore_region(const Py::Tuple & args);

  virtual ~RendererAgg();

  static const size_t PIXELS_PER_INCH;
  unsigned int width, height;
  double dpi;
  size_t NUMBYTES;  //the number of bytes in buffer

  agg::int8u *pixBuffer;
  agg::rendering_buffer renderingBuffer;

  agg::int8u *alphaBuffer;
  agg::rendering_buffer alphaMaskRenderingBuffer;
  alpha_mask_type alphaMask;
  agg::pixfmt_gray8 pixfmtAlphaMask;
  renderer_base_alpha_mask_type rendererBaseAlphaMask;
  renderer_alpha_mask_type rendererAlphaMask;
  agg::scanline_p8 scanlineAlphaMask;

  scanline_p8 slineP8;
  scanline_bin slineBin;
  pixfmt pixFmt;
  renderer_base rendererBase;
  renderer_aa rendererAA;
  renderer_bin rendererBin;
  rasterizer theRasterizer;

  Py::Object lastclippath;
  agg::trans_affine lastclippath_transform;

  const int debug;

protected:
  double points_to_pixels( const Py::Object& points);
  double points_to_pixels_snapto( const Py::Object& points);
  agg::rgba rgb_to_color(const Py::SeqBase<Py::Object>& rgb, double alpha);
  facepair_t _get_rgba_face(const Py::Object& rgbFace, double alpha);
  template<class R>
  void set_clipbox(const Py::Object& cliprect, R& rasterizer);
  bool render_clippath(const Py::Object& clippath, const agg::trans_affine& clippath_trans);
  template<class PathIteratorType>
  void _draw_path(PathIteratorType& path, bool has_clippath,
		  const facepair_t& face, const GCAgg& gc);
  template<class PathGenerator, int check_snap, int has_curves>
  Py::Object
  _draw_path_collection_generic
    (agg::trans_affine 	            master_transform,
     const Py::Object&		    cliprect,
     const Py::Object&		    clippath,
     const agg::trans_affine&       clippath_trans,
     const PathGenerator&	    path_generator,
     const Py::SeqBase<Py::Object>& transforms_obj,
     const Py::Object&              offsets_obj,
     const agg::trans_affine&       offset_trans,
     const Py::Object&              facecolors_obj,
     const Py::Object&              edgecolors_obj,
     const Py::SeqBase<Py::Float>&  linewidths,
     const Py::SeqBase<Py::Object>& linestyles_obj,
     const Py::SeqBase<Py::Int>&    antialiaseds);

private:
  void create_alpha_buffers();
};

// the extension module
class _backend_agg_module : public Py::ExtensionModule<_backend_agg_module>
{
public:
  _backend_agg_module()
    : Py::ExtensionModule<_backend_agg_module>( "_backend_agg" )
  {
    RendererAgg::init_type();
    BufferRegion::init_type();

    add_keyword_method("RendererAgg", &_backend_agg_module::new_renderer,
		       "RendererAgg(width, height, dpi)");
    initialize( "The agg rendering backend" );
  }

  virtual ~_backend_agg_module() {}

private:

  Py::Object new_renderer (const Py::Tuple &args, const Py::Dict &kws);
};



#endif

