#include "stdafx.h"
#include "TemplateMaster.h"
#include "resource.h"
#include "TemplateMasterDlg.h"

CTemplateMaster::CTemplateMaster(CaplReportMgr* ReportMgr)
{
	ASSERT(ReportMgr);
	ASSERT(ReportMgr->m_data);
	ASSERT(ReportMgr->m_data->IsDictLoad());
	m_ReportMgr = ReportMgr;
	if(m_ReportMgr->m_data_source.GetHeader())
		m_pInitialHeader = m_ReportMgr->m_data_source.GetHeader();
	m_pHeader = new CHeader(ReportMgr);
	m_page_sizes = CSize(2970, 2100);
	m_table_rect = CRect(0, -2100, 2970, 0);
	m_ColumnsArray.RemoveAll();
	m_GroupsArray.RemoveAll();
	m_SortsArray.RemoveAll();
	m_table_line_width = 0;
	m_title_line_width = 0;

	m_align = 0;
	m_print_footer = false;

	memset(&m_DefHeaderFont, 0, sizeof(LOGFONT));
	m_DefHeaderFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
	m_DefHeaderFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
	m_DefHeaderFont.lfQuality = DEFAULT_QUALITY;
	m_DefHeaderFont.lfPitchAndFamily = DEFAULT_PITCH;
	m_DefHeaderFont.lfWidth = 0;
	m_DefHeaderFont.lfOrientation = 0;
	m_DefHeaderFont.lfStrikeOut = 0;
	m_DefHeaderFont.lfItalic = 0;
	m_DefHeaderFont.lfUnderline = 0;
	m_DefHeaderFont.lfEscapement = 0;
	m_DefHeaderFont.lfHeight = 100;
	m_DefHeaderFont.lfWeight = FW_BOLD;
	m_DefHeaderFont.lfCharSet = RUSSIAN_CHARSET;
	_strcpy(m_DefHeaderFont.lfFaceName,_T("Arial"));

	m_DefRowFont = m_DefHeaderFont;
	m_DefRowFont.lfWeight = FW_NORMAL;
	m_DefRowFont.lfHeight = 80;

	m_DefGroupFont = m_DefRowFont;

	m_DefFooterFont = m_DefRowFont;
	m_DefFooterFont.lfItalic = 1;
}

CTemplateMaster::~CTemplateMaster()
{
	try
	{
		delete m_pHeader;
	}
	catch(...)
	{
		TRACE(APL_T("Заголовок уже был удален!\n"));
	}
	//удаляем массивы группировок и отображения колонок
	try
	{
		int i;
		for(i=0; i<m_GroupsArray.GetSize(); i++)
			delete m_GroupsArray[i];
		for(i=0; i<m_ColumnsArray.GetSize(); i++)
			delete m_ColumnsArray[i];
	}
	catch(...) {
	}
	m_GroupsArray.RemoveAll();
	m_ColumnsArray.RemoveAll();
	//Сортироку удалят в другом месте
	m_SortsArray.RemoveAll();
}

bool CTemplateMaster::DoTemplate()
{
	HINSTANCE hCurInst = AfxGetResourceHandle();
	AfxSetResourceHandle(dllInst);
	CTemplateMasterDlg dlg(m_ReportMgr, this);
	dlg.m_bEnableSelectPage = m_ReportMgr->m_data_source.GetHeader()==NULL;
	if(dlg.DoModal()==IDOK)
	{
		AfxSetResourceHandle(hCurInst);
		return CreateTemplate();
	}
	AfxSetResourceHandle(hCurInst);
	return false;
}

bool CTemplateMaster::CreateTemplate()
{
	CaplInstance	*Report(NULL);
	CRectReportElement	*pElem(NULL);
	CTableElement	*pTable(NULL);
	CHeaderColumn	*pHeaderColumn(NULL);
	aplExtent		ext;
	CString			BufStr;
	CDC				dc;
	LOGFONT			HeaderFont = m_DefHeaderFont;
	LOGFONT			GroupFont = m_DefGroupFont;
	LOGFONT			RowFont = m_DefRowFont;
	LOGFONT			FooterFont = m_DefFooterFont;
	PRINTDLG		PrnDlg;
	int				i, cnt, MaxHeight, h, j;
	int				fit_to_page_by_print = 1, report_mode = 0, orient;
	int				CurX;
	CFont			font;
	CStringArray	strs;
	TEXTMETRIC		tm;
	CReportSection	*pSection(NULL);
	CSectionLevel	*pLevel(NULL);
	CColumn			*pLevelColumn(NULL);
	CTMColumn		*pTMCol(NULL);
	CGroupCol		*pGrCol(NULL);
	CTMGroupCol		*pTMGrcol(NULL);
	CTMColumn		*pCurTMCol(NULL);

	TGroupColVector	cols2del;

	try
	{
		//Инициализация информации о принтере
		memset(&PrnDlg, 0, sizeof(PRINTDLG));
		AfxGetApp()->GetPrinterDeviceDefaults(&PrnDlg);
		if(PrnDlg.hDevMode==NULL || PrnDlg.hDevNames==NULL) 
		{
			TRACE_TO_FILE(APL_T("В системе не установлен принтер. Генерация отчета невозможна!"));
			return NULL;
		}

		AfxGetApp()->CreatePrinterDC(dc);
		dc.SetMapMode(MM_LOMETRIC);
		font.CreatePointFontIndirect(&HeaderFont, &dc);
		dc.SelectObject(font);

		m_ReportMgr->m_data->GetEntityExtent(m_ReportMgr->e_apl_report, ext);
		if(ext.GetSize()>0)
			Report = ext[0];
		if(Report==NULL)
		{
			//создаем инстанс отчета
			Report = m_ReportMgr->m_data->CreateInstance(m_ReportMgr->e_apl_report);
		}

		fit_to_page_by_print = TRUE;
		report_mode = 0;
		orient = m_page_sizes.cx>m_page_sizes.cy ? 1 : 0;
		m_ReportMgr->m_data->PutAttr(Report, m_ReportMgr->a_apl_report_fit_to_page, fit_to_page_by_print);
		m_ReportMgr->m_data->PutAttr(Report, m_ReportMgr->a_rep_mode, report_mode);
		//	m_ReportMgr->PutPoint(Report, m_ReportMgr->a_apl_report_page_size, m_page_sizes);
		//	m_ReportMgr->m_data->PutAttr(Report, m_ReportMgr->a_apl_report_page_orient, orient);
		//Удаляем существующие страницы
		while(m_ReportMgr->m_sheets.GetSize()>0)
			m_ReportMgr->m_sheets.GetAt(0)->Delete();
		//создаем единственную страницу
		m_pSheet = new CReportSheet(m_ReportMgr);
		m_pSheet->LoadElementsFromFile();
		m_pSheet->m_size = m_page_sizes;

		// Определяем высоту титла
		int TitleHeight = 0;
		//dc.GetTextMetrics(&tm);
		// Создаем в шапке прямоугольники с параметрами
		std::vector<int> param_heights;
		param_heights.resize(m_ReportMgr->m_data_source.m_RParams.GetSize(), 0);
		CString sParamName, sParamValue;
		for(i=0; i<m_ReportMgr->m_data_source.m_RParams.GetSize(); ++i)
		{
			CString sParamName = m_ReportMgr->m_data_source.m_RParams[i]->m_name;
			CString sParamValue = m_ReportMgr->m_data_source.m_RParams[i]->m_value;

			int iRows = 0;
			int iCur = -1;
			do
			{
				++iCur;
				++iRows;
				iCur=sParamValue.Find(_T("\r\n"), iCur);
			}while(iCur>-1);

			int iCurHeight(0);
			if (sParamName.CompareNoCase(_T("title")) == 0)
			{
				iCurHeight = HeaderFont.lfHeight;
			}
			else
			{
				iCurHeight = RowFont.lfHeight;
			}

			//int iCurHeight = tm.tmHeight*iRows;
			TitleHeight += iCurHeight;
			param_heights[i] = iCurHeight;
		}

		CString sTitle;
		int iPrevHeight = 0;
		for(i=0; i<m_ReportMgr->m_data_source.m_RParams.GetSize(); ++i)
		{
			CString sParamName = m_ReportMgr->m_data_source.m_RParams[i]->m_name;
			CString sParamValue = m_ReportMgr->m_data_source.m_RParams[i]->m_value;

			int iCurHeight = 0;
			for(j=0; j<=i; ++j)
				iCurHeight += param_heights[j];

			pElem = new CRectReportElement(m_ReportMgr);
			pElem->SetRect(CRect(m_table_rect.left, m_table_rect.bottom-iCurHeight, m_table_rect.right, m_table_rect.bottom-iPrevHeight), 1);
			pElem->m_value.SetText(sParamValue);
			if (sParamName.CompareNoCase(_T("title"))==0)
			{
				sTitle = sParamValue;
				pElem->m_value.m_font = HeaderFont;
				pElem->m_value.m_align = AT_CENTER|AT_TOP;
			}
			else
			{
				pElem->m_value.m_font = RowFont;
				pElem->m_value.m_align = AT_RIGHT;
			}
			pElem->m_line_width = 0;
			m_pSheet->Add(pElem);

			iPrevHeight = iCurHeight;
		}

		// Нижний колонтитул
		int FooterHeight(0);
		if (m_print_footer)
		{
			FooterHeight = 50;

			// общее кол-во страниц
			pElem = new CRectReportElement(m_ReportMgr);
			if (pElem)
			{
				pElem->SetRect(CRect(m_table_rect.right - 100, m_table_rect.top, m_table_rect.right, m_table_rect.top + FooterHeight), 1);
				pElem->m_value.m_font = FooterFont;
				pElem->m_value.m_align = AT_CENTER | AT_VCENTER;
				pElem->m_line_width = 0;

				CReportParam* par = 0;
				int ind = m_ReportMgr->m_data_source.m_params.Find(STATIC_PAGE_COUNT);
				if (ind < 0)
				{
					par = new CReportParam(m_ReportMgr);
					if (par)
					{
						par->SetType(STATIC_PAGE_COUNT);
						par->m_name = APL_T("Локальное количество страниц");
						par->Update(true);	// сохраняем в степ-дату
					}
				}
				else
				{
					par = m_ReportMgr->m_data_source.m_params.GetAt(ind);
				}
				pElem->m_value.SetText(par);

				m_pSheet->Add(pElem);
			}

			// прямоугольник "из"
			pElem = new CRectReportElement(m_ReportMgr);
			if (pElem)
			{
				pElem->SetRect(CRect(m_table_rect.right - 150, m_table_rect.top, m_table_rect.right - 100, m_table_rect.top + FooterHeight), 1);
				pElem->m_value.SetText(APL_T("из"));
				pElem->m_value.m_font = FooterFont;
				pElem->m_value.m_align = AT_CENTER | AT_VCENTER;
				pElem->m_line_width = 0;
				m_pSheet->Add(pElem);
			}

			// номер страницы
			pElem = new CRectReportElement(m_ReportMgr);
			if (pElem)
			{
				pElem->SetRect(CRect(m_table_rect.right - 250, m_table_rect.top, m_table_rect.right - 150, m_table_rect.top + FooterHeight), 1);
				pElem->m_value.m_font = FooterFont;
				pElem->m_value.m_align = AT_CENTER | AT_VCENTER;
				pElem->m_line_width = 0;

				CReportParam* par = 0;
				int ind = m_ReportMgr->m_data_source.m_params.Find(STATIC_PAGE_NUM);
				if (ind < 0)
				{
					par = new CReportParam(m_ReportMgr);
					if (par)
					{
						par->SetType(STATIC_PAGE_NUM);
						par->m_name = APL_T("Локальный номер страницы");
						par->Update(true);	// сохраняем в степ-дату
					}
				}
				else
					par = m_ReportMgr->m_data_source.m_params.GetAt(ind);
				pElem->m_value.SetText(par);

				m_pSheet->Add(pElem);
			}

			// надпись "Стр."
			pElem = new CRectReportElement(m_ReportMgr);
			if (pElem)
			{
				pElem->SetRect(CRect(m_table_rect.right - 350, m_table_rect.top, m_table_rect.right - 250, m_table_rect.top + FooterHeight), 1);
				pElem->m_value.SetText(APL_T("Стр."));
				pElem->m_value.m_font = FooterFont;
				pElem->m_value.m_align = AT_RIGHT | AT_VCENTER;
				pElem->m_line_width = 0;
				m_pSheet->Add(pElem);
			}

			// титл
			// пока не нужен - это на будущее для варианта с продолжением таблицы на 2 листе без заголовка
			//pElem = new CRectReportElement(m_ReportMgr);
			//if (pElem)
			//{
			//	pElem->SetRect(CRect(m_table_rect.left, m_table_rect.top, m_table_rect.right - 350, m_table_rect.top + FooterHeight), 1);
			//	pElem->m_value.SetText(sTitle);
			//	pElem->m_value.m_font = FooterFont;
			//	pElem->m_value.m_align = AT_LEFT | AT_VCENTER;
			//	pElem->m_line_width = 0;
			//	m_pSheet->Add(pElem);
			//}
		}

		//создаем заголовочные элементы
		//ширину элементов назначаем автоматически
		//высоту элементов рассчитываем
		//текст заголовка - имена колонок таблицы
		cnt = m_ColumnsArray.GetSize();

		//Определяем максимальную высоту таблицы, но не допускаем высоту таблицы более половины высоты страницы
		//и создаем описание источника данных
		MaxHeight = 0;
		for(i=0; i<cnt; i++)
		{
			pTMCol = m_ColumnsArray[i];
			pHeaderColumn = pTMCol->pColumn;
			BufStr = pTMCol->sTitle;
			//Определяем высоту текста при заданной ширине
			CTextValue::BreakString(&strs, pTMCol->iWidth-60-m_title_line_width, &dc, BufStr);
			dc.GetTextMetrics(&tm);
			h = (tm.tmAscent)*(strs.GetSize()+1)+(tm.tmExternalLeading+tm.tmDescent)*strs.GetSize();
			MaxHeight = MaxHeight>h ? MaxHeight : h;
			m_ReportMgr->m_base_query->AddColumn(pHeaderColumn->m_name, pHeaderColumn->m_type);
		}
		MaxHeight = MaxHeight>m_page_sizes.cy/2 ? m_page_sizes.cy/2 : MaxHeight;

		//Создаем элементы заголовка.
		CurX = m_table_rect.left;
		for(i=0; i<cnt; i++)
		{
			pTMCol = m_ColumnsArray[i];
			BufStr = pTMCol->sTitle;
			pElem = new CRectReportElement(m_ReportMgr);
			pElem->SetRect(CRect(CurX, m_table_rect.bottom-MaxHeight-TitleHeight, CurX+pTMCol->iWidth, m_table_rect.bottom-TitleHeight), 1);
			pElem->m_value.SetText(BufStr);
			pElem->m_value.m_font = HeaderFont;
			pElem->m_line_width = m_title_line_width;
			m_pSheet->Add(pElem);
			CurX+=pTMCol->iWidth;
		}

		pTable = new CTableElement(m_ReportMgr);
		m_table_rect.bottom-=MaxHeight;
		m_table_rect.bottom-=TitleHeight;
		m_table_rect.top += FooterHeight;
		pTable->SetRect(m_table_rect, 1);
		//Создаем секцию
		pSection = new CReportSection(m_ReportMgr);
		pSection->m_name = APL_T("Секция 1");
		pTable->m_sections.Add(pSection);
		pTable->m_line_width = 0;
		pTable->m_row_lf = RowFont;

		//Создаем группы
		for(i=0; i<m_GroupsArray.GetSize(); i++)
		{
			pTMGrcol = m_GroupsArray[i];
			pHeaderColumn = m_ReportMgr->m_base_query->GetColumn(m_ReportMgr->m_base_query->Find(pTMGrcol->pColumn->GetName()));
			pGrCol = new CGroupCol(m_ReportMgr);
			cols2del.push_back(pGrCol);
			pGrCol->m_lf = GroupFont;
			pGrCol->m_name = pTMGrcol->pColumn->GetName();
			pGrCol->m_col = pHeaderColumn;
			pGrCol->m_draw_first_row = pTMGrcol->iMode==1 ? 1:0;
			if(pTMGrcol->iMode==1) //Формируем заголовок группы как строку
			{
				//создаем один уровень и в нем строку
				pLevel = new CSectionLevel(m_ReportMgr);
				pLevel->m_name = _T("A");
				pLevel->m_height = 80;
				pGrCol->m_row.Add(pLevel);
				cnt = m_ColumnsArray.GetSize();
				bool bFill = false;
				for(j=0; j<cnt; j++)
				{
					pCurTMCol = m_ColumnsArray[j];
					if(pCurTMCol->pColumn==pTMGrcol->pColumn)
						bFill = true;
					pHeaderColumn = m_ReportMgr->m_base_query->GetColumn(m_ReportMgr->m_base_query->Find(pCurTMCol->pColumn->GetName()));
					BufStr = pCurTMCol->sTitle;
					pLevelColumn = new CColumn(m_ReportMgr);
					pLevelColumn->m_name = BufStr;
					if(bFill)
						pLevelColumn->m_ds_column = pHeaderColumn;
					else
						pLevelColumn->m_ds_column = NULL;
					pLevelColumn->m_width = pCurTMCol->iWidth;
					pLevelColumn->m_SpacePara = aplSpacePara15;
					pLevelColumn->m_border = m_table_line_width;
					if (m_align > 0)
					{
						pLevelColumn->m_align = m_align;
					}
					pLevel->m_columns.Add(pLevelColumn);
				}
			}
			else //Формируем заголовок группы как заголовок
			{
				//создаем один уровень и в нем строку
				pLevel = new CSectionLevel(m_ReportMgr);
				pLevel->m_name = _T("A");
				pLevel->m_height = 80;
				pGrCol->m_row.Add(pLevel);
				cnt = m_ColumnsArray.GetSize();
				for(j=0; j<cnt; j++)
				{
					pCurTMCol = m_ColumnsArray[j];
					pHeaderColumn = m_ReportMgr->m_base_query->GetColumn(m_ReportMgr->m_base_query->Find(pCurTMCol->pColumn->GetName()));
					BufStr = pCurTMCol->sTitle;
					pLevelColumn = new CColumn(m_ReportMgr);
					pLevelColumn->m_name = BufStr;
					if(pCurTMCol->pColumn==pTMGrcol->pColumn)
						pLevelColumn->m_ds_column = pHeaderColumn;
					else
						pLevelColumn->m_ds_column = NULL;
					pLevelColumn->m_width = pCurTMCol->iWidth;
					pLevelColumn->m_SpacePara = aplSpacePara15;
					pLevelColumn->m_border = m_table_line_width;
					if (m_align > 0)
					{
						pLevelColumn->m_align = m_align;
					}
					pLevel->m_columns.Add(pLevelColumn);
				}
			}
			pSection->m_groups.Add(pGrCol);
		}
		//создаем поля сортировки
		CSortColumn* pSortCol;
		for(i=0; i<m_SortsArray.GetSize(); i++)
		{
			pSortCol = new CSortColumn(m_ReportMgr);
			pHeaderColumn = m_ReportMgr->m_base_query->GetColumn(m_ReportMgr->m_base_query->Find(m_SortsArray[i]->GetName()));
			pSortCol->m_column = pHeaderColumn;
			pSection->m_sorts.Add(pSortCol);
		}
		//заполняем строку секции
		//при этом никогда не заполняются поля по которым осуществляются группировки
		pLevel = new CSectionLevel(m_ReportMgr);
		pLevel->m_name = _T("A");
		pLevel->m_height = 80;
		pSection->m_levels.Add(pLevel);
		cnt = m_ColumnsArray.GetSize();
		for(i=0; i<cnt; i++)
		{
			pTMCol = m_ColumnsArray[i];
			pHeaderColumn = m_ReportMgr->m_base_query->GetColumn(m_ReportMgr->m_base_query->Find(pTMCol->pColumn->GetName()));
			BufStr = pTMCol->sTitle;
			pLevelColumn = new CColumn(m_ReportMgr);
			pLevelColumn->m_name = BufStr;
			if(!pTMCol->bGroup)
				pLevelColumn->m_ds_column = pHeaderColumn;
			else
				pLevelColumn->m_ds_column = NULL;
			pLevelColumn->m_width = pTMCol->iWidth;
			pLevelColumn->m_SpacePara = aplSpacePara15;
			pLevelColumn->m_border = m_table_line_width;
			if (m_align>0)
			{
				pLevelColumn->m_align = m_align;
			}
			pLevel->m_columns.Add(pLevelColumn);
		}

		m_pSheet->Add(pTable);
		m_ReportMgr->m_base_query->Update();
		m_pSheet->Update();
		ext.Clear();
		ext.Add(m_pSheet->m_inst);
		m_ReportMgr->m_sheets.Add(m_pSheet);
		m_ReportMgr->m_data->PutAttr(Report, m_ReportMgr->a_rep_sheets, ext);
		m_ReportMgr->m_data->PutAttr(Report, m_ReportMgr->a_rep_binding,0);

		dc.DeleteDC();

	}
	catch (...)
	{
		if(pTable) delete pTable;
		for(UINT ind=0; ind<cols2del.size(); ++ind)
			if(cols2del[ind]) delete cols2del[ind];
	}

	return true;
}

bool CTemplateMaster::DoAutoTemplate()
{
	int w, h, i;
	CTMColumn* pCol;

	double dHeight = 210.0;
	double dWidth = 297.0;
	double dLeft = 0.0;
	double dBottom = 0.0;
	double dRight = 0.0;
	double dTop = 0.0;

	w = int(dWidth*10);
	h = int(dHeight*10);
	int l, r, t, b;
	l = int(dLeft*10);
	t = int(dTop*10);
	r = int((dWidth-dRight)*10);
	b = int((dHeight-dBottom)*10);

	m_page_sizes = CSize(w, h);
	m_table_rect = CRect(l, -b, r, -t);

	m_ColumnsArray.RemoveAll();
	if (m_pInitialHeader==NULL || m_pInitialHeader->GetSize()==0)
		return false;

	int Width = 2970/m_pInitialHeader->GetSize();
	for(i=0; i<m_pInitialHeader->GetSize(); i++)
	{
		CHeaderColumn* pHeaderCol = m_pInitialHeader->GetColumn(i);
		//Если мы найдем такую колонку в группах, то поставим соответствующий флаг
		bool bFind = false;
		for(int j=0; j<m_GroupsArray.GetSize(); j++)
		{
			if(m_GroupsArray[j]->pColumn==pHeaderCol)
			{
				bFind = true;
				break;
			}
		}
		if(bFind) continue;

		CString buf = pHeaderCol->GetName();

		CTMColumn* pTMCol = new CTMColumn;
		pTMCol->pColumn = pHeaderCol;
		pTMCol->iWidth = Width;
		pTMCol->sTitle = buf;
		pTMCol->bGroup = false;

		m_ColumnsArray.Add(pTMCol);
	}

	// пересчитываем ширину полей
	int cx = int((dWidth-dLeft-dRight)*10);
	int delta = 0, c_width=0;
	int width = (int)(cx/m_ColumnsArray.GetSize());
	CString buf;
	c_width=width*m_ColumnsArray.GetSize();
	delta = cx-c_width;

	buf.Format(_T("%.1f"), (double)width/10);
	for(i=0; i<m_ColumnsArray.GetSize(); i++)
	{
		pCol = m_ColumnsArray[i];
		pCol->iWidth = width;
		if(delta>0)
		{
			pCol->iWidth = width+delta;
			delta=0;
			continue;
		}
	}

	double dTableLineWidth = ((double)AfxGetApp()->GetProfileInt(_T("DefaultSettings"),_T("LineWidth"),1))/10;
	double dTitleLineWidth = ((double)AfxGetApp()->GetProfileInt(_T("DefaultSettings"),_T("LineWidth"),1))/10;
	m_table_line_width = int(dTableLineWidth*10);
	m_title_line_width= int(dTitleLineWidth*10);

	return CreateTemplate();
}