// PrintGant.cpp: implementation of the CPrintGant class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "PrintGant.h"
#include "SetupPrintDlg.h"
#include <apl_gui.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CaplPrintGant::CaplPrintGant()
{
	memset(&m_text_lf,0,sizeof(LOGFONT));
	memset(&m_title_lf,0,sizeof(LOGFONT));
	m_title_lf.lfHeight = 140;
	m_title_lf.lfCharSet = RUSSIAN_CHARSET;

	m_text_lf.lfHeight = 120;
	m_text_lf.lfCharSet = RUSSIAN_CHARSET;

	m_hPages = 1;
	m_TitleCY = 0;
	m_RowCY = 0;
	m_dTitleCY = 0;
	m_dRowCY = 0;
	m_tree_CX = 0;
	m_gant_CX = 0;
}

CaplPrintGant::~CaplPrintGant()
{

}

bool CaplPrintGant::SetupPrinter()
{
	CSetupPrintDlg dlg;
	if(dlg.DoModal()!=IDOK) return false;
	m_hPages = dlg.m_hPages;
	return true;
}

bool CaplPrintGant::PrintGant(CaplTreeListCtrl* Ctrl)
{
	if(Ctrl==NULL) return false;
	m_TLCtrl = Ctrl;
	m_tree_CX = m_TLCtrl->GetColumnsWidth();
	m_gant_CX = 0;

	if(!SetupPrinter()) return false;

	CDC PrintDC;
	if(!AfxGetApp()->CreatePrinterDC(PrintDC))
	{
		AfxMessageBox(_T("Cann't create printer DC."));
		return false;
	}
	//Расчет количества страниц по вертикали.
	int mm = PrintDC.SetMapMode(MM_LOMETRIC);
	
	int PageCy = PrintDC.GetDeviceCaps(VERTSIZE)*10;
	
	m_title_font.CreatePointFontIndirect(&m_title_lf,&PrintDC);
	m_text_font.CreatePointFontIndirect(&m_text_lf,&PrintDC);
	
	CFont *old = PrintDC.SelectObject(&m_title_font);
	TEXTMETRIC TextMetric;
	PrintDC.GetTextMetrics(&TextMetric);
	m_TitleCY = TextMetric.tmHeight  + TextMetric.tmDescent;
	m_dTitleCY = TextMetric.tmExternalLeading;
	
	PrintDC.SelectObject(&m_text_font);
	PrintDC.GetTextMetrics(&TextMetric);
	m_RowCY = TextMetric.tmHeight  + TextMetric.tmDescent;
	m_dRowCY = TextMetric.tmExternalLeading;

	int PageCnt = 0;
	int RowCY = PageCy - m_TitleCY - 2*m_dTitleCY - 2*m_dRowCY;
	int rec_cnt = Ctrl->GetVisibleCount();

	double tmp = double(rec_cnt*m_RowCY+rec_cnt*m_dRowCY)/double(PageCy);
	PageCnt = int(tmp);
	if(tmp>PageCnt) PageCnt++;

	{
		int cx = PrintDC.GetDeviceCaps(HORZSIZE)*10;//В пикселях (0.1 мм)
		int cy = PrintDC.GetDeviceCaps(VERTSIZE)*10;//В пикселях (0.1 мм)
		int CX = cx*m_hPages;
		int m_screen_cx = m_tree_CX +  m_gant_CX;
		double pc = double(m_gant_CX)/double(m_screen_cx);
		int gant_cx = int(CX*pc);
		int table_cx = CX - gant_cx;
		//Распределение столбцов
		CArray<ColData*, ColData*> Cols;//Массив хранящий ширину и расположение каждого столбца
		int i, cnt = m_TLCtrl->GetColumnsNum();
		int cur_pos = 0;
		int pages = 1;
		CaplTreeListHeaderCtrl* head = &m_TLCtrl->m_wndHeader;
		for(i=0; i<cnt; i++)
		{
			ColData* cd = new ColData;
			cd->cdInd = i;
			int w = m_TLCtrl->GetColumnWidth(i);

			HDITEM item;
			TCHAR buf[256];
			item.mask = HDI_TEXT | HDI_WIDTH;
			item.pszText = buf;
			item.cchTextMax = 256;
			head->GetItem(i,&item);
			cd->cdName = item.pszText;

			double pc = double(w)/double(m_tree_CX);
			cd->cdWidth = int(table_cx*pc);
			int XCenter = cur_pos  + cd->cdWidth/2;
			if(XCenter>cx*pages)
			{
				cur_pos = cx*pages;
				pages++;
			}
			else if(cd->cdWidth+cur_pos>cx*pages)
				cd->cdWidth = cx*pages - cur_pos;
			cd->cdPosX = cur_pos;
			cur_pos+=cd->cdWidth;
			Cols.Add(cd);
		}
		//У последнего получаем координату Х и корректируем gant_cx;
		ColData* cd = Cols.GetAt(Cols.GetSize()-1);
		gant_cx = CX - cd->cdPosX - cd->cdWidth;
		cnt = Cols.GetSize();
		for(i=0; i<cnt; i++)
		{
			delete Cols.GetAt(i);
		}
		Cols.RemoveAll();
		if(gant_cx<0) 
		{
			AfxMessageBox(APL_T("В результате распределения столбцов ширина зоны Диаграммы Ганта меньше 0."));
			return false;
		}
	}

	PrintDC.StartDoc(APL_T("Диаграмма Ганта"));
	for(int i=0; i<PageCnt; i++)
	{
		for(int j=0; j<m_hPages;j++)
		{
			PrintDC.StartPage();
			Print(&PrintDC,j,i);
			PrintDC.EndPage();
		}
	}
	PrintDC.EndDoc();
	PrintDC.SelectObject(old);
	PrintDC.SetMapMode(mm);
	m_text_font.DeleteObject();
	m_title_font.DeleteObject();

	PrintDC.DeleteDC();
	return true;
}

int CaplPrintGant::Print(CDC *pDC, int cur_hPage, int cur_page)
{
	//Определение суммарной ширины листа и распределение столбцов.
	int cx = pDC->GetDeviceCaps(HORZSIZE)*10;//В пикселях (0.1 мм)
	int cy = pDC->GetDeviceCaps(VERTSIZE)*10;//В пикселях (0.1 мм)
	int CX = cx*m_hPages;
	int m_screen_cx = m_tree_CX +  m_gant_CX;
	double pc = double(m_gant_CX)/double(m_screen_cx);
	int gant_cx = int(CX*pc);
	int table_cx = CX - gant_cx;
	//Распределение столбцов
	CArray<ColData*, ColData*> Cols;//Массив хранящий ширину и расположение каждого столбца
	int i, cnt = m_TLCtrl->GetColumnsNum();
	int cur_pos = 0;
	int pages = 1;
	CaplTreeListHeaderCtrl* head = &m_TLCtrl->m_wndHeader;
	for(i=0; i<cnt; i++)
	{
		ColData* cd = new ColData;
		cd->cdInd = i;
		int w = m_TLCtrl->GetColumnWidth(i);

		HDITEM item;
		TCHAR buf[256];
		item.mask = HDI_TEXT | HDI_WIDTH;
		item.pszText = buf;
		item.cchTextMax = 256;
		head->GetItem(i,&item);
		cd->cdName = item.pszText;

		double pc = double(w)/double(m_tree_CX);
		cd->cdWidth = int(table_cx*pc);
		int XCenter = cur_pos  + cd->cdWidth/2;
		if(XCenter>cx*pages)
		{
			cur_pos = cx*pages;
			pages++;
		}
		else if(cd->cdWidth+cur_pos>cx*pages)
			cd->cdWidth = cx*pages - cur_pos;
		cd->cdPosX = cur_pos;
		cur_pos+=cd->cdWidth;
		Cols.Add(cd);
	}
	//У последнего получаем координату Х и корректируем gant_cx;
	ColData* cd = Cols.GetAt(Cols.GetSize()-1);
	gant_cx = CX - cd->cdPosX - cd->cdWidth;
	if(gant_cx<0) 
	{
		AfxMessageBox(_T(""));
	}

	//Смещение начала координат для отображение необходимой области печати.
	int dx = cx*cur_hPage;
	CPoint old_org_pt = pDC->SetWindowOrg(CPoint(dx,0));

	//Отображение Заголовков.
	pDC->SelectObject(&m_title_font);
	cnt = m_TLCtrl->GetColumnsNum();
	int y = 0;
	for(i = 0; i<cnt;i++)
	{
		ColData* cd = Cols.GetAt(i);
		DrawTextInRect(pDC, cd->cdName, cd->cdPosX,0,cd->cdWidth,m_TitleCY);
	}
	y-=m_TitleCY;

	//Отрисовка таблицы
	pDC->SelectObject(&m_text_font);
	HTREEITEM ht = m_TLCtrl->GetFirstVisibleItem();
	while (ht!=NULL)
	{
		for(int j=0; j<cnt;j++)
		{
			CString str;
			str = m_TLCtrl->GetItemText(ht,j);
			ColData* cd = Cols.GetAt(j);
			DrawTextInRect(pDC,str,cd->cdPosX,y,cd->cdWidth, m_RowCY,APL_DM_TEXT|APL_DM_VLINES);
		}
		ht = m_TLCtrl->GetNextVisibleItem(ht);
		y-=m_RowCY;
	}
	

	//Удаление Cols
	cnt = Cols.GetSize();
	for(i=0; i<cnt; i++)
	{
		delete Cols.GetAt(i);
	}
	Cols.RemoveAll();

	pDC->SetWindowOrg(old_org_pt);

	return 0;
}

void CaplPrintGant::DrawTextInRect(CDC *pDC, CString text, int x, int y, int cx, int cy, UINT mode)
{
	if(cy<0)
		cy = pDC->GetTextExtent(text).cy;
	if(mode&APL_DM_RECT)
	{
		pDC->MoveTo(x,y);
		pDC->LineTo(x+cx-1,y);
		pDC->LineTo(x+cx-1,y-cy);
		pDC->LineTo(x,y-cy);
		pDC->LineTo(x,y);
	}
	if(mode&APL_DM_VLINES)
	{
		pDC->MoveTo(x,y);
		pDC->LineTo(x,y-cy);
		pDC->MoveTo(x+cx-1,y);
		pDC->LineTo(x+cx-1,y-cy);
	}
	if(mode&APL_DM_HLINES)
	{
		pDC->MoveTo(x,y);
		pDC->LineTo(x+cx-1,y);
		pDC->MoveTo(x,y-cy);
		pDC->LineTo(x+cx-1,y-cy);
	}
	if(APL_DM_TEXT)
	{
		if(pDC->GetTextExtent(text).cx>cx)
		{
			int cx3 = pDC->GetTextExtent(_T("...")).cx;
			while(pDC->GetTextExtent(text).cx>cx-cx3)
			{
				text = text.Left(text.GetLength()-1);
				if(text.IsEmpty()) break;
			}
			text+=_T("...");
		}
		int tx, ty;
		int tcy;
		tcy = pDC->GetTextExtent(text).cy;
		tx = x + 1;
		ty = y - int((cy - tcy)/2);
		pDC->TextOut(tx,ty,text);
	}
}
