// ReportView.cpp : implementation file
//

#include "stdafx.h"
#include "ReportView.h"
#include "CommonQuery.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define PAGE_A1 8410, 5940
#define PAGE_A2 5940, 4210
#define PAGE_A3 4210, 2970
#define PAGE_A4 2970, 2100
#define PAGE_A5 2100, 1480

/////////////////////////////////////////////////////////////////////////////
// CReportView
IMPLEMENT_DYNCREATE(CReportView, CScrollView)

BEGIN_MESSAGE_MAP(CReportView, CScrollView)
	//{{AFX_MSG_MAP(CReportView)
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CReportView::CReportView():CScrollView()
{
	m_ReportMgr.Init();

	m_bFitToClient = false;
	m_bUseEdit = false;

	if(_pPrinterDC==NULL)
	{
		_pPrinterDC = new CDC;
		PRINTDLG dlg;
		memset(&dlg, 0, sizeof(PRINTDLG));
		AfxGetApp()->GetPrinterDeviceDefaults(&dlg);
		ASSERT(dlg.hDevMode);
		AfxGetApp()->CreatePrinterDC(*_pPrinterDC);
	}
}

CReportView::~CReportView()
{
	CloseReport();
	int i;
	CString buf;
	for(i=0; i<m_TmpFiles.GetSize(); i++)
	{
		DeleteFile(m_TmpFiles[i]);
	}
}


/////////////////////////////////////////////////////////////////////////////
// CReportView drawing

void CReportView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	// TODO: calculate the total size of this view
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);
}

void CReportView::OnDraw(CDC* pDC)
{
	// TODO: add draw code for native data here
	int i;
	if(m_ReportMgr.m_sheets.GetSize()>0)
	{
		CReportElement *pElem = NULL;
		CReportSheet *pSheet = m_ReportMgr.m_sheets.GetAt(m_CurSheet);
		if(pSheet==NULL) return;
		CSize size = CSize(10, 10);
		size = pSheet->m_size+CSize(10, 10);

		pSheet->SetOrgPt(CPoint(5, 5));
		for(i=0; i<pSheet->m_els.GetSize(); i++)
		{
			pElem = pSheet->m_els.GetAt(i);
			pElem->Draw(pDC, 1, 1);
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
// CReportView diagnostics

#ifdef _DEBUG
void CReportView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CReportView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CReportView message handlers

BOOL CReportView::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
	
	return CScrollView::OnEraseBkgnd(pDC);
}

bool CReportView::CloseReport()
{
	if(m_ReportMgr.m_data==NULL) return true;

	m_ReportMgr.m_data->CloseWithoutClear();
	m_ReportMgr.m_data->ClearData();
	m_ReportMgr.m_data_source.RemoveAll();
	m_ReportMgr.Detach();
	
	return true;
}

bool CReportView::RV_GenerateReport(CStringArray &Templates, CDataSource *pDataSource)
{
	m_LastDotsFiles.RemoveAll();
	m_LastDotsFiles.Append(Templates);
	m_DataSource.RemoveAll();
	CloseReport();
	
	m_CurSheet =0;

	if(Templates.GetSize()==0) return false;

	CString buf, path;
	CString Data, str;
	int i;

	//Проверка на существование шаблона
	CFile file;
	for(i=0; i<Templates.GetSize(); i++)
	{
		if(file.Open(Templates[i], CFile::modeRead)==FALSE)
		{
			Invalidate();
			return false;
		}
		file.Close();
	}
	
	m_ReportMgr.Init();
	m_ReportMgr.m_data_source.RemoveAll();

	CRParamsArray params;

	m_DataSource.CloneDataSource(*pDataSource, NULL);
	m_ReportMgr.m_data_source.CloneDataSource(*pDataSource, &m_ReportMgr);
	
	int r,c;
	m_DataSource.GetSize(r,c);
	
	BeginWaitCursor();
	m_data.SetErorPrintMode(false);

	bool bOk = true;	
	CStringArray rep_paths;
	for(i=0; i<Templates.GetSize(); i++)
	{
		if(i>0)
		{
			m_ReportMgr.Detach();
			m_ReportMgr.Init();
			m_ReportMgr.m_data_source.CloneDataSource(m_DataSource, &m_ReportMgr);
		}
		path.Empty();
		CString sTempEnv; sTempEnv.GetEnvironmentVariable(_T("temp"));
		GetTempFileName(sTempEnv, _T("rep"), 0, path.GetBuffer(MAX_PATH));
		path.ReleaseBuffer();
		::DeleteFile(path);
		path.Replace(_T(".tmp"), _T(".aplrep"));
		if(!GenerateReport(&m_ReportMgr, &params, Templates[i], path))
		{
			bOk = false;
			break;
		}
		else
			rep_paths.Add(path);
	}
	if(bOk)
	{
		//Объединение отчетов
		path.Empty();
		CString sTempEnv; sTempEnv.GetEnvironmentVariable(_T("temp"));
		GetTempFileName(sTempEnv, _T("rep"), 0, path.GetBuffer(MAX_PATH));
		path.ReleaseBuffer();
		::DeleteFile(path);
		path.Replace(_T(".tmp"), _T(".aplrep"));
		UnificationArrayReports(path, &rep_paths);
	}
	
	DWORD attrs;
	for(i=0; i<rep_paths.GetSize(); i++)
	{
		attrs = ::GetFileAttributes(rep_paths[i]);
		if(attrs&FILE_ATTRIBUTE_READONLY)
		{
			attrs&=~FILE_ATTRIBUTE_READONLY;
			::SetFileAttributes(rep_paths[i], attrs);
		}
		::DeleteFile(rep_paths[i]);
	}

	m_ReportMgr.Attach(&m_data, NULL);
	m_TmpFiles.Add(path);
	m_ReportMgr.LoadFromFile(path);
	m_ReportMgr.m_data_source.CloneUserLegendText(m_DataSource, &m_ReportMgr);
	
	Invalidate();
	
	EndWaitCursor();
	
	return true;
}

void CReportView::OnFilePrint() 
{
	PRINTDLG pd;
	AfxGetApp()->GetPrinterDeviceDefaults(&pd);
	CScrollView::OnFilePrint();
}

void CReportView::OnFilePrintDirect() 
{
	CScrollView::OnFilePrint();
}

void CReportView::OnUpdateFilePrint(CCmdUI* pCmdUI)
{
	pCmdUI->Enable(m_ReportMgr.m_sheets.GetSize()>0?TRUE:FALSE);
}

BOOL CReportView::OnPreparePrinting(CPrintInfo* pInfo) 
{
	CReportSheet *pCurSheet = m_ReportMgr.m_sheets[m_CurSheet];

	AfxGetApp()->GetPrinterDeviceDefaults(&pInfo->m_pPD->m_pd);
	DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(pInfo->m_pPD->m_pd.hDevMode);
	if(pDevMode)
	{
		int tmp;
		CSize size = pCurSheet->m_size;
		if(pCurSheet->m_size.cx>pCurSheet->m_size.cy)
		{
			pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
		}
		else 
		{
			pDevMode->dmOrientation = DMORIENT_PORTRAIT ;
			tmp = size.cx;
			size.cx = size.cy;
			size.cy = tmp;
		}
		if(size==CSize(PAGE_A4))
			pDevMode->dmPaperSize = DMPAPER_A4;
		else if(size==CSize(PAGE_A5))
			pDevMode->dmPaperSize = DMPAPER_A5;
		else if(size==CSize(PAGE_A3))
			pDevMode->dmPaperSize = DMPAPER_A3;
		else if(size==CSize(PAGE_A2))
			pDevMode->dmPaperSize = DMPAPER_A2;
		
		::GlobalUnlock(pInfo->m_pPD->m_pd.hDevMode);
	}
	
	return DoPreparePrinting(pInfo);
}

void CReportView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	CScrollView::OnBeginPrinting(pDC, pInfo);
}

void CReportView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo) 
{
	// TODO: Add your specialized code here and/or call the base class
	
	CScrollView::OnEndPrinting(pDC, pInfo);
}

void CReportView::OnPrint(CDC* pDC, CPrintInfo* pInfo) 
{
	int OldMM;
	int cx, cy, pcx, pcy;
	int a4cx, a4cy;

	CReportSheet *pCurSheet = m_ReportMgr.m_sheets[m_CurSheet];
	if(pCurSheet==0) return;

	OldMM = pDC->SetMapMode(MM_LOMETRIC);
	cx=2970; cy=2100; pcx = pCurSheet->m_size.cx; pcy = pCurSheet->m_size.cy;
	a4cx=2970; a4cy=2100;

	double scale = 1;
	int x=0, y=0;

	int pa_width;
	int pa_height;
	pa_width = pCurSheet->m_size.cx;
	pa_height = pCurSheet->m_size.cy;

	double xdpi = pDC->GetDeviceCaps(LOGPIXELSX);
	double ydpi = pDC->GetDeviceCaps(LOGPIXELSX);
	if(pInfo->m_bPreview)
	{
		//Рисуем рамку печатаемой области
		cx = pDC->GetDeviceCaps(HORZSIZE)*10;
		cy = pDC->GetDeviceCaps(VERTSIZE)*10;
		CPen pen;
		pen.CreatePen(PS_DOT|PS_COSMETIC,1,RGB(192,192,192));
		CPen *old = pDC->SelectObject(&pen);
		pDC->MoveTo(0,200);
		pDC->LineTo(0,-cy-200);
		pDC->MoveTo(cx,200);
		pDC->LineTo(cx,-cy-200);
		pDC->MoveTo(-200,0);
		pDC->LineTo(cx+200,0);
		pDC->MoveTo(-200,-cy);
		pDC->LineTo(cx+200,-cy);
		pDC->SelectObject(old);
		pen.DeleteObject();
	}
	if(!m_ReportMgr.m_bFitToPage)
	{
		double tcx = pcx;
		double tcy = pcy;
		double sc1 = tcx/pa_width;
		double sc2 = tcy/pa_height;
		scale = sc1<sc2 ? sc2 : sc1;
 		if(scale>1)
			scale=1;
		double dx = pDC->GetDeviceCaps(PHYSICALOFFSETX);
		double dy = pDC->GetDeviceCaps(PHYSICALOFFSETY);
		if(m_ReportMgr.m_bSplitPageToA4)
		{
			x = pcx+10;
			y = -pcy-10;
			pDC->SetWindowOrg(x,y);
		}
		else
		{
			x = int((dx*254)/xdpi);//254 - это дюйм в 0.1 миллиметра
			y = int((-dy*254)/ydpi);
			pDC->SetWindowOrg(x,y);
		}
	}
	else
	{
		double tcx = pDC->GetDeviceCaps(HORZSIZE);
		double tcy = pDC->GetDeviceCaps(VERTSIZE);
		cx = int(tcx*10); cy = int(tcy*10);
		double sc1 = (tcx*10)/pa_width;
		double sc2 = (tcy*10)/pa_height;
		scale = sc1>sc2 ? sc2 : sc1;
		pDC->SetWindowOrg(x,y);
	}
	CRgn rgn;
	if(!pInfo->m_bPreview)
	{
		x*=int(xdpi);
		y*=int(ydpi);
		cx*=int(xdpi);
		cy*=int(ydpi);
	}
	rgn.CreateRectRgn(0, 0, cx, cy);
	pDC->SelectClipRgn(&rgn, RGN_AND);

	bool free = false;
	if(!pCurSheet->IsLoaded())
	{
		pCurSheet->LoadElementsFromFile();
		free = true;
	}
	UINT flag = DRAW_PICTURE|DRAW_TEXT;
	for(int i=0; i<pCurSheet->m_els.GetSize();i++)
	{
		CReportElement* elem = pCurSheet->m_els.GetAt(i);
		if(elem==0) continue;
		elem->Draw(pDC,scale, 1, flag);
	}
	if(free)
		pCurSheet->FreeElements();
	pDC->SelectClipRgn(NULL);
	rgn.DeleteObject();
	pDC->SetWindowOrg(0,0);
	pDC->SetMapMode(OldMM);
}

void CReportView::OnFirstPage()
{
	if(m_ReportMgr.m_sheets.GetSize()==0) return;
	if(m_CurSheet==0) return;

	m_CurSheet=0;
	Invalidate();
}

void CReportView::OnUpdateFirstPage(CCmdUI* pCmdUI)
{
	BOOL bEnable = FALSE;

	if(m_ReportMgr.m_sheets.GetSize()>0 && m_CurSheet>0)
		bEnable = TRUE;

	pCmdUI->Enable(bEnable);
}

void CReportView::OnPrevPage()
{
	if(m_ReportMgr.m_sheets.GetSize()==0) return;
	if(m_CurSheet==0) return;
	
	m_CurSheet--;
	Invalidate();
}

void CReportView::OnUpdatePrevPage(CCmdUI* pCmdUI)
{
	BOOL bEnable = FALSE;
	
	if(m_ReportMgr.m_sheets.GetSize()>0 && m_CurSheet>0)
		bEnable = TRUE;
	
	pCmdUI->Enable(bEnable);
}

void CReportView::OnNextPage()
{
	if(m_ReportMgr.m_sheets.GetSize()==0) return;
	if(m_CurSheet>=m_ReportMgr.m_sheets.GetSize()-1) return;
	
	m_CurSheet++;
	Invalidate();
}

void CReportView::OnUpdateNextPage(CCmdUI* pCmdUI)
{
	BOOL bEnable = FALSE;
	
	if(m_ReportMgr.m_sheets.GetSize()>0 && m_CurSheet<m_ReportMgr.m_sheets.GetSize()-1)
		bEnable = TRUE;
	
	pCmdUI->Enable(bEnable);
}

void CReportView::OnLastPage()
{
	if(m_ReportMgr.m_sheets.GetSize()==0) return;
	if(m_CurSheet>=m_ReportMgr.m_sheets.GetSize()-1) return;
	
	m_CurSheet=m_ReportMgr.m_sheets.GetSize()-1;
	Invalidate();
}

void CReportView::OnUpdateLastPage(CCmdUI* pCmdUI)
{
	BOOL bEnable = FALSE;
	
	if(m_ReportMgr.m_sheets.GetSize()>0 && m_CurSheet<m_ReportMgr.m_sheets.GetSize()-1)
		bEnable = TRUE;
	
	pCmdUI->Enable(bEnable);
}


void CReportView::OnPaint() 
{
	CPaintDC dc(this);
	CMetaFileDC metaDC;
	CDC memDC;
	CBitmap bm, *old;

	OnPrepareDC(&dc);

	CRect cl_rect;
	CSize sizes, mf_sizes;
	dc.SetMapMode(MM_LOMETRIC);
	GetClientRect(&cl_rect);
	dc.DPtoLP(&cl_rect);
	cl_rect.NormalizeRect();
	sizes = cl_rect.Size();

	if(m_ReportMgr.m_sheets.GetSize()>0)
	{
		CReportSheet *pCurSheet = m_ReportMgr.m_sheets[m_CurSheet];
		sizes = pCurSheet->m_size;
	}


	mf_sizes = sizes;
	dc.LPtoHIMETRIC(&mf_sizes);
	metaDC.CreateEnhanced(_pPrinterDC, NULL, &CRect(0,0, mf_sizes.cx+100, mf_sizes.cy+100), NULL);
	metaDC.SetAttribDC(_pPrinterDC->m_hAttribDC);
	int mm = metaDC.SetMapMode(MM_LOMETRIC);

	OnDraw(&metaDC);

	metaDC.SetMapMode(mm);
	HENHMETAFILE hEnhMetafile = metaDC.CloseEnhanced();

	memDC.CreateCompatibleDC(&dc);
	memDC.SetMapMode(MM_LOMETRIC);

	if(!m_bFitToClient)
	{
		CSize cl_sizes;
		cl_sizes.cx = cl_rect.Width()>sizes.cx?cl_rect.Width():sizes.cx;
		cl_sizes.cy = cl_rect.Height()>sizes.cy?cl_rect.Height():sizes.cy;
		SetScrollSizes(MM_LOMETRIC, cl_sizes);
		
		bm.CreateCompatibleBitmap(&dc, cl_sizes.cx+10, cl_sizes.cy+10);
		old = memDC.SelectObject(&bm);
		memDC.FillSolidRect(CRect(0,0, cl_sizes.cx+10, -cl_sizes.cy-10), RGB(255, 255, 255));
		::PlayEnhMetaFile(memDC.m_hDC, hEnhMetafile, &CRect(0,0, sizes.cx+10, -sizes.cy-10));
		::BitBlt(dc.m_hDC, 0, 0, cl_sizes.cx+10, -cl_sizes.cy-10, memDC.m_hDC, 0, 0, SRCCOPY);
	}
	else
	{
		SetScrollSizes(MM_LOMETRIC, cl_rect.Size());
		CRect rect = CRect(0,0, sizes.cx, sizes.cy);
		int tmp;
		//Отцентровка метафайла
		CalcCenterRect(cl_rect, rect);
		tmp = rect.top; rect.top = rect.bottom;
		rect.bottom = tmp;
		bm.CreateCompatibleBitmap(&dc, cl_rect.Width(), cl_rect.Height());
		old = memDC.SelectObject(&bm);
		memDC.FillSolidRect(cl_rect, RGB(255, 255, 255));
		::PlayEnhMetaFile(memDC.m_hDC, hEnhMetafile, &rect);
		::BitBlt(dc.m_hDC, 0, 0, cl_rect.Width(), -cl_rect.Height(), memDC.m_hDC, 0, 0, SRCCOPY);
	}

	::DeleteEnhMetaFile(hEnhMetafile);
	memDC.SelectObject(old);
	memDC.DeleteDC();

	ReleaseDC(&dc);
}

bool CReportView::Regen()
{
	if(m_LastDotsFiles.GetSize()==0) return false;

	CDataSource tmpDS;
	tmpDS.CloneDataSource(m_DataSource, NULL);
	CloseReport();
	m_DataSource.RemoveAll();
	
	CString buf, tmp_file, path;
	CString Data, str;
	int i;
	
	//Проверка на существование шаблона
	CFile file;
	for(i=0; i<m_LastDotsFiles.GetSize(); i++)
	{
		if(file.Open(m_LastDotsFiles[i], CFile::modeRead)==FALSE)
		{
			Invalidate();
			return false;
		}
		file.Close();
	}
	
	m_ReportMgr.Init();
	m_ReportMgr.m_data_source.RemoveAll();
	
	m_DataSource.CloneDataSource(tmpDS, NULL);
	m_ReportMgr.m_data_source.CloneDataSource(tmpDS, &m_ReportMgr);
	
	int r,c;
	m_DataSource.GetSize(r,c);
	
	BeginWaitCursor();
	m_data.SetErorPrintMode(false);
	
	CString sTempEnv; sTempEnv.GetEnvironmentVariable(_T("temp"));
	GetTempFileName(sTempEnv, _T("rep"), 0, tmp_file.GetBuffer(MAX_PATH));
	tmp_file.ReleaseBuffer();
	
	bool bOk = true;	
	CStringArray rep_paths;
	for(i=0; i<m_LastDotsFiles.GetSize(); i++)
	{
		if(i>0)
		{
			m_ReportMgr.Detach();
			m_ReportMgr.Init();
			m_ReportMgr.m_data_source.CloneDataSource(m_DataSource, &m_ReportMgr);
		}
		path.Empty();
		CString sTempEnv; sTempEnv.GetEnvironmentVariable(_T("temp"));
		GetTempFileName(sTempEnv, _T("rep"), 0, path.GetBuffer(MAX_PATH));
		path.ReleaseBuffer();
		::DeleteFile(path);
		path.Replace(_T(".tmp"), _T(".aplrep"));
		CRParamsArray params;
		if(!GenerateReport(&m_ReportMgr, &params, m_LastDotsFiles[i], tmp_file, NULL, FALSE))
		{
			bOk = false;
			break;
		}
		else
			rep_paths.Add(tmp_file);
	}
	if(bOk)
	{
		//Объединение отчетов
		path.Empty();
		CString sTempEnv; sTempEnv.GetEnvironmentVariable(_T("temp"));
		GetTempFileName(sTempEnv, _T("rep"), 0, path.GetBuffer(MAX_PATH));
		path.ReleaseBuffer();
		::DeleteFile(path);
		path.Replace(_T(".tmp"), _T(".aplrep"));
		UnificationArrayReports(path, &rep_paths);
	}
	
	DWORD attrs;
	for(i=0; i<rep_paths.GetSize(); i++)
	{
		attrs = ::GetFileAttributes(rep_paths[i]);
		if(attrs&FILE_ATTRIBUTE_READONLY)
		{
			attrs&=~FILE_ATTRIBUTE_READONLY;
			::SetFileAttributes(rep_paths[i], attrs);
		}
		::DeleteFile(rep_paths[i]);
	}
	
	m_ReportMgr.Attach(&m_data, NULL);
	m_TmpFiles.Add(path);
	m_ReportMgr.LoadFromFile(path);
	
	Invalidate();
	
	EndWaitCursor();
	
	return true;
}
