#pragma once

#include "..\pdfWriter\PdfWriter.h"
//
class QColor;
class QPainter;
class QPen;
class QFont;
class QPageSize;

class CReportSheet;
class CReportElement;
class CPictureElement;
class CTextValue;
class CRectReportElement;
class CaplReportMgr;

namespace apl
{
	namespace reportCtr
	{
		namespace decl
		{
			typedef QPageSize* (*pf_crtPageSizeDef)();//A4
			typedef void (*pf_getPageSizePoint)(const QPageSize* ps, int& w, int& h);
			typedef void (*pf_getPageSizeMM)(const QPageSize* ps, double& w, double& h);
			//
			typedef QPageSize* (*pf_crtPageSize)( const pageSize::ps& ps );
			typedef QPageSize* (*pf_crtPageSizeMM)( const int& w, const int& h );
			//
			typedef QPdfWriter* (*pf_crtPdfWriterDef)( const char* fileNamePdf );
			typedef QPdfWriter* (*pf_crtPdfWriter)( const char* fileNamePdf, QPageSize* ps );
			typedef void (*pf_getCurrPageSizeMM)( QPdfWriter* writer, double& w, double& h );
			typedef bool (*pf_addPageDef)(QPdfWriter* w);
			typedef bool (*pf_addPage)( QPdfWriter* w, QPageSize* ps );
			//
			typedef QRect* (*pf_crtRect)( const int& x, const int& y, const int& w, const int& h );
			typedef QRect* (*pf_crtRectDef)( const int& w, const int& h );
			//
			typedef QPainter* (*pf_crtPainter)(QPdfWriter* writer, QRect* rect);
			//typedef bool (*pf_crtPainter)( QPdfWriter* writer, QRect* rect, QPainter* pntr );
			//typedef QPainter* (*pf_crtWriter)(const std::string& fileNamePdf);
			typedef void (*pf_testPdf1)(const std::string& fileNamePdf);
			typedef QColor* (*pf_getCurrColor)();
			typedef char* (*pf_getColorDescr)(const QColor* clr);
			//
			typedef QColor* (*pf_crtColor)(int r, int g, int b);
			typedef QColor* (*pf_crtColorByName)(const char* nameColor);
			typedef void (*pf_setCurrColor)(QColor *clr);
			//
			typedef void (*pf_DrawTextF)( const double& x, const double& y, const char* text, QPainter* dc );
			typedef void (*pf_DrawText)( const int& x, const int& y, const char* text, QPainter* dc );
			typedef void (*pf_endDraw)( QPainter* dc );
			typedef void (*pf_setPen)( QPen *pen, QPainter* dc );
			typedef QPen* (*pf_crtPen)(QColor *clr);
			typedef QPen* (*pf_crtPenDef)();
			typedef void (*pf_setPenColor)( QColor *clr, QPen * pen );
			typedef QFont* (*pf_crtFont)( const char* family, const FontDescr& fd );
			typedef void (*pf_setFontSizeF)( const double&s, QFont *font );
			typedef void (*pf_setFontPixelSize)(const int&s, QFont *font);
			typedef void (*pf_setFont)( QFont *font, QPainter* dc );
			typedef QFont* (*pf_crtFontByName)( const char* family );
			typedef void (*pf_DrawLine)(const double& x1, const double& y1, const double& x2, const double& y2,QPainter* dc);
			typedef void (*pf_setPenWidthF)( const double& w, QPen *pen );
			typedef void (*pf_setPenWidth)( const int& w, QPen *pen );
			typedef void (*pf_addRotateText)( const double& degrees, const double& x, const double& y, const char* text, QPainter* dc );
			typedef void (*pf_DrawRect)( const double& x, const double& y, const double& w, const double& h,QPainter* dc );
			typedef void (*pf_DrawRectText)(const double& x, const double& y, const double& w, const double& h, const char* text, const pdfAlignment& align, QPainter* dc);
			typedef void (*pf_DrawRectTextRotate)(const double& degree, const double& x, const double& y, const double& w, const double& h, const char* text, const pdfAlignment& align, QPainter* dc);
			typedef void (*pf_DrawImage)(const double& x, const double& y, const double& w, const double& h, LPCTSTR file, QPainter* dc);			
			//
			typedef void (*pf_deleteFont)( QFont * font );
			typedef void (*pf_deletePen)( QPen* obj );
			typedef void (*pf_deleteColor)( QColor* obj );
			typedef void (*pf_deletePainter)( QPainter* obj );
			typedef void (*pf_deletePageSize)( QPageSize* obj );
			typedef void (*pf_deletePdfWriter)( QPdfWriter* obj );
			typedef void (*pf_deleteRect)( QRect* obj );
			//
		}
		namespace aux
		{
			struct SheetGuard
			{
				SheetGuard(CReportSheet& sheet);

				CReportSheet& operator()(){return sheet_;}
				const CReportSheet& operator()()const {return sheet_;}

				CReportSheet * operator->(){return &sheet_;}
				const CReportSheet * operator->()const{return &sheet_;}

				~SheetGuard();

				CReportSheet& sheet_;
				bool needDoFree_;
			};
			//
			std::wstring S2W(const CString& src);

			bool GetExePath(CString &buf);

			CString getExePath();
			void ShowPageSizeParams(const char* prefix, const QPageSize* ps, void(*extractor)(const QPageSize* ps, double& w, double& h));
			void ShowPageSizePoint(const char* prefix, const QPageSize* ps, void(*extractor)(const QPageSize* ps, int& w, int& h));

			template <typename T, typename U>void ShowPageSize(const char* prefix, T* t, void(*extractor)(T* t, U& w, U& h));

			CString intToStr(const int& i);
			CString DigitToStr(const double& i);

			void ShowMargins(const CReportSheet& sheet);
			void ShowOptPt(const CReportSheet& sheet);
			void ShowSize(const CReportSheet& sheet);
			void ShowLogFont(const tagLOGFONTA& lgf);
			//
			struct hlpr
			{
				struct Rect
				{
					Rect():x_(0),y_(0),w_(0),h_(0){}

					Rect(const double& x, const double& y,const double& w, const double& h)
						:x_(x),y_(y),w_(w),h_(h){}
					double x_;
					double y_;
					double w_;
					double h_;
				};
				//
				inline
					static Rect calcFromRC(const int& rc_x, const int& rc_y,const int& rc_cx, const int& rc_cy)
				{
					static const double km = 1.0;
					//
					double x = 1*km * rc_x;
					double y = (-1)*km * rc_y;
					double w =    1*km * rc_cx;
					double h = (-1)*km * rc_cy;
					//
					return Rect(x,y,w,h);
				}
				//
				static void drawLine2(const CReportElement& elem, decl::pf_DrawLine F, QPainter * dc);
				//
				static double extractTextOrientation(const CTextValue& txt_value);

				static CString extractShowableText(const CTextValue& txt_value, const CReportSheet& sheet);
				//
				static pdfAlignment mkAlign(const CTextValue& txt_value);


			};
		}
		//
		using namespace decl;
		struct pdfWriterHandler
		{
			pdfWriterHandler(const CString& fullName);
			~pdfWriterHandler();
			HINSTANCE hInst;
			//
			pf_crtPageSizeDef crtPageDef;
			pf_getPageSizePoint getPageSizePoint;
			pf_getPageSizeMM getPageSizeMM;
			pf_crtPageSize crtPageSize;
			pf_crtPageSizeMM crtPageSizeMM;
			//
			pf_crtPdfWriterDef crtWriterDef;
			pf_crtPdfWriter crtPdfWriter;
			pf_getCurrPageSizeMM getCurrPageSizeMM;
			pf_addPageDef addPageDef;
			pf_addPage addPage;
			pf_crtRect crtRect;
			pf_crtRectDef crtRectDef;
			pf_crtPainter crtPainter;
			//
			pf_testPdf1 p_testPdf1;
			pf_getCurrColor getCurrColor;
			pf_getColorDescr getColorDescr;
			//
			pf_crtColor crtColor;
			pf_crtColorByName crtColorByName;
			pf_setCurrColor setCurrColor;
			//
			pf_DrawTextF drawTextF;
			pf_DrawText drawText;
			pf_endDraw endDraw;
			pf_setPen setPen;
			pf_crtPen crtPen;
			pf_crtPenDef crtPenDef;
			pf_setPenColor setPenColor;
			pf_crtFont crtFont;
			pf_setFontSizeF setFontSizeF;
			pf_setFontPixelSize setFontPixelSize;
			pf_setFont setFont;
			pf_crtFontByName crtFontByName;
			pf_DrawLine drawLine;
			//
			pf_setPenWidthF setPenWidthF;
			pf_setPenWidth setPenWidth;
			//pf_addRotateText
			pf_addRotateText drawTextRotate;
			pf_DrawRect drawRect;
			pf_DrawRectText drawRectText;
			pf_DrawRectTextRotate DrawRectTextRotate;
			//
			pf_DrawImage DrawImage;			
			//
			pf_deleteFont deleteFont;
			pf_deletePen deletePen;
			pf_deleteColor deleteColor;
			pf_deletePainter deletePainter;
			pf_deletePageSize deletePageSize;
			pf_deletePdfWriter deletePdfWriter;
			pf_deleteRect deleteRect;
			//
			void doResolve();
			//
			bool isReady()const;

		};
		//
		namespace wrDll
		{
			using namespace decl;

			QColor* getColor(const COLORREF& cRef, pdfWriterHandler& H);
			//
			QColor* getColorLine(const CReportElement& elem, pdfWriterHandler& H);
			//inline
			void setPen_v2(pdfWriterHandler& H, const CReportElement& elem, QPainter* dc);
			//
			QFont * mkFontForText(const CTextValue& txt_value, pdfWriterHandler& H);

			struct FontGuard
			{
				typedef QFont Type;
				//
				FontGuard(Type *f, pdfWriterHandler& h):f_(f), h_(h){}

				~FontGuard()
				{
					if (f_)
					{
						h_.deleteFont(f_);
						f_ = NULL;
					}
				}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}

				Type *f_;
				pdfWriterHandler& h_;
			};
			struct PenGuard
			{
				typedef QPen Type;
				//
				PenGuard(Type *f, pdfWriterHandler& h):f_(f), h_(h){}
				~PenGuard(){if (f_){h_.deletePen(f_);f_ = NULL;}}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}
				//
				Type *f_;
				pdfWriterHandler& h_;
			};
			struct ColorGuard
			{
				typedef QColor Type;
				//
				ColorGuard(Type *f, pdfWriterHandler& h):f_(f), h_(h){}
				~ColorGuard(){if (f_){h_.deleteColor(f_);f_ = NULL;}}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}
				//
				Type *f_;
				pdfWriterHandler& h_;
			};
			struct PainterGuard
			{
				typedef QPainter Type;
				//
				PainterGuard(Type *f, pdfWriterHandler& h):f_(f), h_(h){}
				~PainterGuard(){if (f_){h_.endDraw(f_); h_.deletePainter(f_) ;f_ = NULL;}}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}
				//
				Type *f_;
				pdfWriterHandler& h_;
			};
			//QPageSize
			struct PageSizeGuard
			{
				typedef QPageSize Type;
				//
				PageSizeGuard(Type *f, pdfWriterHandler& h):f_(f), h_(h){}
				~PageSizeGuard(){if (f_){h_.deletePageSize(f_) ;f_ = NULL;}}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}
				//
				Type *f_;
				pdfWriterHandler& h_;
			};
			//
			struct PdfWriterGuard
			{
				typedef QPdfWriter Type;
				//
				PdfWriterGuard(Type *f, pdfWriterHandler& h):f_(f), h_(h){}
				~PdfWriterGuard(){if (f_){h_.deletePdfWriter(f_);}}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}
				//
				Type *f_;
				pdfWriterHandler& h_;
			};
			struct RectGuard
			{
				typedef QRect Type;
				//
				RectGuard(Type *f, pdfWriterHandler& h):f_(f), h_(h){}
				~RectGuard(){if (f_){h_.deleteRect(f_);}}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}
				//
				Type *f_;
				pdfWriterHandler& h_;
			};
			//
			template<typename T, typename F>
			struct SomeGuard
			{
				typedef T Type;
				//
				SomeGuard(Type *t, F& f):t_(t), f_(f){}
				~SomeGuard(){if (t_){f_(t_);t_ = NULL;}}
				Type * operator()(){return f_;}
				const Type * operator()()const{return f_;}
				//
				Type *t_;
				F& f_;
			};

			template<typename T, typename F>
			struct ObjectGuard
			{
				ObjectGuard(T*t, F fDeleter, pdfWriterHandler& h)
					:t_(t), fDeleter_(fDeleter), H_(h)
				{
					std::cout << "start ObjectGuard" << std::endl;
				}

				~ObjectGuard()
				{
					if (t_)
					{
						//fDeleter_(t_);
						//t_ = NULL;
					}
				}

				T* operator()(){return t_;}
				const T* operator()()const {return t_;}

				pdfWriterHandler &H_;
				T* t_;
				F fDeleter_;
				//F f_;
			};
			namespace rect
			{
				bool predShowBorder(const CRectReportElement& rectElem, const CTextValue& txt_value);

				void draw(const CRectReportElement& p, const CReportElement& elem, pdfWriterHandler& H, const CReportSheet& sheet, QPainter *dc);
				void drawImage(const CPictureElement& p, pdfWriterHandler& H, const CReportSheet& sheet, QPainter *dc);
			}
			void drawElement(const CReportElement* p_elem, CReportSheet& sheet, pdfWriterHandler& H, QPainter *dc);
		}
		namespace dbg
		{
			void tst_Color(pdfWriterHandler& H);
			void tst_qpdf2(pdfWriterHandler& H);
			void tst_3(pdfWriterHandler& H);
		}

	}
			
namespace auxPdfWriter
{
	struct hlp
	{
		static reportCtr::pdfWriterHandler mkHandler(const char* fullName);
		static reportCtr::pdfWriterHandler* mkPHandler(const char* fullName);
		static reportCtr::pdfWriterHandler* mkPHandlerDef();
		static void makePdfWithMgr(const CaplReportMgr& repMgr, reportCtr::pdfWriterHandler& H, const char* fullPdfName, int debugLevel);
		static int genRep(const char* fullDotName, const char* fullSourceName, const char* fullOutputReportName);
		static int mkPdf(const char* fullReportName, reportCtr::pdfWriterHandler& H, const char* fullPdfName, int debugLevel);
		static bool splitRep(const char* rep1, const char* rep2, const char* repRes);
		//
		//static void Do_reportMgrToPdf(const CString &exportFileName, const CaplReportMgr& m_ReportMgr);
	};

	//
namespace magic
{
namespace FontSize
{
	inline
	const double& getMult()
	{
		static const double mult = 1.0*24/(45.0*25);
		return mult;
	}
}
namespace Degree
{
	//inline
	//const double& getMultFromLogFont()
	//{
	//	static const double mult = 1.0*10.0;
	//	return mult;
	//}
}
}
}
}