#include "lgi/common/Lgi.h"
// #include <cups/ipp.h>
// #include <cups/cups.h>

#define PS_SCALE			10

///////////////////////////////////////////////////////////////////////////////////////
class GPrintDCPrivate // : public GCups
{
public:
	class PrintPainter *p;
	Gtk::GtkPrintContext *Handle;
	LString PrintJobName;
	LString PrinterName;
	int Pages;
	LColour c;
	LRect Clip;
	Gtk::cairo_t *cr;
	
	GPrintDCPrivate(Gtk::GtkPrintContext *handle)
	{
		cr = NULL;
		p = 0;
		Pages = 0;
		Handle = handle;
	}
	
	~GPrintDCPrivate()
	{
	}
	
	bool IsOk()
	{
		#ifndef __clang__
		return	this != 0;
		#else
		return true;
		#endif
	}
};

/////////////////////////////////////////////////////////////////////////////////////
LPrintDC::LPrintDC(void *Handle, const char *PrintJobName, const char *PrinterName)
{
	d = new GPrintDCPrivate((Gtk::GtkPrintContext*)Handle);
	d->PrintJobName = PrintJobName;
	d->PrinterName = PrinterName;
	d->cr = gtk_print_context_get_cairo_context(d->Handle);
	ColourSpace = CsRgb24;
	d->Clip = Bounds();
}

LPrintDC::~LPrintDC()
{
	DeleteObj(d);
}

Gtk::GtkPrintContext *LPrintDC::GetPrintContext()
{
	return d->Handle;
}

int LPrintDC::X()
{
	return gtk_print_context_get_width(d->Handle);
}

int LPrintDC::Y()
{
	return gtk_print_context_get_height(d->Handle);
}

int LPrintDC::GetBits()
{
	return 24;
}

int LPrintDC::DpiX()
{
	return Gtk::gtk_print_context_get_dpi_x(d->Handle);
}

int LPrintDC::DpiY()
{
	return Gtk::gtk_print_context_get_dpi_y(d->Handle);
}

LRect LPrintDC::ClipRgn(LRect *Rgn)
{
	LRect Prev = d->Clip;
	if (Rgn)
		d->Clip = *Rgn;
	else
		d->Clip = Bounds();
	return Prev;
}

LRect LPrintDC::ClipRgn()
{
	return d->Clip;
}

COLOUR LPrintDC::Colour()
{
	return d->c.c24();
}

COLOUR LPrintDC::Colour(COLOUR c, int Bits)
{
	LColour col(c, Bits);
	return Colour(col).c24();
}

LColour LPrintDC::Colour(LColour c)
{
	LColour Prev = d->c;
	d->c = c;
	if (d->cr)
		cairo_set_source_rgb(d->cr,
							(double)d->c.r() / 255.0,
							(double)d->c.g() / 255.0,
							(double)d->c.b() / 255.0);
	return Prev;
}

void LPrintDC::Set(int x, int y)
{
	if (d->cr)
	{
		cairo_new_path(d->cr);
		cairo_rectangle(d->cr, x, y, x+1, y+1);
		cairo_fill(d->cr);
	}
}

void LPrintDC::HLine(int x1, int x2, int y)
{
	Line(x1, y, x2, y);
}

void LPrintDC::VLine(int x, int y1, int y2)
{
	Line(x, y1, x, y2);
}

void LPrintDC::Line(int x1, int y1, int x2, int y2)
{
	if (d->cr)
	{
		cairo_set_line_width(d->cr, 0.5);
		cairo_new_path(d->cr);
		cairo_move_to(d->cr, x1, y1);
		cairo_line_to(d->cr, x2, y2);
		cairo_stroke(d->cr);
	}
}

void LPrintDC::Circle(double cx, double cy, double radius)
{
	LAssert(!"Not impl.");
}

void LPrintDC::FilledCircle(double cx, double cy, double radius)
{
	LAssert(!"Not impl.");
}

void LPrintDC::Arc(double cx, double cy, double radius, double start, double end)
{
	LAssert(!"Not impl.");
}

void LPrintDC::FilledArc(double cx, double cy, double radius, double start, double end)
{
	LAssert(!"Not impl.");
}

void LPrintDC::Ellipse(double cx, double cy, double x, double y)
{
	LAssert(!"Not impl.");
}

void LPrintDC::FilledEllipse(double cx, double cy, double x, double y)
{
	LAssert(!"Not impl.");
}

void LPrintDC::Box(int x1, int y1, int x2, int y2)
{
	LRect r(x1, y1, x2, y2);
	Box(&r);
}

void LPrintDC::Box(LRect *a)
{
	LRect r;
	if (a)
		r = *a;
	else
		r = Bounds();
	if (d->cr)
	{
		double Half = 0.5;
		cairo_set_line_width(d->cr, Half);
		cairo_new_path(d->cr);
		cairo_rectangle(d->cr,
						Half + r.x1,
						Half + r.y1,
						-Half + r.X(),
						-Half + r.Y());
		cairo_stroke(d->cr);
	}
}

void LPrintDC::Rectangle(int x1, int y1, int x2, int y2)
{
	LRect r(x1, y1, x2, y2);
	Rectangle(&r);
}

void LPrintDC::Rectangle(LRect *a)
{
	LRect r;
	if (a)
		r = *a;
	else
		r = Bounds();
	if (d->cr)
	{
		cairo_new_path(d->cr);
		cairo_rectangle(d->cr, r.x1, r.y1, r.X(), r.Y());
		cairo_fill(d->cr);
	}
}

void LPrintDC::Blt(int x, int y, LSurface *Src, LRect *SrcClip)
{
	LRect s = SrcClip ? *SrcClip : Src->Bounds();
	LRect d = s;
	d.ZOff(x, y);
	StretchBlt(&d, Src, &s);
}

void LPrintDC::StretchBlt(LRect *rc, LSurface *Src, LRect *s)
{
	if (!d->cr)
	{
		LAssert(0);
		return;
	}
	
	uint8_t *Scan0 = (*Src)[0];
	if (!Scan0)
	{
		LAssert(0);
		return;
	}
	
	Gtk::cairo_format_t Fmt = Gtk::CAIRO_FORMAT_INVALID;
	switch (Src->GetBits())
	{
		case 16:
			Fmt = Gtk::CAIRO_FORMAT_RGB16_565;
			break;
		case 24:
			Fmt = Gtk::CAIRO_FORMAT_RGB24;
			break;
		case 32:
			Fmt = Gtk::CAIRO_FORMAT_ARGB32;
			break;
	}
	if (Fmt == Gtk::CAIRO_FORMAT_INVALID)
	{
		LAssert(0);
		return;
	}
	
	Gtk::cairo_surface_t *Img = cairo_image_surface_create_for_data(Scan0,
																	Fmt,
																	Src->X(),
																	Src->Y(),
																	Src->GetRowStep());
	if (!Img)
	{
		LAssert(0);
		return;
	}

	Gtk::cairo_pattern_t *Pat = cairo_pattern_create_for_surface(Img);
	if (Pat)
	{
		Gtk::cairo_matrix_t m;
		double Sx = (double) s->X() / rc->X();
		double Sy = (double) s->Y() / rc->Y();
		cairo_matrix_init_scale(&m, Sx, Sy);
		cairo_matrix_translate(&m, -rc->x1,-rc->y1);
		cairo_pattern_set_matrix(Pat, &m);

		cairo_save(d->cr);
		cairo_set_source(d->cr, Pat);
		
		cairo_new_path(d->cr);
		cairo_rectangle(d->cr, rc->x1, rc->y1, rc->X(), rc->Y());
		cairo_fill(d->cr);
		
		cairo_restore(d->cr);
		cairo_pattern_destroy(Pat);
	}
	
	cairo_surface_destroy(Img);
}

void LPrintDC::Polygon(int Points, LPoint *Data)
{
	LAssert(!"Not impl.");
}

void LPrintDC::Bezier(int Threshold, LPoint *Pt)
{
	LAssert(!"Not impl.");
}

