#include "stdafx.h"
#include "Functions.h"
#include "resource.h"
#include "PropertyDlg.h"
#include "ReportDict.h"
#include "SimplDlg.h"
#include "CommonQuery.h"
#include <ATLBASE.H>
#include "TextDlg.h"
//#include "sl_struct.h"
//#include "aplSocketTransport.h"
#include <apl_gui.h>
#include <aplxml.h>
#include "TemplateMaster.h"
#include "TitleDlg.h"
#include <winspool.h>
#if _MSC_VER >= 1600
	#include <memory>
#endif

#include <apl_image.h>

bool SaveReportAsTIFF(CaplReportMgr *ReportMgr, CString sFileName)
{
	if(_pPrinterDC==NULL)
	{
		_pPrinterDC = new CDC;
		if(!AfxGetApp()->CreatePrinterDC(*_pPrinterDC))
		{
			PRINTDLG dlg;
			memset(&dlg, 0, sizeof(PRINTDLG));
			AfxGetApp()->GetPrinterDeviceDefaults(&dlg);
			if(dlg.hDevMode==NULL)
				throw(APL_T("В системе не установлен принтер. Генерация отчета невозможна!"));
			if(!AfxGetApp()->CreatePrinterDC(*_pPrinterDC))
				throw(APL_T("Не удалось создать контекст принтера. Генерация отчета невозможна!"));
		}
	}

	int DPI(400);

	CDC *pDC = _pPrinterDC;
	int cnt_sheets = ReportMgr->m_sheets.GetSize();
	int mm = pDC->SetMapMode(MM_LOMETRIC);

	CString fname, path;
	CStringArray files;

	path.GetEnvironmentVariable(_T("temp"));
	if(!path.IsEmpty())
	{
		if(path[path.GetLength()-1]!=_T('\\'))
			path+=_T("\\");
	}

	for(int i=0;i<cnt_sheets;i++)
	{
		CReportSheet* sheet = ReportMgr->m_sheets.GetAt(i);
		sheet->Update(false);
		CDC memDC;
		memDC.CreateCompatibleDC(pDC);
		memDC.SetMapMode(MM_LOMETRIC);

		CBitmap bm;
		CSize size = CSize(int(double(sheet->m_size.cx)*double(DPI)/254+0.5), int(double(sheet->m_size.cy)*double(DPI)/254+0.5));

		BITMAPINFO bmi;
		bmi.bmiColors[0].rgbBlue = 255;
		bmi.bmiColors[0].rgbRed = 255;
		bmi.bmiColors[0].rgbGreen = 255;
		bmi.bmiColors[0].rgbReserved = 0;

		bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		bmi.bmiHeader.biWidth = size.cx;
		bmi.bmiHeader.biHeight= size.cy;
		bmi.bmiHeader.biPlanes = 1;
		bmi.bmiHeader.biBitCount = 32;
		bmi.bmiHeader.biCompression = BI_RGB;
		bmi.bmiHeader.biSizeImage = 0;
		bmi.bmiHeader.biXPelsPerMeter = DPI;
		bmi.bmiHeader.biYPelsPerMeter = DPI;
		bmi.bmiHeader.biClrUsed = 0;
		bmi.bmiHeader.biClrImportant = 0;

		void *buf;
		HBITMAP hBm = ::CreateDIBSection(memDC.m_hDC, &bmi, DIB_RGB_COLORS, &buf,NULL, NULL);
		memDC.DPtoLP(&size);
		size.cx*=1;
		size.cy*=-1;

		bm.Attach(hBm);
		CBitmap *old = memDC.SelectObject(&bm);

		CPoint org_pt = sheet->SetOrgPt(CPoint(0,0));
		memDC.Rectangle(0,0,int(size.cx),int(size.cy));
		bool free = false;
		if(sheet->m_els.GetSize()==0)
		{
			sheet->LoadElementsFromFile();
			free = true;
		}
		double scale = double(-size.cy)/double(sheet->m_size.cy);
		int cnt = sheet->m_els.GetSize();
		UINT flag = DRAW_TEXT|DRAW_PICTURE;
		for(int j=0; j<cnt;j++)
		{
			CReportElement* elem = sheet->m_els.GetAt(j);
			if(elem==0) continue;
			elem->Draw(&memDC, scale, 1, flag);
		}
		if(free)
			sheet->FreeElements();
		sheet->SetOrgPt(org_pt);
		fname.Format(_T("%s%s.tiff"),path, sheet->m_name);

		//сжатие CCITT FAX4 = 3
		if(!SaveBitmapAs(bm, fname, DPI, FALSE, 3)) break;
		files.Add(fname);
		memDC.SelectObject(old);
		bm.DeleteObject();
		memDC.DeleteDC();
	}

	UnificationTIFF(&files, sFileName);

	/* Терерь это в UnificationTIFF
	int i;
	for(i=0; i<files.GetSize(); ++i)
	{
		CFile::Remove(files[i]);
	}
	*/

	pDC->SetMapMode(mm);
	AfxGetMainWnd()->ReleaseDC(pDC);

	return false;
}

__declspec (dllexport) bool SaveToFile(CaplReportMgr* mgr, LPCTSTR outFileName)
{
	CRegKey key;
	bool res = false;
	if(key.Open(HKEY_CURRENT_USER,_T("Software\\CALS Centre \"Applied Logistic\"\\Конструктор отчетов\\"))==ERROR_SUCCESS)
	{
		TCHAR *str = new TCHAR[1024];
		DWORD dw = 1024;
#if _MSC_VER >= 1400
		LONG QVres = key.QueryStringValue(_T("FileDS"), str, &dw);
#else
		LONG QVres = key.QueryValue((LPTSTR)str,_T("FileDS"), &dw);
#endif
		if(ERROR_SUCCESS==QVres)
		{
			CString file = str;

/*обработка системных переменных %USERPROFILE%\Мои документы\DataSource.csv*/
			CString sEnv;
			CString sEnvVal;
			int iStIndex;
			int iEnIndex;
			iStIndex= file.Find(_T("%"));
			if(-1!=iStIndex)
			{
				iEnIndex= iStIndex+1; 
				while(file[iEnIndex]!=_T('%') && iEnIndex<file.GetLength())
					iEnIndex++;
				if(file[iStIndex]==_T('%') && file[iEnIndex]==_T('%'))
				{
					sEnv= file.Mid(iStIndex+1, iEnIndex-iStIndex-1);
					if(sEnv==_T("MYDOCUMENTS"))
					{
						LPTSTR szPath= sEnvVal.GetBuffer(1024);
						SHGetSpecialFolderPath(NULL, szPath, CSIDL_PERSONAL, FALSE);
						sEnvVal.ReleaseBuffer();
					}
					else
					{
						sEnvVal.GetEnvironmentVariable(sEnv);
					}
					if(!sEnvVal.IsEmpty())
					{
						if(iEnIndex+2<file.GetLength() && file[iEnIndex+1]==_T('\\')) iEnIndex+=2;
						if(sEnvVal[sEnvVal.GetLength()-1]!=_T('\\')) sEnvVal+=_T("\\");
						file= sEnvVal+file.Mid(iEnIndex);
					}
				}
			}
/*обработка системных переменных %USERPROFILE%*/

			if(!file.IsEmpty())
			{
				mgr->m_data_source.SaveToFile(file);
				res = true;

				// дополнительно сохраняем (обычно путь указывает на рядом с aplrep)
				if(outFileName != NULL)
				{
					CString dsFileName(outFileName);
					dsFileName.Replace(_T(".aplrep"), _T(".ds"));
					mgr->m_data_source.SaveToFile(dsFileName);
				}
			}
		}
		delete []str;
		key.Close();
	}
	return res;
}
//************************************************************************
__declspec (dllexport) bool ShowElemProperties(RE_Array* m_eles, int mode)
{
	HINSTANCE hInst = AfxGetResourceHandle();
	AfxSetResourceHandle(dllInst);
	CPropertyDlg dlg;
	dlg.m_elements = m_eles;
	dlg.mode = mode;
	BOOL res = dlg.DoModal();
	AfxSetResourceHandle(hInst);
	return res==IDOK;
}

__declspec (dllexport) bool ShowSimplDialog(TCHAR* title, CString &str, int mode)
{
	HINSTANCE hInst = AfxGetResourceHandle();
	AfxSetResourceHandle(dllInst);

	CTextDlg dlg;
	dlg.m_sText = str;
	dlg.m_sTitle = title;
	dlg.m_Mode = mode;
	BOOL res = dlg.DoModal();
	if(res==IDOK)
		str = dlg.m_sText;
	AfxSetResourceHandle(hInst);
	return res==IDOK;
}

__declspec (dllexport) CString GetAttrEx(CaplInstance* inst, TCHAR* attr, CaplNetStepData* data)
{
	if(data==NULL) return _T("");
	if(inst==NULL) return _T("");
	data->SetAutoDownloadMode(true);
	CaplEntity* ent = inst->GetType();
	if(ent==0) return _T("");
	CString tmp = attr;
	tmp.TrimLeft(_T("."));
	int ind = tmp.Find(_T("."));
	if(ind>-1)
	{
		CaplAttr* attr_ = data->GetAttrDefinition(ent,tmp.Left(ind));
		tmp = tmp.Right(tmp.GetLength()-ind-1);
		CaplInstance* tmp_inst;
		data->GetAttr(inst,attr_,tmp_inst);
		return GetAttrEx(tmp_inst,tmp.GetBuffer(0),data);
	}
	CaplAttr* attr_ = data->GetAttrDefinition(ent,tmp);
	CString res=_T("");
	if(attr_==0) return res;
	if(attr_->type==aplINTEGER)
	{
		int val;
		data->GetAttr(inst,attr_,val);
		res.Format(_T("%d"),val);
	}
	else if(attr_->type==aplREAL)
	{
		double val;
		data->GetAttr(inst,attr_,val);
		CDataSource::GetDoubleAsString(val, res);
	}
	else if(attr_->type==aplSTRING)
		data->GetAttr(inst,attr_,res);
	return res;
}

void SelectString(CListCtrl* lc, int cur)
{
	lc->SetItemState(cur,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);
}

typedef struct
{
	CTableElement* table;
	CReportSheet* sheet;
} TTableSheetMapElement;

__declspec (dllexport) bool GetSheetTextValues(LPCTSTR reportPath, int nSheetNum, CStringArray &textItems)
{
	// узнаем путь
	TCHAR buf[1024];
	DWORD len = 1024;
	CString m_sDictPath;

	GetPrivateProfileString(_T("Paths"), _T("Dictionary"), _T(""), buf, len, _T("AplTransport.ini"));

	m_sDictPath = buf;
	if(m_sDictPath.IsEmpty()) GetExePath(GetModuleHandle(NULL), m_sDictPath);
	if(m_sDictPath[m_sDictPath.GetLength()-1] != _T('\\')) m_sDictPath += _T("\\");

	// подключим словарь
	CaplStepDataWithFile ReportData;
	if(false == ReportData.LoadDictionary(m_sDictPath + _T("report_constructor")))
	{
		CString str;
		str.Format(APL_T("Ошибка загрузки словаря %sreport_constructor.dict"), m_sDictPath);
	}

	// загрузим БД из файла
	if(!ReportData.LoadFromFile(reportPath, false))
	{
		int error = ReportData.GetLastError();
		if(error != APLAPIERR_FILE_BD_READ_ONLY)
		{
			CString str;
			str.Format(APL_T("Ошибка загрузки данных %s (%d)\n%s"), reportPath, error, ReportData.GetErrorDescription(error));			

			return false;
		}
	}

	// инициализируем манагер
	CaplReportMgr reportMgr;
	reportMgr.Attach(&ReportData, m_sDictPath);

	// возьмем нужныую страницу
	aplExtent sheets;
	ReportData.GetEntityExtent(reportMgr.e_apl_report_sheet, sheets);

	CString sValue;
	aplExtent elements;
	CaplInstance *textValue = NULL;

	for(int i=nSheetNum; i<sheets.Size; ++i)
	{
		ReportData.GetAttr(sheets[i], reportMgr.a_rep_sheet_els, elements);
		for(int j=0; j<elements.Size; ++j)
		{
			ReportData.GetAttr(elements[j], reportMgr.a_elem_text_val, textValue);
			if(textValue)
			{
				ReportData.GetAttr(textValue, reportMgr.a_val_text, sValue);
				if(sValue.IsEmpty() == false)
					textItems.Add(sValue);
			}
		}

		break;
	}

	return true;
}

__declspec (dllexport) bool GenerateReport(CaplReportMgr* ReportMgr, LPCTSTR DotName, LPCTSTR OutFileName, CaplNetStepData* net_data, BOOL bWriteDataSource, int *piTotalPages, bool bShowAutoTemplateDlg /*= true*/)
{
	int iTotalPages(-1);

	if (piTotalPages != NULL)
		iTotalPages = *piTotalPages;

	//Инициализация информации о принтере
	try
	{
		if(_pPrinterDC==NULL)
		{
			_pPrinterDC = new CDC;
			if(!AfxGetApp()->CreatePrinterDC(*_pPrinterDC))
			{
				PRINTDLG dlg;
				memset(&dlg, 0, sizeof(PRINTDLG));
				AfxGetApp()->GetPrinterDeviceDefaults(&dlg);
				if(dlg.hDevMode==NULL)
					throw(APL_T("В системе не установлен принтер. Генерация отчета невозможна!"));
				if(!AfxGetApp()->CreatePrinterDC(*_pPrinterDC))
					throw(APL_T("Не удалось создать контекст принтера. Генерация отчета невозможна!"));
			}
		}

		if(ReportMgr==0) 
		{
			throw(CString(APL_T("Не указан менеджер отчетов!")));
		}
		if(DotName==0)
		{
			TRACE_TO_FILE(APL_T("НЕ указан файл шаблона!\nБудем формировать автошаблон!"));
		}
		else
		{
			//проверяем наличие файла шаблона
			
			CFileFind ff;
			if(!ff.FindFile(DotName))
				throw(CString(APL_T("Шаблон не найден. Генерация отчета невозможна!")));
			ff.Close();

// 			CFile tst_file;
// 			if(!tst_file.Open(DotName, CFile::modeRead))
// 				throw(CString(APL_T("Шаблон не найден. Генерация отчета невозможна!")));
// 			tst_file.Close();
		}
		if(OutFileName==NULL)
		{
			throw(CString(APL_T("Не указан файл отчета!")));
		}

		if(bWriteDataSource)
		{
			CString file_name(OutFileName);
			int ind = file_name.ReverseFind(_T('.'));
			if(ind>0)
				file_name = file_name.Left(ind+1);
			file_name+=_T("aplDSF");
			ReportMgr->m_data_source.SaveToFile(file_name);
		}
		
		CString OFName = OutFileName;
		if(OFName.IsEmpty())
		{
			throw(CString(APL_T("Не указан файл отчета!")));
		}
		TCHAR buf[1024];
		DWORD len = 1024;
		CString m_sDictPath = _T("");
		GetPrivateProfileString(_T("Paths"), _T("Dictionary"), _T(""), buf, len,_T("AplTransport.ini"));
		m_sDictPath = buf;
		if(m_sDictPath==_T("")) GetExePath(GetModuleHandle(NULL), m_sDictPath);
		if(m_sDictPath[m_sDictPath.GetLength()-1]!=_T('\\'))m_sDictPath+=_T("\\");
		

		CaplStepDataWithFile ReportData;
		CaplInstance* Report;
		int fit_to_page_by_print, report_mode;
		CSize page_size;
		aplExtent reports;
		CaplInstance* query_inst, *header_inst;
		aplExtent ext;
		aplExtent params;
		int cnt, i, iBinding;
		CString BufStr;

		if(!ReportData.LoadDictionary(m_sDictPath+_T("report_constructor")))
		{
			CString str;
			str.Format(APL_T("Ошибка загрузки словаря %sreport_constructor.dict"),m_sDictPath);
// 			throw(CString(_T("str"))); :)) информативно
			throw(str);
			return false;
		}
		ReportMgr->Attach(&ReportData, m_sDictPath);
		ReportData.SetErrorMessageMode(false);
		if(DotName!=NULL)
		{
			if(!ReportData.LoadFromFile(DotName, false))
			{
				int error = ReportData.GetLastError();
				if(error!=APLAPIERR_FILE_BD_READ_ONLY)
				{
					CString str;
					str.Format(APL_T("Ошибка загрузки данных %s (%d)\n%s"),DotName,error,ReportData.GetErrorDescription(error));
					ReportMgr->Detach();
					throw(str);
				}
			}
		}
		else //автошаблон
		{
			CTemplateMaster TemplateMaster(ReportMgr);
			if(bShowAutoTemplateDlg)
			{
				if(!TemplateMaster.DoTemplate())
					return false;
			}
			else if (!TemplateMaster.DoAutoTemplate())
				return false;

			ReportMgr->RemoveAllSheets();
		}

		ReportData.GetEntityExtent(ReportMgr->e_apl_report,reports);
		if(reports.Size<0) 
		{
			ReportMgr->Detach();
			throw(CString(APL_T("Не корректный шаблон:\nШаблон пуст!")));
			return false;
		}
		Report = reports[0];
		if(Report==0)
		{
			ReportMgr->Detach();
			throw(CString(APL_T("Не корректный шаблон:\nШаблон пуст!")));
		}
		ReportData.GetAttr(Report, ReportMgr->a_apl_report_fit_to_page, fit_to_page_by_print);
		ReportData.GetAttr(Report, ReportMgr->a_rep_mode, report_mode);
		
		//Параметры
		ReportData.GetEntityExtent(ReportMgr->e_param,params);
		cnt = params.GetSize();
		for(i=0; i<cnt;i++)
		{
			CReportParam* par = new CReportParam(ReportMgr);
			par->m_inst = params.GetAt(i);
			par->Update(false);
		}
		
		//Чтение заголовков
		//Основные поля
		ReportData.GetEntityExtent(ReportMgr->e_apl_select,ext);
		if(ext.Size>0)
			ReportMgr->m_base_query->m_inst = ext[0];
		else 
			query_inst = NULL;
		ReportMgr->m_base_query->Update(false);
		//Дополнительные поля
		ReportData.GetEntityExtent(ReportMgr->e_apl_result_select,ext);
		if(ext.Size>0)
			ReportMgr->m_header->m_inst = ext[0];
		else 
			header_inst = NULL;
		ReportMgr->m_header->Update(false);
		//проверяем совместимость переданной таблицы и ИД указанного в шаблоне
		if(!ReportMgr->m_data_source.TestHeader(ReportMgr->m_base_query)) throw(APL_T("Недопустимый источник данных!"));
		
		//Создание объектов
		aplExtent sheets;
		CString name = _T("");
		ReportData.GetAttr(Report, ReportMgr->a_rep_sheets,sheets);
		ReportData.GetAttr(Report, ReportMgr->a_rep_binding,iBinding);
		cnt = sheets.GetSize();
		for(i=0; i<cnt;i++)
		{
			CReportSheet* sheet = new CReportSheet(ReportMgr);
			sheet->m_inst = sheets.GetAt(i);
			ReportMgr->m_sheets.Add(sheet);
			name.Format(APL_T("Лист%d"),i+1);
			sheet->m_name = name;
			sheet->LoadElementsFromFile();
			sheet->Update(false);
		}
		//Обновление не созданных связей таблиц
		cnt = ReportMgr->m_non_create_table_maps.GetSize();
		for(i=0; i<cnt;i++)
		{
			CTableMapElement* elem = (CTableMapElement*)ReportMgr->m_non_create_table_maps.GetAt(i);
			CaplInstance* inst;
			ReportData.GetAttr(elem->m_inst,ReportMgr->a_map_src,inst);
			elem->m_table = ReportMgr->FindTable(inst);
			if(elem->m_table==NULL)
			{
				TRACE(APL_T("Таблица на которую ссылается элемент не найдена\n"));
				elem->m_owner_sheet->DeleteElement(elem,false);
			}
			else
			{
				TRACE(APL_T("Связь с таблицей восстановлена\n"));
			}
		}
		ReportMgr->m_non_create_table_maps.RemoveAll();
		//Генерация отчета
		if(ReportMgr->m_sheets.GetSize()==0) 
		{
			ReportMgr->Detach();
			throw(CString(APL_T("Шаблон не содержит ни одной страницы! Генерация отчета невозможна!")));
		}
		//Параметры
		cnt = ReportMgr->m_data_source.m_RParams.GetSize(); 
		for(i=0; i<cnt;i++)
		{
			CaplRParam* par = ReportMgr->m_data_source.m_RParams.GetAt(i);
			int ind = ReportMgr->m_data_source.m_params.Find(par->m_name);
			if(ind>-1)
				ReportMgr->m_data_source.m_params.GetAt(ind)->SetParam(par->m_value);
		}
		
		//Обновсление параметров.
		for(i=0; i<ReportMgr->m_data_source.m_params.GetSize();i++)
		{
			CReportParam* param = ReportMgr->m_data_source.m_params.GetAt(i);
			param->Update(true);
		}
		
		if(!ReportMgr->m_data_source.Extend(ReportMgr->m_header, net_data))
		{
			ReportMgr->Detach();
			throw(CString(APL_T("Не удалось расширить источник данных. Генерация отчета невозможна!")));
		}
		
		SaveToFile(ReportMgr, OutFileName);

		//Формирование шаблонов
		CArray<TTableSheetMapElement, TTableSheetMapElement> dots;
		CReportSheet* TableContentSheet=NULL;
		
		cnt = ReportMgr->m_sheets.GetSize();
		for(i=0; i<cnt; i++)
		{
			CTableElement* table = NULL;
			CReportSheet* sheet = ReportMgr->m_sheets[i];
			int e_cnt = sheet->m_els.GetSize();
			for(int i_e=0; i_e<e_cnt;i_e++)
			{
				if(sheet->m_els.GetAt(i_e)->GetType()==E_TABLE_CONTENT_TITLE)
					TableContentSheet = sheet;
				if(sheet->m_els.GetAt(i_e)->GetType()!=E_TABLE) continue;
				table = (CTableElement*)sheet->m_els.GetAt(i_e);
				if (table)//Ищем все ее продолжения
				{
					int ind = i;
					for (int s = i + 1; s < cnt; s++)
					{
						int ce_cnt = ReportMgr->m_sheets[s]->m_els.GetSize();
						for (int j = 0; j < ce_cnt; j++)
						{
							if (ReportMgr->m_sheets[s]->m_els.GetAt(j)->GetType() != E_TABLE_MAP) continue;
							CTableMapElement* tm_e = (CTableMapElement*)ReportMgr->m_sheets[s]->m_els.GetAt(j);
							if (tm_e->m_table == table)
								ind = s;
						}
					}
					if (ind > -1)
					{
						CReportSheet* dot = ReportMgr->m_sheets.GetAt(ind);
						TTableSheetMapElement dotMap;
						dotMap.table = table;
						dotMap.sheet = new CReportSheet(ReportMgr);
						dotMap.sheet->LoadElementsFromFile();
						dotMap.sheet->m_size = dot->m_size;
						int L_e_cnt = dot->m_els.GetSize();
						for (int l_i = 0; l_i < L_e_cnt; ++l_i)
							dotMap.sheet->Add(dot->m_els.GetAt(l_i)->CreateClon());
						dots.Add(dotMap);
					}
				}
			}
		}
		
		int max_page = 0;
		int s_cnt = ReportMgr->m_sheets.GetSize();
		
		for(int s=0; s<s_cnt;s++)
		{
			CReportSheet* sheet = ReportMgr->m_sheets.GetAt(s);
			bool br = false;
			for(int l_i=0; l_i<sheet->m_els.GetSize(); l_i++)
			{
				if(sheet->m_els.GetAt(l_i)->GetType()==E_TABLE)
				{
					CTableElement* table = (CTableElement*)sheet->m_els.GetAt(l_i);
					//Поиск страницы шаблона для данной таблицы
					int TmpInd = -1;
					for(int di=0; di<dots.GetSize(); di++)
					{
						TTableSheetMapElement tme = dots.GetAt(di);
						if(tme.table != table) continue;
						ReportMgr->m_dot_sheet = tme.sheet;
						TmpInd = di;
						break;
					}
					if(ReportMgr->m_dot_sheet == NULL)
						throw(CString(APL_T("Не указана страница шаблона!")));
					table->cur_sheet = sheet;
					int st_ind;
					if(table->GenTable()==NULL)
					{
						st_ind = s;
						br = true;
					}
					else
						st_ind = ReportMgr->FindSheetInd(table->cur_sheet)+1;
					//Удаление шаблона
					if(TmpInd>-1)
					{
						dots.RemoveAt(TmpInd);
						delete ReportMgr->m_dot_sheet;
						ReportMgr->m_dot_sheet = NULL;
					}
					//Удаление лишних листов
					CArray<CReportSheet*, CReportSheet*> del_sheets;
					for(int ti=st_ind; ti<ReportMgr->m_sheets.GetSize(); ti++)
					{
						CReportSheet* del_sheet = ReportMgr->m_sheets.GetAt(ti);
						int e_cnt = del_sheet->m_els.GetSize();
						if (e_cnt==0)
							del_sheets.Add(del_sheet);	// если на стр. ничего нет нах такую страницу
						for(int j=0; j<e_cnt;j++)
						{
							CReportElement* elem = del_sheet->m_els.GetAt(j);
							if(elem->GetType()!=E_TABLE_MAP && elem->GetType()!=E_TABLE) continue;
							if(elem->GetType()==E_TABLE)
							{
								if(elem == table)
									del_sheets.Add(del_sheet);
							}
							else if(elem->GetType()==E_TABLE_MAP)
							{
								CTableMapElement* tme = (CTableMapElement*)elem;
								if(tme->m_table == table)
									del_sheets.Add(del_sheet);
							}
						}
					}
					while(del_sheets.GetSize()>0)
					{
						CReportSheet* L_sheet = del_sheets.GetAt(0);
						int sheetInd = ReportMgr->FindSheetInd(L_sheet);
						L_sheet->Delete();
						del_sheets.RemoveAt(0);
					}
					s = st_ind-1;
					s_cnt =ReportMgr->m_sheets.GetSize();
					ReportMgr->m_dot_sheet = NULL;
				}
				else if(sheet->m_els.GetAt(l_i)->GetType()==E_DIAGRAM)
				{
					((CDiagramElement*)sheet->m_els.GetAt(l_i))->GenerateDiagram();
				}
				else if(sheet->m_els.GetAt(l_i)->GetType()==E_GISTOGRAM)
				{
					((CGistogramElement*)sheet->m_els.GetAt(l_i))->GenerateGistogram();
				}
				else if(sheet->m_els.GetAt(l_i)->GetType()==E_RECT)
				{
					if(sheet->m_els[l_i]->m_bCreateTableContent)
					{
						CRectReportElement* pItem = (CRectReportElement*)sheet->m_els[l_i];
						CTableContent *pTableContent = new CTableContent(ReportMgr);
						pTableContent->m_sheets.Add(sheet);
						pTableContent->m_Title = pItem->m_value.GetText();
						ReportMgr->m_TableContents.Add(pTableContent);
					}
				}
			}
		}
		for(int di=0; di<dots.GetSize(); di++)
		{
			TTableSheetMapElement tme = dots.GetAt(di);
			delete tme.sheet;
		}
		dots.RemoveAll();
		report_mode = 1;
		ReportMgr->Update(true);
		
		//Создание содержания если оно есть.
		if(TableContentSheet)
		{
			int cnt_L = TableContentSheet->m_els.GetSize();
			int i_l;
			for(i_l=0; i_l<cnt_L; i_l++)
			{
				if(TableContentSheet->m_els[i_l]->GetType()==E_TABLE_CONTENT_TITLE)
				{
					CTableContentElement* elem = (CTableContentElement*)TableContentSheet->m_els[i_l];
					if(!elem->GenContent())
					{
						while(TableContentSheet->m_els.GetSize()>0)
							TableContentSheet->DeleteElement(TableContentSheet->m_els[0],false);
						ReportData.DeleteInstance(TableContentSheet->m_inst);
						ReportMgr->m_sheets.RemoveAt(ReportMgr->FindSheetInd(TableContentSheet));
						delete TableContentSheet;
					}
					break;
				}
			}
		}
	
		if (iTotalPages!=-1&&ReportMgr->m_sheets.GetSize())
		{
			CReportSheet* pSheet = ReportMgr->m_sheets.GetAt(ReportMgr->m_sheets.GetSize()-1);
			while (iTotalPages>ReportMgr->m_sheets.GetSize())
			{
				ReportMgr->CloneSheet(pSheet);
			}
			cnt = ReportMgr->m_sheets.GetSize();
		}

		ReportMgr->Update(true);
		s_cnt = ReportMgr->m_sheets.GetSize();
		sheets.Clear();

		cnt = ReportMgr->m_sheets.GetSize();
		for(i=0; i<cnt;i++)
		{
			CReportSheet* sheet_L = ReportMgr->m_sheets.GetAt(i);
			if(!sheet_L->IsLoaded())
				sheet_L->LoadElementsFromFile();
			sheet_L->Update();
			sheets.Add(sheet_L->m_inst);
		}

		//Обновление страниц, подмена таблиц и ее продолжений на прямоугольники.
		cnt = ReportMgr->m_sheets.GetSize();
		CReportElement* Elem;
		CRectReportElement *RectElem;
		CReportSheet* sheet;
		for(i=0; i<cnt;i++)
		{
			sheet = ReportMgr->m_sheets.GetAt(i);
			int e_cnt = sheet->m_els.GetSize();
			for(int j=0; j<e_cnt;j++)
			{
				Elem = sheet->m_els.GetAt(j);
				if(Elem==0) continue;
				else if(Elem->GetType()==E_RECT)
				{
					RectElem = (CRectReportElement*)Elem;
					if(RectElem->m_value.GetType()==INST_VAL)
					{
						CReportParam* par = RectElem->m_value.GetParam();
						if(par)
						{
							int ParType = par->GetType();
							if(ParType==STATIC_PAGE_NUM)
							{
								CString str_buf;
								str_buf.Format(_T("%d"), i+1);
								RectElem->m_value.SetText(str_buf);
							}
							else if(ParType==STATIC_PAGE_COUNT)
							{
								CString str_buf;
								str_buf.Format(_T("%d"), cnt);
								RectElem->m_value.SetText(str_buf);
							}
							else if(ParType==STATIC_CUR_DATE)
							{
								CString str_buf;
								aplGetFormatedDate(COleDateTime::GetCurrentTime(), str_buf);
								RectElem->m_value.SetText(str_buf);
							}
							else if(ParType==PAGE_PARAM)
							{
								CString str_buf;
								str_buf.Format(_T("PAGE_PARAM - %d (%s)\n"), i+1, OutFileName);
								//TRACE(str_buf);
							}
						}
					}
				}
				else if(Elem->GetType()==E_TABLE_MAP)
				{
					CRectReportElement* nElem = new CRectReportElement(ReportMgr);
					nElem->m_size = Elem->m_size;
					nElem->m_org_pt = Elem->m_org_pt;
					nElem->m_line_width = Elem->m_line_width;
					nElem->m_fixed = Elem->m_fixed;
					nElem->m_owner_sheet = sheet;
					nElem->m_color = Elem->m_color;
					nElem->Update();
					sheet->DeleteElement(Elem, false);
					sheet->m_els.InsertAt(j,nElem);
					sheet->Add(nElem);
				}
			}
		}
		//Подмена таблиц
		while(ReportMgr->m_tables.GetSize()>0)
		{
			CTableElement* elem = ReportMgr->m_tables.GetAt(0);
			if(elem->GetType()==E_TABLE)
			{
				CReportSheet* owner = elem->m_owner_sheet;
				CRectReportElement* nElem = new CRectReportElement(ReportMgr);
				nElem->m_size = elem->m_size;
				nElem->m_org_pt = elem->m_org_pt;
				nElem->m_line_width = elem->m_line_width;
				nElem->m_fixed = elem->m_fixed;
				nElem->m_color = elem->m_color;
				nElem->m_owner_sheet = owner;
				nElem->Update();
				owner->DeleteElement(elem, false);
				owner->Update();
				owner->Add(nElem);
//				nElem->ExecuteCmd(ID_REPORTELEM_BACK);
			}
		}
	
		ReportData.PutAttr(Report, ReportMgr->a_rep_sheets, sheets);
		ReportData.PutAttr(Report, ReportMgr->a_rep_binding,iBinding);
		ReportData.PutAttr(Report, ReportMgr->a_apl_report_fit_to_page, fit_to_page_by_print);
		ReportData.PutAttr(Report, ReportMgr->a_rep_mode, report_mode);

		if(piTotalPages)
			*piTotalPages = sheets.GetSize();

		sheets.Clear();
		//Сохранение данных
		bool res = true;
		bool bSaveAsTIFF(false);
		CString sExt;
		int iFInd(OFName.ReverseFind(_T('.')));
		if(iFInd>-1)
		{
			sExt = OFName.Right(OFName.GetLength()-iFInd);
			if(sExt.CompareNoCase(_T(".tiff"))==0 || sExt.CompareNoCase(_T(".tif"))==0)
			{
				bSaveAsTIFF = true;
				SaveReportAsTIFF(ReportMgr, OFName);
			}
		}
		if(OutFileName!=0 && !bSaveAsTIFF)
		{
			if(s_cnt>0)
				res = ReportData.SaveToFile(OutFileName, false);
			else
			{
				CFile File;
				if(File.Open(OutFileName, CFile::modeCreate|CFile::modeWrite))
					File.Close();
				else
					res = false;
			}
			if(!res)
			{
				CString str_buf, str_buf1; int code;
				code = ReportMgr->m_data->GetLastError();
				str_buf1 = ReportMgr->m_data->GetLastErrorDescription();
				str_buf.Format(APL_T("Ошибка сохранения файла отчета:\nИмя файла: %s\nОписание ошибки и ее код: %s (%d)"),OutFileName, str_buf1, code);
				ReportMgr->Detach();
				AfxMessageBox(str_buf, MB_OK|MB_ICONINFORMATION);
				return false;
				//throw(str_buf);
			}
		}

		ReportMgr->Detach();
		return res;
	}
	catch(CString &str)
	{
		TRACE_TO_FILE(str);
		AfxMessageBox(str, MB_OK|MB_ICONINFORMATION);
		return false;
	}
	catch(const TCHAR *str)
	{
		TRACE_TO_FILE(str);
		AfxMessageBox(str, MB_OK|MB_ICONINFORMATION);
		return false;
	}
	catch (...)
	{
		TRACE_TO_FILE(APL_T("При генерации отчета возникла ошибка вызванная недопустимостью применяемого дополнения или недопустимостью применяемого источника данных!"));
		AfxMessageBox(APL_T("При генерации отчета возникла ошибка вызванная недопустимостью применяемого дополнения или недопустимостью применяемого источника данных!"), MB_OK|MB_ICONINFORMATION);
		return false;
	}
}

APL_SPEC_EXPORT bool GenerateReport(CaplReportMgr* ReportMgr, CRParamsArray *RParams, LPCTSTR DotName, LPCTSTR OutFileName, CaplNetStepData* net_data, BOOL bWriteDataSource, int *piTotalPages, bool bShowAutoTemplateDlg /*= true*/)
{
	ReportMgr->m_data_source.m_RParams.Append(*RParams);
	
	return GenerateReport(ReportMgr, DotName, OutFileName, net_data, bWriteDataSource, piTotalPages, bShowAutoTemplateDlg);
}
//===========================================
extern "C" APL_SPEC_EXPORT CRParamsArray* mkParamsArray( const Apl::aux::tVecPairStr& vec )
{
	CRParamsArray* out = new CRParamsArray;
	{
		using namespace Apl::aux;
		//
		const int& size = vec.size();
		for(int i=0; i<size; ++i)
		{
			const tPairStr& curr = vec[i];
			const tStr& first = curr.first;
			const tStr& second = curr.second;
			//
			out->Add(first.c_str(), second.c_str());
		}
	}
	return out;
}

extern "C" APL_SPEC_EXPORT void freeParamsArray( CRParamsArray* p )
{
	delete p;
}

extern "C" APL_SPEC_EXPORT CaplReportMgr* mkDict( const std::vector<std::pair<_std_string, int>>& vecHeader, const Apl::aux::tVecStr& vecTableRow )
{
	CaplReportMgr* out = new CaplReportMgr;
	{
		out->Init();
		//
		CDataSource *data_source = &out->m_data_source;
		//
		CHeader* header = new CHeader(NULL);
		{
			const int& size = vecHeader.size();
			for(int i=0; i<size; ++i)
			{
				header->AddColumn(vecHeader[i].first.c_str(), vecHeader[i].second);
			}
			//
			data_source->SetHeader(header);
		}
		//
		CTableRow *row = new CTableRow();
		{
			const int& size = vecTableRow.size();
			for(int i=0; i<size; ++i)
			{
				row->AddColumn(vecTableRow[i].c_str());
			}
			//
			data_source->AddRow(row);
		}
	}
	return out;
}


extern "C" APL_SPEC_EXPORT void addRowToDict( const Apl::aux::tVecStr& vecTableRow, CaplReportMgr* dict )
{
	CDataSource *data_source = &dict->m_data_source;
	{
		CTableRow *row = new CTableRow();
		{
			const int& size = vecTableRow.size();
			for(int i=0; i<size; ++i)
			{
				row->AddColumn(vecTableRow[i].c_str());
			}
			//
			data_source->AddRow(row);
		}
	}
}


extern "C" APL_SPEC_EXPORT void freeDict( CaplReportMgr* p )
{
	delete p;
}

extern "C" APL_SPEC_EXPORT bool GeneratePdf( CaplReportMgr* ReportMgr, const _std_string& aplRepFile )
{
	bool out = ReportMgr->ExportToPdf(aplRepFile.c_str());
	return out;
}

extern "C" APL_SPEC_EXPORT bool GenerateReport_T1(CaplReportMgr* ReportMgr, CRParamsArray *RParams, const _std_string& DotName, const _std_string& OutFileName, CaplNetStepData* net_data /*= NULL*/, bool bWriteDataSource /*= FALSE*/, int *piTotalPages /*= NULL*/, bool bShowAutoTemplateDlg /*= true*/)
{
	struct stubApp : public CWinApp
	{
		stubApp() :CWinApp()
		{
			{
				free((void*)m_pszAppName);
				//Change the name of the application file.
				//The CWinApp destructor will free the memory.
				m_pszAppName = _tcsdup(_T("LOL"));
			}

			CWinApp::InitInstance();

			SetRegistryKey(_T("CALS Centre \"Applied Logistic\" stubApp\""));
		}

	};
	////
#if _MSC_VER >= 1600
	std::shared_ptr<stubApp> p;
	p = std::shared_ptr<stubApp>(new stubApp);
#else
	std::tr1::shared_ptr<stubApp> p;
	p = std::tr1::shared_ptr<stubApp>(new stubApp);
#endif
	//
	CString cDotName(DotName.c_str());
	CString cOutFileName(OutFileName.c_str());
	//
	bool b_bWriteDataSource = bWriteDataSource;
	//
	bool out = GenerateReport(ReportMgr, RParams, cDotName, cOutFileName, net_data, b_bWriteDataSource, piTotalPages, bShowAutoTemplateDlg);
	//
	return out;
}


__declspec (dllexport) bool GenerateReport(CaplReportMgr* ReportMgr, LPCTSTR DotName, LPCTSTR ParamName, LPCTSTR OutFileName, CaplNetStepData* net_data, BOOL bWriteDataSource, int *piTotalPages)
{
	if(ReportMgr==0) 
	{
		TRACE_TO_FILE(APL_T("Не указан менеджер отчетов!"));
		return false;
	}
	if(ParamName==0)
	{
		TRACE_TO_FILE(APL_T("НЕ указан файл параметров!"));
		return false;
	}
	if(DotName==0)
	{
		TRACE_TO_FILE(APL_T("НЕ указан файл шаблона!"));
		return false;
	}
	CRParamsArray params;
	params.LoadFromFile(ParamName);
	return GenerateReport(ReportMgr,&params,DotName,OutFileName, net_data, bWriteDataSource, piTotalPages);
}

__declspec (dllexport) bool SaveBitmapAs(HBITMAP hBM, LPCTSTR FileName, int DPI, BOOL bColor, DWORD CompressionMode)
{
	// функция перенесена в CaplImage
	return CaplImage::SaveBitmapAs(hBM,FileName,DPI,bColor,CompressionMode);
}

__declspec (dllexport) CString GetAsString(CaplValue* val)
{
	if(val==NULL) return _T("");
	CString str = _T("");
	if(val->type==aplSTRING)
	{
		val->Get(str);
	}
	else if(val->type==aplINTEGER)
	{
		int tmp;
		val->Get(tmp);
		str.Format(_T("%d"),tmp);
	}
	else if(val->type==aplREAL)
	{
		double tmp;
		val->Get(tmp);
		CDataSource::GetDoubleAsString(tmp, str);
	}
	else if(val->type==aplAGGR)
	{
		int i;
		CString sBuf;
		for(i=0; i<val->aggrval->GetSize(); ++i)
		{
			sBuf = GetAsString(val->aggrval->GetByIndex(i));
			if(i==0)
				str = sBuf;
			else
				str=str+_T("; ")+sBuf;
		}
	}

	return str;
}

__declspec (dllexport) bool UnificationReports(const CString& filename1, const CString& filename2)
{
	//Файл 2 будет добавлен к файлу 1
	CStringArray arr;
	arr.Add(filename1);
	arr.Add(filename2);
	return UnificationArrayReports(filename1, &arr);
}

__declspec (dllexport) bool UnificationArrayReports(const CString& filename1, const CStringArray *filenames, CProgressCtrl* progress, const CStringArray* object_names /*= NULL*/)
{
	//Файл 2 будет добавлен к файлу 1
	if(filenames==NULL) return false;
	if(filenames->GetSize()==0) return false;

	if(progress)
	{
		progress->SetStep(1);
		progress->SetRange(0, filenames->GetSize());
		progress->SetPos(0);
	}
	CaplStepDataWithFile m_data1;
	CaplStepDataWithFile m_data2;
	CaplReportMgr mgr1, mgr2;
	CaplInstance *select = NULL, *result_select = NULL;
	CString dict_path = _T("");
	{
		TCHAR buf[1024]=_T("");
		DWORD len = 1024;
		GetPrivateProfileString(_T("Paths"), _T("Dictionary"), _T(""), buf, len, _T("AplTransport.ini"));
		dict_path = buf;
		if(dict_path==_T("")) GetExePath(GetModuleHandle(NULL),dict_path);
		if(dict_path[dict_path.GetLength()-1]!=_T('\\'))dict_path+=_T("\\");
	}

	if(!m_data1.LoadDictionary(dict_path+_T("report_constructor")))
		return false;
	if(!m_data2.LoadDictionary(dict_path+_T("report_constructor")))
		return false;
	if(!m_data1.LoadFromFile(filenames->GetAt(0), false))
		return false;
	mgr1.Init();
	mgr1.Attach(&m_data1,dict_path);
	
	CaplInstance* report1 = NULL, *report2 = NULL;
	aplExtent reports, tc_ext1, tc_ext2;
	aplExtent params;
	aplExtent ext_to_copy;
	aplExtent sheets, sheets1;
	aplExtent ext;
	aplExtent ext1;
	aplExtent tmp;

	CaplInstance* inst;
	CaplInstance* val, *par, *font;//Это есть у всех.
	CaplInstance* size, *point;//Это есть у всех.

	CString error_msg;
	CString unique_name = _T("Unique_name_");

	int cnt, i, iBinding;
	int par_type = -1;
	int val_type = NONE_VAL;

	m_data1.GetEntityExtent(mgr1.e_apl_user, reports);
	m_data1.GetEntityExtent(mgr1.e_apl_report, reports);
	m_data1.GetEntityExtent(mgr1.e_param, params);
	if(reports.Size>0)
		report1 = reports[0];
	if(report1==NULL)
		return false;
	m_data1.GetAttr(report1, mgr1.a_rep_sheets, sheets1);
	if(progress)
		progress->StepIt();

	m_data1.GetEntityExtent(mgr1.e_apl_select,ext);
	if(ext.Size>0)
		select = ext[0];
	m_data1.GetEntityExtent(mgr1.e_apl_result_select,ext);
	if(ext.Size>0)
		result_select = ext[0];

	// формируем содержание для первого отчета
	CaplInstance* pReport1TableContent(NULL);
	if (object_names && (object_names->GetSize() == filenames->GetSize()))
	{
		pReport1TableContent = m_data1.CreateInstance(mgr1.e_apl_table_content);
		if (pReport1TableContent)
		{
			CaplAggr aggr_sheets;
			for (int i = 0; i < sheets1.GetSize(); ++i)
			{
				aggr_sheets.Add(sheets1[i]);
			}
			m_data1.PutAttr(pReport1TableContent, mgr1.a_apl_tc_sheets, aggr_sheets);
			m_data1.PutAttr(pReport1TableContent, mgr1.a_apl_tc_title, object_names->GetAt(0));
		}
	}

	m_data1.GetEntityExtent(mgr1.e_apl_table_content, tc_ext1);
	if (pReport1TableContent)
	{
		CaplAggr aggr_content;
		for (int i = 0; i < tc_ext1.GetSize(); ++i)
		{
			if (tc_ext1[i] != pReport1TableContent)
			{
				aggr_content.Add(tc_ext1[i]);
			}
		}
		m_data1.PutAttr(pReport1TableContent, mgr1.a_apl_tc_childs, aggr_content);
	}

	// подмена статичной нумерации для первого отчета
	CString first_report_name = _T("first_report_");
	m_data1.GetEntityExtent(mgr1.e_report_sheet_elem, ext);
	for (i = 0; i < ext.Size; i++)
	{
		m_data1.GetAttr(ext[i], mgr1.a_elem_text_val, val);
		if (val)
		{
			m_data1.GetAttr(val, mgr1.a_val_inst, par);
			m_data1.GetAttr(val, mgr1.a_val_type, val_type);
			if (par)
			{
				m_data1.GetAttr(par, mgr1.a_param_type, par_type);
			}
			if (val_type == INST_VAL && par)
			{
				if (par_type == STATIC_PAGE_COUNT)
				{
					m_data1.PutAttr(val, mgr1.a_val_text, first_report_name + _T("static_count"));
					m_data1.PutAttr(val, mgr1.a_val_inst, (CaplInstance*)NULL);
				}
			}
		}
	}

	for(int ReportsNum=1; ReportsNum<filenames->GetSize(); ReportsNum++)
	{
		if(!m_data2.LoadFromFile(filenames->GetAt(ReportsNum), false))
		{
			error_msg.Format(APL_T("Ошибка открытия файла: %s. Данный файл не добавлен в общий отчет!"), filenames->GetAt(ReportsNum));
			TRACE_TO_FILE(error_msg);
			continue;
		}
		mgr2.Init();
		mgr2.Attach(&m_data2, dict_path);
		ext_to_copy.Clear();
		sheets.Clear();
		sheets1.Clear();
		ext.Clear();
		//Копируются почти все элементы кроме параметров и т.д. параметры типа номер страници и кол-во страниц дублируются;
		//Получили инстанс каждого отчета.
		m_data2.GetEntityExtent(mgr2.e_apl_report, reports);
		if(reports.Size<=0)
		{
			m_data2.ClearData();
			mgr2.Detach();
			if(progress)
				progress->StepIt();
			continue;
		}
		report2 = reports[0];

		m_data2.GetEntityExtent(mgr2.e_apl_select, ext);
		if(ext.GetSize()>0)
		{
			ext_to_copy.Append(ext);
			m_data2.GetAttr(ext[0], mgr2.a_apl_sel_cols, ext);
			ext_to_copy.Append(ext);
		}
		m_data2.GetEntityExtent(mgr2.e_apl_result_select,ext);
		if(ext.GetSize()>0)
		{
			ext_to_copy.Append(ext);
			m_data2.GetAttr(ext[0], mgr2.a_apl_res_sel_cols, ext);
			ext_to_copy.Append(ext);
		}

		m_data2.GetEntityExtent(mgr2.e_apl_data_source,ext);
		ext_to_copy.Append(ext);
		m_data2.GetEntityExtent(mgr2.e_apl_diagram_item,ext);
		ext_to_copy.Append(ext);
		m_data2.GetEntityExtent(mgr2.e_apl_coordinate_line,ext);
		ext_to_copy.Append(ext);
		// копирование параметров линий координат (там где подписи координат задаются параметром)
		for(i=0; i<ext.GetSize(); ++i)
		{
			m_data2.GetAttr(ext[i], mgr2.a_apl_coordinate_line_parametr, par);
			if (par)
				ext_to_copy.Add(par);
		}

		m_data2.GetEntityExtent(mgr2.e_apl_legend,ext);
		ext_to_copy.Append(ext);
		m_data2.GetEntityExtent(mgr2.e_font,ext);
		ext_to_copy.Append(ext);
		m_data2.GetEntityExtent(mgr2.e_apl_data_source_column,ext);
		ext_to_copy.Append(ext);
		m_data2.GetEntityExtent(mgr2.e_apl_data_source_string_value,ext);
		ext_to_copy.Append(ext);
		m_data2.GetEntityExtent(mgr2.e_apl_data_source_real_value,ext);
		ext_to_copy.Append(ext);
		ext.Clear();

		m_data1.GetAttr(report1, mgr1.a_rep_sheets, sheets1);
		m_data1.GetAttr(report1, mgr1.a_rep_binding,iBinding);
		m_data1.GetEntityExtent(mgr1.e_apl_report_sheet,ext);
		if(ext.Size>sheets1.Size)
		{
			for(i=0; i<ext.Size; i++)
				if(sheets1.Find(ext[i])<0) m_data1.DeleteInstance(ext[i]);
		}
	
		//Копирование страниц и элементов.
		unique_name = _T("Unique_name_");
		m_data2.GetAttr(report2, mgr2.a_rep_sheets, sheets);
		cnt = sheets.GetSize();
		for(i=0; i<cnt; i++)
		{
			tmp.Clear();
			m_data2.GetAttr(sheets[i], mgr2.a_rep_sheet_els, tmp);
			ext.Append(tmp);
			ext_to_copy.Append(tmp);
		}
		ext.Append(sheets);
		ext_to_copy.Append(sheets);


		int SheetInd = sheets1.GetSize()+1;
		cnt = ext.GetSize();
		for(i=0; i<cnt; i++)
		{
			inst = ext[i];
			val = NULL; par = NULL; font = NULL;//Это есть у всех.
			size = NULL, point = NULL;//Это есть у всех.
			par_type = -1;
			val_type = NONE_VAL;

			if(m_data2.IsKindOf(inst, mgr2.e_apl_report_sheet))
			{
				// запомним локальный номер листа
				CString buf;
				m_data2.GetAttr(inst, mgr2.a_elem_name, buf);

				CaplInstance *textValue = 0;
				m_data2.GetAttr(inst, mgr2.a_elem_text_val, textValue);
				if(0 == textValue)
					textValue = m_data2.CreateInstance(mgr2.e_value);					
				
				m_data2.PutAttr(textValue, mgr2.a_val_text, buf);
				m_data2.PutAttr(inst, mgr2.a_elem_text_val, textValue);
				
				buf.Format(APL_T("Лист%d"), SheetInd);
				m_data2.PutAttr(inst, mgr2.a_elem_name, buf);
				SheetInd++;
			}
			m_data2.GetAttr(inst, mgr2.a_elem_org_pt, point);
			m_data2.GetAttr(inst, mgr2.a_elem_size, size);
			m_data2.GetAttr(inst, mgr2.a_elem_text_val, val);
			if(val)
			{
				m_data2.GetAttr(val, mgr2.a_val_font, font);
				m_data2.GetAttr(val, mgr2.a_val_inst, par);
				//Для параметра особая проверка. если этот параметр отображает номер страницы
				//или количество страниц. то его необходимо сохранить.
				//иначе значение параметра прописать в значение Val и par установить в NULL;
				m_data2.GetAttr(val, mgr2.a_val_type, val_type);
				if(par)
				{
					m_data2.GetAttr(par, mgr2.a_param_type, par_type);
				}
				if(val_type==INST_VAL && par)
				{
					if(par_type>-1 && par_type<PAGE_PARAM)
					{
						CString str;
						m_data2.GetAttr(par, mgr2.a_param_value, str);
						m_data2.PutAttr(val, mgr2.a_val_text, str);
						m_data2.PutAttr(val, mgr2.a_val_type, TEXT_VAL);
					}
					else
					{
						if(par_type==PAGE_PARAM)
							m_data2.PutAttr(val, mgr2.a_val_text, unique_name+_T("num"));
						else if(par_type==PAGE_COUNT)
							m_data2.PutAttr(val, mgr2.a_val_text, unique_name+_T("count"));
						else if(par_type==CURRENT_DATE)
							m_data2.PutAttr(val, mgr2.a_val_text, unique_name+_T("cur_date"));
						else if(par_type==STATIC_PAGE_COUNT)
							m_data2.PutAttr(val, mgr2.a_val_text, unique_name+_T("static_count"));
						else if(par_type==STATIC_PAGE_NUM)
							m_data2.PutAttr(val, mgr2.a_val_text, unique_name+_T("static_num"));
					}
					m_data2.PutAttr(val, mgr2.a_val_inst, (CaplInstance*)NULL);
				}
				ext_to_copy.Add(val);
				if(font) ext_to_copy.Add(font);
			}
			if(point) ext_to_copy.Add(point);
			if(size) ext_to_copy.Add(size);
		}

		// формируем содержание для отчета
		CaplInstance *pReportTableContent(NULL);
		if (object_names && (object_names->GetSize()==filenames->GetSize()))
		{
			pReportTableContent = m_data2.CreateInstance(mgr2.e_apl_table_content);
			if (pReportTableContent)
			{
				CaplAggr aggr_sheets;
				for (int i = 0; i < sheets.GetSize(); ++i)
				{
					aggr_sheets.Add(sheets[i]);
				}
				m_data2.PutAttr(pReportTableContent, mgr2.a_apl_tc_sheets, aggr_sheets);
				m_data2.PutAttr(pReportTableContent, mgr2.a_apl_tc_title, object_names->GetAt(ReportsNum));

				ext_to_copy.Add(pReportTableContent);
			}
		}

		m_data2.GetEntityExtent(mgr2.e_apl_table_content, tc_ext2);
		if (pReportTableContent)
		{
			CaplAggr aggr_content;
			for (int i = 0; i < tc_ext2.GetSize(); ++i)
			{
				if (tc_ext2[i] != pReportTableContent)
				{
					aggr_content.Add(tc_ext2[i]);
				}
			}
			m_data2.PutAttr(pReportTableContent, mgr2.a_apl_tc_childs, aggr_content);
		}
		ext_to_copy.Append(tc_ext2);

		//Вызов функции копирования объектов в другую БД;
		m_data2.aplFarCopyInstances(ext_to_copy, m_data1, false);

		//воссоздаем ссылки на поля ИД, недостающие поля ИД.
		//Основные поля ИД
		m_data1.GetEntityExtent(mgr1.e_apl_select, ext);
		if(ext.GetSize()>1)
		{
			ext.Remove(ext.Find(select));
			if(select==NULL)
				select = ext[0];
			else
			{
				CString name, name1;
				int j;
				CaplInstance *inst_L = NULL;
				CaplInstance *test_select = NULL;
				aplExtent tmp_ext;
				aplExtent tmp_ext1;
				test_select = ext[0];
				m_data1.GetAttr(test_select, mgr1.a_apl_sel_cols, ext1);
				m_data1.GetAttr(select, mgr1.a_apl_sel_cols, ext);
				for(i=0; i<ext1.GetSize(); i++)
				{
					//поиск поля с таким наименованием
					m_data1.GetAttr(ext1[i], mgr1.a_apl_col_name, name1);
					inst_L = NULL;
					for(j=0; j<ext.GetSize(); j++)
					{
						m_data1.GetAttr(ext[j], mgr1.a_apl_col_name, name);
						if(name==name1)
						{
							inst_L = ext[j];
							break;
						}
					}
					if(inst_L==NULL)
					{
						ext.Add(ext1[i]);
						ext1.Remove(ext1.Find(ext1[i--]));
					}
					else
					{
						//ext1[i] - inst
						//Подменяем значения атрибутов
						//секции
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_report_section, mgr1.a_section_sort, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
						{
							m_data1.GetAttr(tmp_ext[j], mgr1.a_section_sort, tmp_ext1);
							tmp_ext1.Remove(tmp_ext1.Find(ext1[i]));
							tmp_ext1.Add(inst_L);
							m_data1.PutAttr(tmp_ext[j], mgr1.a_section_sort, tmp_ext1);
						}
						//условия
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_condition, mgr1.a_apl_condition_ds_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_condition_ds_column, inst_L);
						//поле группировки
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_group_col, mgr1.a_apl_gr_col, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_gr_col, inst_L);
						//apl_column
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_column, mgr1.a_apl_column_ds_col, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_column_ds_col, inst_L);
						//apl_sort_column
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_sort_column, mgr1.a_apl_sc_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_sc_column, inst_L);
						//apl_diagramm_elem
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_diagram_element, mgr1.a_apl_diagram_element_group_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_diagram_element_group_column, inst_L);
						//apl_coord_line
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_coordinate_line, mgr1.a_apl_coordinate_line_ds_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_coordinate_line_ds_column, inst_L);
						//apl_diagramm_item
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_diagram_item, mgr1.a_apl_diagram_item_ds_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_diagram_item_ds_column, inst_L);
					}
				}
				m_data1.PutAttr(select, mgr1.a_apl_sel_cols, ext);
				for(i=0; i<ext1.GetSize(); i++)
					m_data1.DeleteInstance(ext1[i]);
				m_data1.DeleteInstance(test_select);
			}
		}
		//Дополнительные поля ИД
		m_data1.GetEntityExtent(mgr1.e_apl_result_select, ext);
		if(ext.GetSize()>1)
		{
			ext.Remove(ext.Find(result_select));
			if(result_select==NULL)
				result_select = ext[0];
			else
			{
				CString name, name1;
				int j;
				CaplInstance *inst_L = NULL;
				CaplInstance *test_select = NULL;
				aplExtent tmp_ext;
				aplExtent tmp_ext1;
				test_select = ext[0];
				m_data1.GetAttr(test_select, mgr1.a_apl_res_sel_cols, ext1);
				m_data1.GetAttr(result_select, mgr1.a_apl_res_sel_cols, ext);
				for(i=0; i<ext1.GetSize(); i++)
				{
					//поиск поля с таким наименованием
					m_data1.GetAttr(ext1[i], mgr1.a_apl_col_name, name1);
					inst_L = NULL;
					for(j=0; j<ext.GetSize(); j++)
					{
						m_data1.GetAttr(ext[j], mgr1.a_apl_col_name, name);
						if(name==name1)
						{
							inst_L = ext[j];
							break;
						}
					}
					if(inst_L==NULL)
					{
						ext.Add(ext1[i]);
						ext1.Remove(ext1.Find(ext1[i--]));
					}
					else
					{
						//ext1[i] - inst
						//Подменяем значения атрибутов
						//секции
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_report_section, mgr1.a_section_sort, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
						{
							m_data1.GetAttr(tmp_ext[j], mgr1.a_section_sort, tmp_ext1);
							tmp_ext1.Remove(tmp_ext1.Find(ext1[i]));
							tmp_ext1.Add(inst_L);
							m_data1.PutAttr(tmp_ext[j], mgr1.a_section_sort, tmp_ext1);
						}
						//условия
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_condition, mgr1.a_apl_condition_ds_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_condition_ds_column, inst_L);
						//поле группировки
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_group_col, mgr1.a_apl_gr_col, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_gr_col, inst_L);
						//apl_column
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_column, mgr1.a_apl_column_ds_col, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_column_ds_col, inst_L);
						//apl_sort_column
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_sort_column, mgr1.a_apl_sc_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_sc_column, inst_L);
						//apl_diagramm_elem
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_diagram_element, mgr1.a_apl_diagram_element_group_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_diagram_element_group_column, inst_L);
						//apl_coord_line
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_coordinate_line, mgr1.a_apl_coordinate_line_ds_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_coordinate_line_ds_column, inst_L);
						//apl_diagramm_item
						m_data1.FindInstanceUsers(ext1[i], mgr1.e_apl_diagram_item, mgr1.a_apl_diagram_item_ds_column, tmp_ext);
						for(j=0; j<tmp_ext.GetSize(); j++)
							m_data1.PutAttr(tmp_ext[j], mgr1.a_apl_diagram_item_ds_column, inst_L);
					}
				}
				m_data1.PutAttr(result_select, mgr1.a_apl_res_sel_cols, ext);
				for(i=0; i<ext1.GetSize(); i++)
					m_data1.DeleteInstance(ext1[i]);
				m_data1.DeleteInstance(test_select);
			}
		}
		
		CaplInstance* par_page_num = 0;
		CaplInstance* par_page_count = 0;
		CaplInstance* par_cur_date = 0;
		CaplInstance* par_static_page_num = 0;
		CaplInstance* par_static_page_count = 0;

		for(i=0; i<params.Size;i++)
		{
			int par_type_L = 0;
			m_data1.GetAttr(params[i], mgr1.a_param_type, par_type_L);
			if(par_type_L==PAGE_COUNT)
				par_page_count = params[i];
			else if(par_type_L==PAGE_PARAM)
				par_page_num = params[i];
			else if(par_type_L==CURRENT_DATE)
				par_cur_date = params[i];
			else if(par_type_L==STATIC_PAGE_NUM)
				par_static_page_num = params[i];
			else if(par_type_L==STATIC_PAGE_COUNT)
				par_static_page_count = params[i];
		}

		if(par_page_num==0)
		{
			par_page_num = m_data1.CreateInstance(mgr1.e_param);
			m_data1.PutAttr(par_page_num, mgr1.a_param_type, PAGE_PARAM);
			m_data1.PutAttr(par_page_num, mgr1.a_param_name, APL_T("Номер страницы"));
		}
		if(par_page_count==0)
		{
			par_page_count = m_data1.CreateInstance(mgr1.e_param);
			m_data1.PutAttr(par_page_count, mgr1.a_param_type, PAGE_COUNT);
			m_data1.PutAttr(par_page_count, mgr1.a_param_name, APL_T("Количество страниц"));
		}
		if(par_cur_date==0)
		{
			par_cur_date = m_data1.CreateInstance(mgr1.e_param);
			m_data1.PutAttr(par_cur_date, mgr1.a_param_type, CURRENT_DATE);
			m_data1.PutAttr(par_cur_date, mgr1.a_param_name, APL_T("Текущая дата"));
		}
		if(par_static_page_num==0)
		{
			par_static_page_num = m_data1.CreateInstance(mgr1.e_param);
			m_data1.PutAttr(par_static_page_num, mgr1.a_param_type, STATIC_PAGE_NUM);
			m_data1.PutAttr(par_static_page_num, mgr1.a_param_name, APL_T("Локальный номер страницы"));
		}
		if(par_static_page_count==0)
		{
			par_static_page_count = m_data1.CreateInstance(mgr1.e_param);
			m_data1.PutAttr(par_static_page_count, mgr1.a_param_type, STATIC_PAGE_COUNT);
			m_data1.PutAttr(par_static_page_count, mgr1.a_param_name, APL_T("Локальное количество страниц"));
		}

		//проходимся по страницам и восстанавливаем порядок страниц.
		ext.Clear();
		m_data1.GetEntityExtent(mgr1.e_apl_report_sheet,ext);
		sheets.Clear();
		i=1;
		CString page, str;
		while(ext.Size>0)
		{
			page.Format(APL_T("Лист%d"),i);
			for(int j=0; j<ext.Size;j++)
			{
				m_data1.GetAttr(ext[j], mgr1.a_elem_name, str);
				if(str==page)
				{
					sheets.Add(ext[j]);
					ext.Remove(j);
					break;
				}
			}
			i++;
			if(i>ext.Size+sheets.Size)
			{
				TRACE_TO_FILE(APL_T("Аварийный выход из функции объединения страниц"));
				break;
			}
		}
		
		m_data1.PutAttr(report1, mgr1.a_rep_sheets, sheets);
		m_data1.PutAttr(report1, mgr1.a_rep_binding,iBinding);
		ext.Clear();

		//Проходимся по массивам восстановления страничных параметров.
		CString name;
		m_data1.GetEntityExtent(mgr1.e_report_sheet_elem, ext);
		for(i=0; i<ext.Size;i++)
		{
			m_data1.GetAttr(ext[i], mgr1.a_elem_text_val, val);
			if(val)
			{
				m_data1.GetAttr(val, mgr1.a_val_text, name);
				if(name==_T("Unique_name_num"))
				{
					m_data1.PutAttr(val, mgr1.a_val_inst, par_page_num);
					m_data1.PutAttr(val, mgr1.a_val_type, INST_VAL);
				}
				else if(name==_T("Unique_name_count"))
				{
					m_data1.PutAttr(val, mgr1.a_val_inst, par_page_count);
					m_data1.PutAttr(val, mgr1.a_val_type, INST_VAL);
				}
				else if(name==_T("Unique_name_cur_date"))
				{
					m_data1.PutAttr(val, mgr1.a_val_inst, par_cur_date);
					m_data1.PutAttr(val, mgr1.a_val_type, INST_VAL);
				}
				else if(name==_T("Unique_name_static_count"))
				{
					m_data1.PutAttr(val, mgr1.a_val_inst, par_static_page_count);
					m_data1.PutAttr(val, mgr1.a_val_type, INST_VAL);

					CString sheetsCount; sheetsCount.Format(_T("%d"), sheets.Size - sheets1.Size);
					m_data1.PutAttr(val, mgr1.a_val_text, sheetsCount);
				}
				else if(name==_T("Unique_name_static_num"))
				{
					m_data1.PutAttr(val, mgr1.a_val_inst, par_static_page_num);
					m_data1.PutAttr(val, mgr1.a_val_type, INST_VAL);
				}
				else if (name == _T("first_report_static_count"))
				{
					m_data1.PutAttr(val, mgr1.a_val_inst, par_static_page_count);
					m_data1.PutAttr(val, mgr1.a_val_type, INST_VAL);

					CString sheetsCount; sheetsCount.Format(_T("%d"), sheets1.Size);
					m_data1.PutAttr(val, mgr1.a_val_text, sheetsCount);
				}
			}
		}
		m_data2.ClearData();
		mgr2.Detach();
		if(progress)
			progress->StepIt();
	}
	m_data1.SaveToFile(filename1, true);

	mgr1.Detach();
	mgr2.Detach();
	return true;
}

bool CRParamsArray::LoadFromFile(LPCTSTR file_name, bool LoadNamesOnly)
{
	if(file_name==NULL) return false;
	CString str, ext;
	str = file_name;
	if(str.ReverseFind(_T('.'))>-1)
	{
		ext =str.Right(str.GetLength()-1-str.ReverseFind(_T('.')));
		if(ext.CompareNoCase(_T("xml"))==0) //читаем их XML
		{
			CaplXMLFile XMLFile;
			if(!XMLFile.LoadFromFile(file_name)) return false;
			//Проверяем наш ли это XML
			if(XMLFile.root.name.CompareNoCase(_T("data_source"))!=0) return false;
			
			CaplXMLNode* pNode = NULL;
			int i, j;
			//Ищем субноде с именем columns
			for(i=0; i<XMLFile.root.subnodes.GetSize(); i++)
			{
				pNode = XMLFile.root.subnodes[i];
				if(pNode->name.CompareNoCase(_T("params"))!=0) continue;
				for(j=0; i<pNode->subnodes.GetSize(); i++)
				{
					pNode = pNode->subnodes[j];
					Add(pNode->GetParam(_T("name")), pNode->GetParam(_T("value")));
				}
			}
			return true;
		}
	}
	CStdioFile file;
	if(!file.Open(file_name, CFile::modeRead))
		return false;

	CString name, value;
	int ind;
	str.Empty();
	if(!file.ReadString(str))
	{
		file.Close();
		return false;
	}
	str.TrimLeft();
	str.TrimRight();
	if(str.CompareNoCase(_T("Data Source File"))==0)
	{
		bool bRead = false;;
		do
		{
			if(!file.ReadString(str))
				break;
			str.TrimLeft();
			str.TrimRight();
			if(str.IsEmpty())
				continue;
			if(str.CompareNoCase(_T("[Params]"))==0)
			{
				bRead = true;
				continue;
			}
			if(str.CompareNoCase(_T("[Data]"))==0)
				break;
			if(!bRead) continue;
			if(str[0]==_T(';')) continue;
			ind = str.Find(_T("="));
			if(LoadNamesOnly==false)
			{
				if(ind<0)
					continue;
				name = str.Left(ind);
				value = str.Right(str.GetLength()-ind-1);
				CDataSource::ReplaceBreaks(value);
				Add(name, value);
			}
			else
			{
				if(ind<0)
					ind = str.GetLength();
				name = str.Left(ind);
				Add(name);
			}
		} while(str.CompareNoCase(_T("[Data]"))!=0);
	}
	else
	{
		file.SeekToBegin();
		while(file.ReadString(str))
		{
			if(str.IsEmpty())
				continue;
			str.TrimLeft();
			str.TrimRight();
			if(str[0]==_T(';')) continue;
			ind = str.Find(_T("="));
			if(ind<0)
				continue;
			name = str.Left(ind);
			value = str.Right(str.GetLength()-ind-1);
			Add(name, value);
		}
	}

	file.Close();
	return true;
}

// Счетчик запущенных экземпляров программ на компе
#pragma data_seg("SHARED")  // Begin the shared data segment.
long global_report_mgr_counter=1;
#pragma data_seg()          
#pragma comment(linker, "/section:SHARED,RWS")



bool GetExePath(CString &buf)
{
	buf.Empty();
	TCHAR *tBuf = new TCHAR[1024];
	GetModuleFileName(GetModuleHandle(NULL), tBuf, 1024);
	buf+=tBuf;
	delete []tBuf;
	if(buf.Find(_T("\\"))>-1)
	{
		buf = buf.Left(buf.ReverseFind(_T('\\'))+1);
	}
	else
	{
		buf.Empty();
	}
	//
	return true;
}

__declspec(dllexport) bool CreateTitle(CaplReportMgr *ReportMgr, CReportSheet* pSheet)
{
	if(ReportMgr==NULL) return false;
	if(pSheet==NULL) return false;

	BOOL bRes = 0;
	HINSTANCE hCurInst = AfxGetResourceHandle();
	AfxSetResourceHandle(dllInst);
	CTitleDlg dlg(ReportMgr, pSheet);
	bRes = dlg.DoModal();
	AfxSetResourceHandle(hCurInst);

	return bRes==IDOK;
}

__declspec(dllexport) bool UnificationTIFF(CStringArray *strs, CString sFileName)
{
	// реализация перенесена в CaplImage
	if(strs==NULL) return false;
	if(strs->GetSize()==0) return false;
	return CaplImage::UnificationTIFF(strs,sFileName);
}

__declspec(dllexport) bool CalcCenterRect(const CRect OutRect, CRect &ItemRect)
{
	int cx, cy;
	double sc1, sc2, scale;

	sc1 = (double)OutRect.Width()/(double)ItemRect.Width();
	sc2 = (double)OutRect.Height()/(double)ItemRect.Height();

	if(sc1<sc2)
	{
		cy = ItemRect.Height();
		scale = sc1;
		ItemRect.left = OutRect.left;
		ItemRect.right = OutRect.right;
		ItemRect.bottom = -(int)((OutRect.Height()-(cy*scale))/2);
		ItemRect.top = OutRect.top+(int)((OutRect.Height()-(cy*scale))/2);
	}
	else
	{
		cx = ItemRect.Width();
		scale = sc2;
		ItemRect.top = OutRect.top;
		ItemRect.bottom = OutRect.bottom;
		ItemRect.left = (int)((OutRect.Width()-(cx*scale))/2);
		ItemRect.right = OutRect.right-(int)((OutRect.Width()-(cx*scale))/2);
	}

	return true;
}

__declspec(dllexport) bool UpdateReportParametrs(CaplReportMgr* pReportMgr)
{
	if(pReportMgr==NULL) return false;

	int i;
	int ind;
	for(i=0; i<pReportMgr->m_data_source.m_RParams.GetSize(); i++)
	{
		ind = pReportMgr->m_data_source.m_params.Find(pReportMgr->m_data_source.m_RParams[i]->m_name);
		if(ind>-1)
			pReportMgr->m_data_source.m_params[ind]->SetParam(pReportMgr->m_data_source.m_RParams[i]->m_value);
	}

	return true;
}

__declspec(dllexport) bool UpdateReportParametrs(CaplReportMgr* pReportMgr, LPCTSTR lpszParamsFileName)
{
	if(pReportMgr==NULL || lpszParamsFileName==NULL) return false;
	pReportMgr->m_data_source.m_RParams.LoadFromFile(lpszParamsFileName);
	return UpdateReportParametrs(pReportMgr);
}

__declspec (dllexport) CDC* aplRCGetPrinterDC()
{
	if(_pPrinterDC==NULL)
		aplRCCreatePrinterDC();
	return _pPrinterDC;
}

__declspec (dllexport) bool aplRCCreatePrinterDC()
{
	if(_pPrinterDC==NULL) _pPrinterDC = new CDC;

	PRINTDLG dlg;
	memset(&dlg, 0, sizeof(PRINTDLG));
	AfxGetApp()->GetPrinterDeviceDefaults(&dlg);
	ASSERT(dlg.hDevMode);
	AfxGetApp()->CreatePrinterDC(*_pPrinterDC);

	return true;
}

__declspec (dllexport) bool ReadDots(LPCTSTR FileName, LPCTSTR SecName, CStringArray* res)
{
	if(res==0) return false;
	if(FileName==_T("")) return false;
	if(SecName==_T("")) return false;
	CStdioFile file;
	if(!file.Open(FileName, CFile::modeRead)) return false;
	CString str;
	CString sec;
	sec.Format(_T("[%s]"), SecName);
	bool bSec = false;
	while(1)
	{
		if(!file.ReadString(str))
			break;
		if(str.IsEmpty())
			continue;
		if(str[0]==_T(';'))
			continue;
		if(str[0]==_T('['))//проверяем на нашу секцию
		{
			if(str==sec)
				bSec = true;
			else
				bSec = false;
			continue;
		}
		if(bSec)
			res->Add(str);
	}
	file.Close();
	return true;
}
