/***************************************************************
 * Name:      wxCairo.cpp
 * Purpose:   Code for Application Frame
 * Author:    Igor I (info@tiptopcity.com)
 * Created:   2009-05-24
 * Copyright: Igor I (www.tiptopcity.com)
 * License:
 **************************************************************/

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

//------------------------------------------------------------------------------
//#include <cairo/cairo-svg.h>
//#include <librsvg/rsvg.h>
//#include <librsvg/rsvg-cairo.h>
#if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND) || defined(__BORLANDC__)
	#include <cairo/cairo-win32.h>
#else

#endif

#include <cairo/cairo.h>
//#include <librsvg/rsvg.h>
//#include <librsvg/rsvg-cairo.h>
//#include <svg_cairo.c>
#include <math.h>
#include <string.h>

#include "wxCairo.h"
#include "stdTools.h"
//#include "wxgui/debug.h"
//------------------------------------------------------------------------------
struct stdword{
	std::string str;
	int width;
};
//------------------------------------------------------------------------------
wxCairo::wxCairo()
{
	glId=0;
	m_buffer=NULL;
	m_surface=NULL;
	m_cr=NULL;
	m_format = CAIRO_FORMAT_RGB24;
	m_width=0; m_height=0;
}
//------------------------------------------------------------------------------
wxCairo::~wxCairo()
{
	if(m_buffer!=NULL) delete m_buffer;
	if(m_surface!=NULL) cairo_surface_destroy(m_surface);
	if(m_cr!=NULL) cairo_destroy(m_cr);
}
//------------------------------------------------------------------------------
unsigned char* wxCairo::CreateBuffer(int width,int height)
{
	if(width!=m_width || m_height!=height)
	{
		if(m_buffer!=NULL) delete m_buffer;
		m_width=width; m_height=height;
		m_buffer = new unsigned char[width*height*4]; //RGBA
		memset(m_buffer, 0, width*height*4); //Обнулим массив
		Init();
		return m_buffer;
	}else
	{
		memset(m_buffer, 0, width*height*4); //Обнулим(отчистим) массив
		return m_buffer;
	}
}
//------------------------------------------------------------------------------
bool wxCairo::Init()
{
	if(m_surface!=NULL) cairo_surface_destroy(m_surface);
	if(m_cr!=NULL) cairo_destroy(m_cr);
	m_surface = cairo_image_surface_create_for_data(m_buffer, m_format, m_width, m_height, m_width*4);    
	m_cr = cairo_create(m_surface);
	cairo_set_antialias(m_cr, CAIRO_ANTIALIAS_NONE);
	return true;
}
//------------------------------------------------------------------------------
/*void wxCairo::Draw(wxPaintDC& dc)
{
	// Convert from Cairo RGB24 format to wxImage BGR format.
	unsigned char *dRGB = new unsigned char[m_width*m_height*3];
	//unsigned char *dA = new unsigned char[m_width*m_height];
	for(int y=0;y<m_height;y++)
	{
		for(int x=0;x<m_width;x++)
		{
			dRGB[x*3+y*m_width*3] = m_buffer[x*4+2+y*m_width*4];
			dRGB[x*3+1+y*m_width*3] = m_buffer[x*4+1+y*m_width*4];
			dRGB[x*3+2+y*m_width*3] = m_buffer[x*4+y*m_width*4];

			//dA[x*y] = 255;
		}
	}
	// Blit final image to the screen.
	//wxImage img=wxImage(m_width, m_height, dRGB, dA, true);
	wxImage img=wxImage(m_width, m_height, dRGB, true);
	//if(img.HasAlpha())
	//{
		wxBitmap m_bitmap(img);
		dc.DrawBitmap(m_bitmap, 0, 0, true);
	//}
	delete dRGB;
	//delete dA;
}*/
//------------------------------------------------------------------------------
//Нарисуем чтонибудь для примера в текущем буфере
bool wxCairo::Test()
{
	// White background.
	//cairo_set_source_rgb(m_cr, 1.0, 1.0, 1.0);
	//cairo_rectangle(m_cr, 0, 0, m_width, m_height);
	//cairo_fill(m_cr);

	//draw stuff
	cairo_select_font_face(m_cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size(m_cr, 32.0);
	cairo_set_source_rgb(m_cr, 0.0, 0.0, 1.0);
	cairo_move_to(m_cr, 10.0, 50.0);

	std::string str="Привет мир!";
	//const wxCharBuffer buff = str.mb_str(wxConvUTF8);
	cairo_show_text (m_cr, str.c_str());

	//Curve
	double x=25.6,  y=128.0;
	double x1=102.4, y1=230.4,
		   x2=153.6, y2=25.6,
		   x3=230.4, y3=128.0;

	cairo_move_to (m_cr, x, y);
	cairo_curve_to (m_cr, x1, y1, x2, y2, x3, y3);

	cairo_set_line_width (m_cr, 10.0);
	cairo_stroke (m_cr);

	cairo_set_source_rgba (m_cr, 1, 0.2, 0.2, 0.6);
	cairo_set_line_width (m_cr, 6.0);
	cairo_move_to (m_cr,x,y);   cairo_line_to (m_cr,x1,y1);
	cairo_move_to (m_cr,x2,y2); cairo_line_to (m_cr,x3,y3);
	cairo_stroke (m_cr);

	//SVG
	/*cairo_surface_t *surface;
	//cairo_t *cr;

	surface = cairo_svg_surface_create("Svg.svg", 390, 60);
	cr = cairo_create(surface);

	cairo_set_source_rgb(m_cr, 0, 0, 0);
	cairo_select_font_face (m_cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
	cairo_set_font_size (m_cr, 40.0);

	cairo_move_to(m_cr, 10.0, 50.0);
	cairo_show_text(m_cr, "Disziplin ist Macht.");

	cairo_surface_destroy(surface);
	//cairo_destroy(cr);*/

     /*double  IMAGE_WIDTH	 = 256;
     double  IMAGE_HEIGHT = 256;
     cairo_surface_t*	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, IMAGE_WIDTH, IMAGE_HEIGHT);
     cairo_t*	cr = cairo_create(surface);
     cairo_scale(cr, IMAGE_WIDTH, IMAGE_HEIGHT);
     svg_cairo_t*    svgc;
     svg_cairo_create(&svgc);
     gtk_init(&argc, &argv);	// 1) doesn't work
     svg_cairo_parse(svgc, "data/home.svg");
//    gtk_init(&argc, &argv);	// 2) works
     unsigned	w, h;
     svg_cairo_get_size(svgc, &w, &h);
     cairo_scale(cr, 1.0 / w, 1.0 / h);
     svg_cairo_render(svgc, cr);
     svg_cairo_destroy(svgc);
     cairo_surface_write_to_png(surface, "out.png");
     cairo_destroy(cr);
     cairo_surface_destroy(surface);
     return 0;*/

	return true;
}
//------------------------------------------------------------------------------
void wxCairo::MoveTo(double x, double y)
{
	cairo_move_to(m_cr,x,y);
}
//------------------------------------------------------------------------------
void wxCairo::LineTo(double x, double y)
//void wxCairo::LineTo(double y, double x)
{
	cairo_line_to(m_cr,x,y);
}
//------------------------------------------------------------------------------
void wxCairo::SetLineWidth(double width)
{
	cairo_set_line_width(m_cr, width);
}
//------------------------------------------------------------------------------
void wxCairo::ShowText(std::wstring& str)
{
	std::string utf8=convUTF16ToUTF8(str);
	cairo_show_text (m_cr, utf8.c_str());
}
//------------------------------------------------------------------------------
void wxCairo::SetSourceRGBA(double red, double green, double blue, double alpha)
{
	cairo_set_source_rgba(m_cr, red, green, blue, alpha);
}
//------------------------------------------------------------------------------
void wxCairo::SetSourceRGB(double red, double green, double blue)
{	cairo_set_source_rgb(m_cr, red, green, blue);
}
//------------------------------------------------------------------------------
void wxCairo::Rectangle (double x, double y, double width, double height)
{	cairo_rectangle (m_cr, x, y, width, height);
}
//------------------------------------------------------------------------------
//Не рисовать то что не входит в последний геом объект
void wxCairo::Clip()
{	cairo_clip(m_cr);
}
//------------------------------------------------------------------------------
void wxCairo::ResetClip()
{	cairo_reset_clip(m_cr);
}
//------------------------------------------------------------------------------
void wxCairo::Fill()
{	cairo_fill(m_cr);
}
//------------------------------------------------------------------------------
//Обводка
//Операция cairo_stroke() применяет виртуальный карандаш вдоль контура.Это позволяет источнику передать через маску тонкую(или толстую) линию вдоль контура, в соответствие с карандашной толщиной линии, стилем точек, и наконечниками линии.
void wxCairo::Stroke()
{	cairo_stroke(m_cr);
}
//------------------------------------------------------------------------------
//Преобразовать рисунок в битовый массив
void wxCairo::toBitArray(unsigned char* bitArray)
{
	int pos = 0;
	for (int y = 0; y<m_height; y++)
	{
		for (int x = 0; x<m_width; x++)
		{
			unsigned char r = m_buffer[x * 4 + 2 + y*m_width * 4];
			unsigned char g = m_buffer[x * 4 + 1 + y*m_width * 4];
			unsigned char b = m_buffer[x * 4 + y*m_width * 4];
			unsigned char px = (r + g + b) / 3.0f;

			int posB=floor(pos / 8.0f); //Номер байта

			if (px < 127) //Чёрный это 1
			{
				setBit(&bitArray[posB], pos - posB * 8, true);
				//
			}else //Белый это 0
			{
				setBit(&bitArray[posB], pos - posB * 8, false);
			}
			pos++;
		}
	}
}
//------------------------------------------------------------------------------
void wxCairo::setBit(unsigned char *mas, const unsigned char pos, bool val)
{
	unsigned char mask = 128;
	unsigned char loc = pos / 8;
	mask = mask >> (pos - loc * 8);
	if (val) mas[loc] = mas[loc] | mask;
	else
	{
		mask = ~mask; //Отрицание
		mas[loc] = mas[loc] & mask;
	}
}
//------------------------------------------------------------------------------
void wxCairo::setFontface(std::string family,bool slant,bool weight)
{
	cairo_font_slant_t s;
	if (slant) s = CAIRO_FONT_SLANT_ITALIC;  else s = CAIRO_FONT_SLANT_NORMAL;
	cairo_font_weight_t w;
	if (weight) w = CAIRO_FONT_WEIGHT_BOLD; else w = CAIRO_FONT_WEIGHT_NORMAL;

	cairo_select_font_face(m_cr,family.c_str(),s,w);
}
//------------------------------------------------------------------------------
void  wxCairo::setFontface(const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight)
{
	cairo_select_font_face(m_cr, family, slant, weight);
}
//------------------------------------------------------------------------------
//the new font size, in user space units
void wxCairo::setFontSize(double size)
{
	cairo_set_font_size(m_cr,size);
}
//------------------------------------------------------------------------------
void wxCairo::seveToPNG(std::string filePath)
{
	cairo_surface_write_to_png(m_surface, filePath.c_str());
}
//------------------------------------------------------------------------------
//Ширина текста в пикселях
double wxCairo::getTextWidth(std::wstring& str)
{
	std::string utf8 = convUTF16ToUTF8(str);
	cairo_text_extents_t ext;
	cairo_text_extents(m_cr, utf8.c_str(), &ext);
	return ext.width;
}
//------------------------------------------------------------------------------
//Высота текста в пикселях
double wxCairo::getTextHeight(std::wstring& str)
{
	std::string utf8 = convUTF16ToUTF8(str);
	cairo_text_extents_t ext;
	cairo_text_extents(m_cr, utf8.c_str(), &ext);
	return ext.height;
}
//------------------------------------------------------------------------------
//Вывести текст по центру области
void wxCairo::ShowTextCenter(std::wstring& str, int xStart, int xEnd, int y)
{
	std::string utf8 = convUTF16ToUTF8(str);

	cairo_text_extents_t ext;
	cairo_text_extents(m_cr, utf8.c_str(), &ext);

	ext.width = xStart + (((xEnd - xStart) / 2.0f) - (ext.width / 2.0f));
	cairo_move_to(m_cr, ext.width, y);

	cairo_show_text(m_cr, utf8.c_str());
}
//------------------------------------------------------------------------------
//Вывести текст с переносом на следующую строку с выравниванием по словам, высота символов однирна
//xStart начало для вычисления центра
//xEnd конец для вычисления центра
//y высота
void wxCairo::ShowTextBR(std::wstring& str, int xStart, int xEnd, int y)
{
	/*stdword line;
	std::vector<stdword> parts;

	int maxH=0;
	std::vector<std::wstring> array =split(str,L' ');
	for (std::vector<std::wstring>::iterator it = array.begin() ; it != array.end(); ++it)
	{
		std::wstring s=*it;
		line.word = convUTF16ToUTF8(s);
		cairo_text_extents(m_cr, line.word.c_str(), &line.ext);
		line.ext.width+=line.ext.width/s.length(); //Так как пробел почемуто обрезается при расчёте ширины
		parts.push_back(line);
		if(maxH<line.ext.height) maxH=line.ext.height;
	}

	int w=xStart;
	for (std::vector<stdword>::iterator it = parts.begin() ; it != parts.end(); ++it)
	{
		line=*it;
		if(w+line.ext.width<xEnd)
		{
			cairo_move_to(m_cr, w, y);
			w+=line.ext.width;
		}else
		{
			w=xStart;
			y+=maxH;
			cairo_move_to(m_cr, w, y);
			w+=line.ext.width;
		}
		cairo_show_text(m_cr, line.word.c_str());
	}*/
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//Вывести текст с переносом на следующую строку с выравниванием по словам, высота символов однирна
//xStart начало для вычисления центра
//xEnd конец для вычисления центра
//y высота
void wxCairo::ShowTextCenterBR(std::wstring& str, int xStart, int xEnd, int y)
{
	std::vector<std::wstring> array =split(str,L' '); //Для разбивки на слова
	int height=0;	//Высота символов
	std::vector<stdword> parts; //Для разбивки на строки

	stdword line;
	line.width=0;
	line.str="";
	for (std::vector<std::wstring>::iterator it = array.begin() ; it != array.end(); ++it)
	{
		std::wstring s=*it;
		std::string word = convUTF16ToUTF8(s);
		cairo_text_extents_t ext;
		cairo_text_extents(m_cr, word.c_str(), &ext);
		ext.width+=ext.width/s.length(); //Так как пробел почемуто обрезается при расчёте ширины
		if(height<ext.height) height=ext.height; //Высота символов

		if(line.width+ext.width<xEnd-xStart)
		{
			line.width+=ext.width;
			line.str+=word+' ';
		}else
		{
			parts.push_back(line);
			line.width=0;
			line.str="";
		}
	}
	parts.push_back(line);

	//Отображаю текст по центру
	for (std::vector<stdword>::iterator it = parts.begin() ; it != parts.end(); ++it)
	{
		stdword line=*it;
		int width = xStart + (((xEnd - xStart) / 2.0f) - (line.width / 2.0f));
		cairo_move_to(m_cr, width, y);
		cairo_show_text(m_cr, line.str.c_str());
		y+=height;
	}
}
//------------------------------------------------------------------------------
