#include "PdfWriter.h"

#include <QtGui\QPdfWriter>
#include <QtGui\QPainter>
#include <QtCore\QCoreApplication>
#include <QtWidgets\QApplication>
#include <QtWidgets\QMessageBox>
#include <QtCore\QTextCodec>
#include <QtGui\QColor>
#include <QtCore\QString>
#include <memory>
#include <iostream>
#include <sstream>

extern aplAPI_DLL QPageSize* crtPageSizeDef()
{
	QPageSize* out = new QPageSize(QPageSize::A4);
	{
		//QSizeF sf = out->size(QPageSize::Millimeter);
		//double w = sf.width();
		//double h = sf.height();
		////
		//apl::qt::MsgBox( QString("w=%1, h=%2").arg(w).arg(h), "msgBox");
	}
	return out;
}

extern aplAPI_DLL QPageSize* crtPageSize( const pageSize::ps& ps )
{
	QPageSize::PageSizeId psid = QPageSize::A4;
	switch (ps)
	{
	case pageSize::A1:
		psid = QPageSize::A1;
		break;
	case pageSize::A2:
		psid = QPageSize::A2;
		break;
	case pageSize::A3:
		psid = QPageSize::A3;
		break;
	//case pageSize::A5:
	case pageSize::A5:
		psid = QPageSize::A5;
		break;
	//default:
	}
	QPageSize* out = new QPageSize(psid);
	return out;
}

extern aplAPI_DLL QPageSize* crtPageSizeMM( const int& w, const int& h )
{
	QPageSize* out = new QPageSize(QSize(w,h), QPageSize::Millimeter);
	return out;
}

extern aplAPI_DLL void getPageSizePoint( const QPageSize* ps, int& w, int& h )
{
	QRect rect = ps->rectPoints();
	w = rect.width();
	h = rect.height();
}

extern aplAPI_DLL void getPageSizeMM( const QPageSize* ps, double& w, double& h )
{
	QSizeF sf = ps->size(QPageSize::Millimeter);
	w = sf.width();
	h = sf.height();
}

extern aplAPI_DLL QPdfWriter* crtPdfWriterDef( const char* fileNamePdf )
{
	QString qs = apl::qt::convertRawChar(fileNamePdf);
	QPdfWriter* W = new QPdfWriter(qs);
	if(false)//resolution
	{
		//int res = W->resolution();
		//QMessageBox::warning(NULL, "My Application",
		//	QString("resolution=%1").arg(res),
		//	QMessageBox::Ok);
	}
	if(true)
	{//margin
		QMarginsF defMF(0,0,0,0);
		W->setPageMargins(defMF);
		//
		//const QPageLayout& pl =  W->pageLayout();
		//const QMarginsF& mf = pl.margins();
		//const double& t = mf.top();
		//const double& l = mf.left();
		//const double& b = mf.bottom();
		//const double& r = mf.right();
		//
		//apl::qt::MsgBox(QString("MarginsF: t=%1, l=%2, b=%3, r=%4").arg(t).arg(l).arg(b).arg(r), "pdfWr");
	}
	return W;
}

extern aplAPI_DLL QPdfWriter* crtPdfWriter( const char* fileNamePdf, QPageSize* ps )
{
	QString qs = apl::qt::convertRawChar(fileNamePdf);
	QPdfWriter* W = new QPdfWriter(qs);
	{
		//W->
		W->setPageSize(*ps);
	}
	{
		QMarginsF defMF(0,0,0,0);
		W->setPageMargins(defMF);
	}
	return W;	
}

extern aplAPI_DLL void getCurrPageSizeMM( QPdfWriter* writer, double& w, double& h )
{
	QSizeF sf = writer->pageSizeMM();
	w = sf.width();
	h = sf.height();
}

extern aplAPI_DLL bool addPageDef( QPdfWriter* w )
{
	bool out = w->newPage();
	return out;
}

extern aplAPI_DLL bool addPage( QPdfWriter* w, QPageSize* ps )
{
	bool out = w->newPage();
	{
		w->setPageSize(*ps);
	}
	return out;
}

extern aplAPI_DLL QRect* crtRect( const int& x, const int& y, const int& w, const int& h )
{
	QRect *out = new QRect(x,y,w,h);
	return out;
}

extern aplAPI_DLL QRect* crtRectDef( const int& w, const int& h )
{
	return crtRect( 0, 0, w, h );
}

extern aplAPI_DLL QPainter* crtPainter( QPdfWriter* writer, QRect* rect )
{
	QPainter* dc = new QPainter(writer);
	//pntr = new QPainter(writer);
	//bool out = true;
	{
		bool flag = true;//pntr->begin(pntr->device());
		if (!flag)
		{
			//out = false;
			//int r = apl::qt::MsgBox( "Wrong Painter. Could be file is open in another program", "aplPdfWriter");
		}
	}
	{
		dc->setWindow(*rect);
	}
	return dc;
}

extern aplAPI_DLL void endDraw( QPainter* dc )
{
	dc->end();
}

extern aplAPI_DLL void testPdf1( const std::string& fileNamePdf )
{
	QPdfWriter* dc = new QPdfWriter(fileNamePdf.c_str());
	QPainter* painter = new QPainter( dc );
	{
		//QPdfWriter writer(fileNamePdf.c_str());
		//QPainter& painter(dc);

		painter->setPen(Qt::red);
		painter->drawText(0,0,"THIS IS MY RED PDF TEXT..");

		painter->setPen(Qt::green);
		painter->drawText(0,500,"THIS IS MY GREEN PDF TEXT..");

		painter->setPen(Qt::blue);
		painter->drawText(0,1000,"THIS IS MY BLUE PDF TEXT..");

		painter->end(); 
	}
	//
}

extern aplAPI_DLL QColor* getCurrColor()
{
	apl::qt::StorageCurrentThing& storage = apl::qt::getStorageCurrThing();
	//
	QColor* out = storage.color_;
	return out;
}

extern aplAPI_DLL void setCurrColor( QColor *clr )
{
	apl::qt::StorageCurrentThing& storage = apl::qt::getStorageCurrThing();
	//
	storage.color_ = clr;
}

extern aplAPI_DLL QPen* crtPen( QColor *clr )
{
	QPen* out = new QPen;
	{
		out->setColor(*clr);
	}
	return out;
}

extern aplAPI_DLL QPen* crtPenDef()
{
	QPen *out = new QPen();
	return out;
}

extern aplAPI_DLL void setPenColor( QColor *clr, QPen * pen )
{
	pen->setColor(*clr);
}

extern aplAPI_DLL void setPen( QPen *pen, QPainter* dc )
{
	dc->setPen(*pen);
}

extern aplAPI_DLL void setPenWidthF( const double& w, QPen *pen )
{
	pen->setWidthF(w);
}

extern aplAPI_DLL void setPenWidth( const int& w, QPen *pen )
{
	pen->setWidth(w);
}

extern aplAPI_DLL QFont* crtFont( const char* family, const FontDescr& fd )
{
	QFont * f = new QFont(family);
	{
		f->setItalic(fd.italic);
		f->setBold(fd.bold);
		//f->setPixelSize(100);
		{
			//int s = f->pixelSize();
			//apl::qt::MsgBox(QString("pixelSize=%1").arg(s), "crtFont");
		}
		{
			//int s = f->pointSize();
			//apl::qt::MsgBox(QString("pointSize=%1").arg(s), "crtFont");
			//f->setPointSize(6);
		}
		{
			//double s = f->pointSizeF();
			//apl::qt::MsgBox(QString("pointSizeF=%1").arg(s), "crtFont");
			//f->setPointSizeF(2);
		}
	}
	return f;
}

extern aplAPI_DLL void setFont( QFont *font, QPainter* dc )
{
	dc->setFont(*font);
}

extern aplAPI_DLL QFont* crtFontByName( const char* family )
{
	QString qs = apl::qt::convertRawChar(family);
	QFont * f = new QFont(qs);
	//
	return f;	
}

extern aplAPI_DLL void setFontSizeF( const double&s, QFont *font )
{
	font->setPointSizeF(s);
}

extern aplAPI_DLL void setFontPixelSize( const int&s, QFont *font )
{
	font->setPixelSize(s*39/(45*2.5));
	//font->setPointSizeF(s/10.0);
}

extern aplAPI_DLL void addTextF( const double& x, const double& y, const char* text, QPainter* dc )
{
	{
		//int ret = QMessageBox::warning(NULL, "My Application",
		//	QString("addTexF(x=%1, y=%2)").arg(x).arg(y),
		//	QMessageBox::Ok);
	}
	QPointF p(x,y);
	QString qs = apl::qt::convertRawChar(text);
	//
	dc->drawText(p, qs);
}

extern aplAPI_DLL void addText( const int& x, const int& y, const char* text, QPainter* dc )
{
	//{
	//	int ret = QMessageBox::warning(NULL, "My Application",
	//		QString("addTEx(x=%1, y=%2)").arg(x).arg(y),
	//		QMessageBox::Ok);
	//}
	QString qs = apl::qt::convertRawChar(text);
	QPoint p(x,y);
	dc->drawText(p, qs);
}

extern aplAPI_DLL void DrawLine( const double& x1, const double& y1, const double& x2, const double& y2,QPainter* dc )
{
	QLineF l(x1,y1,x2,y2);
	dc->drawLine(l);
}

extern aplAPI_DLL void addRotateText( const double&degrees, const double& x, const double& y, const char* text, QPainter* dc )
{
	QString qs = apl::qt::convertRawChar(text);
	//
	dc->save();
	dc->translate(x, y);
	dc->rotate(degrees);
	dc->drawText(0,0,qs);
	dc->restore();
}

extern aplAPI_DLL void DrawRect( const double& x, const double& y, const double& w, const double& h,QPainter* dc )
{
	QRectF r(x,y,w,h);
	dc->drawRect(r);
}

void apl::qt::drawRectText( const double& x, const double& y, const double& w, const double& h, const QString& qs, const pdfAlignment& align, QPainter* dc )
{
	double penWidth = 0;
	{
		const QPen& pen = dc->pen();
		penWidth = pen.widthF();
	}
	const double delta = (5+2*penWidth)*0.5;
	//
	double x1 = x;
	double y1 = y;
	double w1 = w;
	double h1 = h;
	//
	int Align = 0;
	switch (align)
	{
	case aplAlignLeft:
		Align = Qt::AlignLeft;
		x1 += delta*2;
		break;
	case aplAlignRight:
		Align = Qt::AlignRight;
		x1 -= delta;
		break;
	case aplAlignCenter:
		Align = Qt::AlignCenter;
		x1 += delta;
		break;
	}
	Align |= Qt::AlignVCenter;
	//
	QRectF r(x1, y1, w1, h1);
	//
	dc->drawText(r, Align, qs);
}



extern aplAPI_DLL void DrawRectText( const double& x, const double& y, const double& w, const double& h, const char* text, const pdfAlignment& align, QPainter* dc )
{
	QString qs = apl::qt::convertRawChar(text);
	apl::qt::drawRectText(x, y, w, h, qs, align, dc);
}

extern aplAPI_DLL void DrawImage(const double& x, const double& y, const double& w, const double& h, const char *file, QPainter* dc)
{
	QString path = apl::qt::convertRawChar(file);

	QImage img;
	img.load(path);

	QRect out(x, y, w, h);
	dc->drawImage(out, img);
}

extern aplAPI_DLL void DrawRectTextRotate( const double& degree, const double& x, const double& y, const double& w, const double& h, const char* text, const pdfAlignment& align, QPainter* dc )
{
	QString qs0 = apl::qt::convertRawChar(text);
	//
	double penWidth = 0;
	{
		const QPen& pen = dc->pen();
		penWidth = pen.widthF();
	}
	const double delta = 5+2*penWidth;
	//
	apl::holder::PainterTransform pt(*dc);
	dc->translate(x,y);
	//
	const char* pch = text;//cstr.c_str();
	//
	double dy=0;
	{
		const QFont& font = dc->font();
		QFontMetricsF fm(font);
		dy = fm.height();
	}
	//
	QStringList sl = qs0.split('\n');
	const int& size = sl.size();
	//
	double kdy = (size-1)/2.0;
	//
	if (0.0==degree)
	{
		if (size>1)
		{
			for (int i=0; i<size; ++i)
			{
				const QString& currStr = sl[i];
				apl::qt::drawRectText(0/*+delta*/, 0+dy*(i-kdy), w, h, currStr, align, dc);
			}
		} 
		else
		{
			apl::qt::drawRectText(0/*+delta*/, 0, w, h, qs0, align, dc);
		}
	}
	else if (-90.0==degree)
	{
		dc->rotate(-90.0);
		DrawRectText(0-h, 0, h, w, pch, align, dc);
	}
	else if (90.0==degree)
	{
		dc->rotate(+90.0);
		DrawRectText(0, 0-w, h, w, pch, align, dc);
	}
	else if (180.0==degree)
	{
		dc->rotate(180.0);
		DrawRectText(0-w, 0-h, w, h, pch, align, dc);
	}
	else
	{
		DrawRectText(0, 0, w, h, pch, align, dc);
	}
}

extern aplAPI_DLL void deleteFont( QFont * font )
{
	apl::qt::cmnDeleter(font);
}

extern aplAPI_DLL void deletePen( QPen* obj )
{
	apl::qt::cmnDeleter(obj);
}

extern aplAPI_DLL void deleteColor( QColor* obj )
{
	apl::qt::cmnDeleter(obj);
}

extern aplAPI_DLL void deletePainter( QPainter* obj )
{
	apl::qt::cmnDeleter(obj);
}

extern aplAPI_DLL void deletePageSize( QPageSize* obj )
{
	apl::qt::cmnDeleter(obj);
}

extern aplAPI_DLL void deletePdfWriter( QPdfWriter* obj )
{
	obj->deleteLater();
}

extern aplAPI_DLL void deleteRect( QRect* obj )
{
	apl::qt::cmnDeleter(obj);
}

extern aplAPI_DLL char* getColorDescr( const QColor* clr )
{
	apl::qt::first_initQt_def();
	//
	char* out;
	{
		//QString str;
		//{
		//	str = "Some Color Descr";
		//}
		std::string s2;// = "2array of char";//str.toStdString();
		{
			using namespace std;
			const int r = clr->red();
			const int g = clr->green();
			const int b = clr->blue();
			//
			stringstream ss;
			ss << "color(r=" << r << ", g=" << g << ", b=" << b << ")";
			s2 = ss.str();
		}
		//
		out = apl::qt::copyCh(s2.c_str());
	}
	//
	return out;
}

extern aplAPI_DLL QColor* crtColor( int r, int g, int b )
{
	apl::qt::first_initQt_def();
	QColor* out = new QColor(r,g,b);
	return out;
}

extern aplAPI_DLL QColor* crtColorByName( const char* nameColor )
{
	apl::qt::first_initQt_def();
	QString qs = apl::qt::convertRawChar(nameColor);
	QColor* out = new QColor(qs);
	return out;
}

void apl::qt::first_initQt( int argc, char **argv )
{
	if (!qApp)
	{
		std::cout<< "first_initQt" <<std::endl;
		//
		new QApplication(argc, argv);
		//
		apl::qt::initCodec();
	}
}

void apl::qt::first_initQt_def()
{
	static const int argc = 1;
	apl::qt::first_initQt(argc, NULL);
}

void apl::qt::initCodec()
{
	//QTextCodec *codec = QTextCodec::codecForName("UTF-8");
	//QTextCodec *codec = QTextCodec::codecForName("Windows-1251");
	//QTextCodec *codec = QTextCodec::codecForName("CP1251");
	//QTextCodec::setCodecForCStrings(codec);
	//QTextCodec::setCodecForLocale(codec);
	////
	//QTextCodec *codecTr = QTextCodec::codecForName("CP1251");//wrong with Eclipse
	//QTextCodec::setCodecForTr(codecTr);

	//QTextCodec *codec = QTextCodec::codecForName("Windows-1251");
	//QTextCodec::setCodecForTr(codec);
	//QTextCodec::setCodecForCStrings(codec);
	//QTextCodec::setCodecForLocale(codec);
}

apl::qt::StorageCurrentThing& apl::qt::getStorageCurrThing()
{
	static StorageCurrentThing inst;
	return inst;
}

char* apl::qt::copyCh( const char* source )
{
	const int size = strlen(source);
	char *out = new char[size+1];
	strcpy(out, source);
	out[size] = '\0';
	//
	return out;
}

QString apl::qt::convertRawChar( const char* pch )
{
	QString out;
	{
		{
			QByteArray encodedString(pch);
			QTextCodec *codec = QTextCodec::codecForLocale();
			out = codec->toUnicode(encodedString);
		}
	}
	return out;
}

int apl::qt::MsgBox( const QString& text, const QString& caption )
{

	int ret = QMessageBox::warning(NULL, caption,
		text,
		QMessageBox::Ok);
	//
	return ret;
}

apl::qt::StorageCurrentThing::StorageCurrentThing()
{
	color_ = new QColor;
}

apl::holder::PainterTransform::PainterTransform( QPainter& dc ) :dc_(dc)
{
	dc_.save();
}

apl::holder::PainterTransform::~PainterTransform()
{
	dc_.restore();
}
