#include <cstring>
#include <cerrno>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <utility>
#include <fstream>


#include <pygobject.h>
#include <pygtk/pygtk.h>

#include "agg_basics.h"
#include "_backend_agg.h"
#include "_transforms.h"

// the extension module
class _gtkagg_module : public Py::ExtensionModule<_gtkagg_module>
{
public:
  _gtkagg_module()
    : Py::ExtensionModule<_gtkagg_module>( "_gtkagg" )
  {
    add_varargs_method("agg_to_gtk_drawable",
		       &_gtkagg_module::agg_to_gtk_drawable,
		       "Draw to a gtk drawable from a agg buffer.");
    initialize( "The _gtkagg module" );
  }

  virtual ~_gtkagg_module() {}

private:

  Py::Object agg_to_gtk_drawable(const Py::Tuple &args) {
    // args are gc, renderer, bbox where bbox is a transforms BBox
    // (possibly None).  If bbox is None, blit the entire agg buffer
    // to gtk.  If bbox is not None, blit only the region defined by
    // the bbox
    args.verify_length(3);

    PyGObject *py_drawable = (PyGObject *)(args[0].ptr());
    RendererAgg* aggRenderer = static_cast<RendererAgg*>(args[1].ptr());

    GdkDrawable *drawable = GDK_DRAWABLE(py_drawable->obj);
    GdkGC* gc = gdk_gc_new(drawable);

    int srcstride = aggRenderer->get_width()*4;
    int srcwidth = (int)aggRenderer->get_width();
    int srcheight = (int)aggRenderer->get_height();

    // these three will be overridden below
    int destx = 0;
    int desty = 0;
    int destwidth = 1;
    int destheight = 1;
    int deststride = 1;


    bool needfree = false;

    agg::int8u *destbuffer = NULL;

    if (args[2].ptr() == Py_None) {
      //bbox is None; copy the entire image
      destbuffer = aggRenderer->pixBuffer;
      destwidth = srcwidth;
      destheight = srcheight;
      deststride = srcstride;
    }
    else {
      //bbox is not None; copy the image in the bbox

      Bbox* clipbox = static_cast<Bbox*>(args[2].ptr());
      double l = clipbox->ll_api()->x_api()->val() ;
      double b = clipbox->ll_api()->y_api()->val();
      double r = clipbox->ur_api()->x_api()->val() ;
      double t = clipbox->ur_api()->y_api()->val() ;

      //std::cout << b << " "
      //		<< t << " ";

      destx = (int)l;
      desty = srcheight-(int)t;
      destwidth = (int)(r-l);
      destheight = (int)(t-b);
      deststride = destwidth*4;

      needfree = true;
      destbuffer = new agg::int8u[deststride*destheight];
      if (destbuffer ==NULL) {
	throw Py::MemoryError("_gtkagg could not allocate memory for destbuffer");
      }

      agg::rendering_buffer destrbuf;
      destrbuf.attach(destbuffer, destwidth, destheight, deststride);
      pixfmt destpf(destrbuf);
      renderer_base destrb(destpf);
      //destrb.clear(agg::rgba(1, 0, 0));

      agg::rect_base<int> region(destx, desty, (int)r, srcheight-(int)b);
      destrb.copy_from(*aggRenderer->renderingBuffer, &region,
		       -destx, -desty);


    }


    /*std::cout << desty << " "
	      << destheight << " "
	      << srcheight << std::endl;*/


    //gdk_rgb_init();
    gdk_draw_rgb_32_image(drawable, gc, destx, desty,
			  destwidth,
			  destheight,
			  GDK_RGB_DITHER_NORMAL,
			  destbuffer,
			  deststride);

    if (needfree) delete [] destbuffer;

    return Py::Object();

  }
};


extern "C"
DL_EXPORT(void)
  init_gtkagg(void)
{
  init_pygobject();
  init_pygtk();
  //suppress unused warning by creating in two lines
  static _gtkagg_module* _gtkagg = NULL;
  _gtkagg = new _gtkagg_module;

};







