// ReportSection.cpp: implementation of the CReportSection class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ReportDict.h"
#include "Functions.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define AT_SHOW_TEXT	1
#define AT_TEST			2
#define AT_DRAW_GROUP	4
#define AT_FINISH_GROUP 8

// ЯАИ:  функция для затыки изменяющей высоту уровня
// max_width - ограничение по ширине
bool GetCPictureElementProportionalSize(CPictureElement *elem, int max_width, int &img_prop_cx, int &img_prop_cy)
{
	if(0==elem) return false;
	if(0==elem->m_image) return false;
	
	long xDPI,yDPI;
	elem->m_image->GetDPI(xDPI,yDPI);
	if(0==xDPI || 0==yDPI) return false;
	
	int imgCx,imgCy;
	elem->m_image->GetImageDimensions(imgCx,imgCy);
	if(0==imgCx || 0==imgCy) return false;

	int img_cx=(int)((25.4*10*imgCx)/xDPI); // в мм
	int img_cy=(int)((25.4*10*imgCy)/yDPI); // в мм

	if(img_cx<=max_width)
	{
		img_prop_cx=img_cx;
		img_prop_cy=img_cy;
	}
	else
	{
		img_prop_cy=img_cy*max_width/img_cx;  // пропорционально уменьшаем размеры картинки
		img_prop_cx=max_width;
	}
	return true;
}

// ЯАИ:  функция для затыки изменяющей высоту уровня
bool GetPictureProportionalHigh(CaplReportMgr* rep_mgr, CaplReportValue *val, int width, int&high)
{
	high=0;
	if(0==val) return false;
	if(0==rep_mgr) return false;
	if(0==width) return false;

	CaplDataBuf *buf;
	val->Get(&buf);
	CString tmp; tmp.GetEnvironmentVariable(_T("temp"));
	tmp+=_T("\\picture.png");
	CFile f;
	if(f.Open(tmp,CFile::modeCreate|CFile::modeWrite))
	{
		f.Write(buf->GetBuffer(),buf->m_Size);
		f.Close();
	}
	CPictureElement elem(rep_mgr);
	elem.m_mode = DM_FIT_TO_RECT;
	elem.LoadPicture(tmp);
	CFile::Remove(tmp);

	int img_cx=0;
	GetCPictureElementProportionalSize(&elem,width,img_cx,high);
	return true;
}

// ЯАИ:  функция для затыки изменяющей высоту уровня
bool GetHighSectionLevelWithPict(CaplReportMgr* rep_mgr, CSectionLevel *lev, CDataSource *ds, int ind, int &img_cx, int &img_cy)
{
	img_cy=0;
	int i;
	for(i=0;i<lev->m_columns.GetSize();i++)
	{
		CColumn* col = lev->m_columns.GetAt(i);
		//Берем значение из ист. данных и преобразуем его к строке
		CaplReportValue* val=NULL;
		val = ds->GetAt(ind, col->m_ds_column);
		if(0==val) continue;
		if(aplBINARY!=val->type) continue;
		int high=0;
		GetPictureProportionalHigh(rep_mgr,val,col->m_width,high);
		if(high==0) continue;
		img_cy=high;
		break;// Считаем что только 1 картинка в строке
	}
	return true;
};

CReportSection::CReportSection(CaplReportMgr *dict):m_conditions(dict)
{
	m_title_column = NULL;
	m_CurTableContent = NULL;
	
	m_inst = NULL;
	m_ReportMgr = dict;
	m_show_empty_string_in_title = 1;
}
CReportSection::~CReportSection()
{
	m_levels.RemoveAll();
	m_conditions.RemoveAll();
	m_groups.RemoveAll();
	m_sorts.RemoveAll();
}

int CReportSection::CreateSection(CaplReportMgr* dict)
{
	ASSERT(dict);
	m_ReportMgr = dict;
	CaplStepDataWithFile* data = m_ReportMgr->m_data;
	m_inst = data->CreateInstance(m_ReportMgr->e_report_section);
	data->PutAttr(m_inst,m_ReportMgr->a_section_name,m_name);
	m_title.UpdateData(dict);
	data->PutAttr(m_inst,m_ReportMgr->a_section_title,m_title.m_inst);
	return 0;
}

void CSectionLevelArray::Update(bool set)
{
	for(int i=0; i<m_Data.GetSize();i++)
		m_Data.GetAt(i)->Update(set);
}

void CReportSection::Update(bool set)
{
	int i;
	if(set)
	{
		if(m_inst==0)
			m_inst = m_ReportMgr->m_data->CreateInstance(m_ReportMgr->e_report_section);
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_section_name,m_name);
		m_title.UpdateData(m_ReportMgr);
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_section_title,m_title.m_inst);
		m_levels.Update(set);
		aplExtent ext;
		m_levels.GetExtent(ext);
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_section_levels,ext);
		if(m_title_column)
		{
			m_title_column->Update(set);
			m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_section_title_col,m_title_column->m_inst);
		}
		else
			m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_section_title_col,(CaplInstance*)NULL);
		ext.Clear();
		int cnt = m_conditions.GetSize();
		for(i=0; i<cnt;i++)
		{
			CCondition* cond = m_conditions.GetAt(i);
			cond->Update(set);
			ext.Add(cond->m_inst);
		}
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_apl_rep_section_conditions,ext);
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_apl_rep_section_show_es,m_show_empty_string_in_title);
		ext.Clear();
		cnt = m_groups.GetSize();
		for(i=0; i<cnt; i++)
		{
			CGroupCol* col = m_groups.GetAt(i);
			col->Update(set);
			ext.Add(col->m_inst);
		}
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_section_groups,ext);
		ext.Clear();
		cnt = m_sorts.GetSize();
		for(i=0; i<cnt; i++)
		{
			CSortColumn* col = m_sorts.GetAt(i);
			col->Update(set);
			ext.Add(col->m_inst);
		}
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_section_sort,ext);
	}
	else
	{
		if(m_inst==0) return;
		m_levels.RemoveAll();
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_section_name,m_name);
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_section_title,m_title.m_inst);
		m_title.CreateFromInst(m_title.m_inst,m_ReportMgr);
		aplExtent ext;
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_section_levels,ext);
		for(i=0; i<ext.GetSize();i++)
		{
			CSectionLevel* level = new CSectionLevel(m_ReportMgr);
			level->m_inst = ext[i];
			m_levels.Add(level);
		}
		m_levels.Update(set);
		CaplInstance* inst;
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_section_title_col,inst);
		m_title_column = m_levels.GetTitleColumn(inst);
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_apl_rep_section_conditions,ext);
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_apl_rep_section_show_es,m_show_empty_string_in_title);
		m_conditions.RemoveAll();
		for(i=0; i<ext.GetSize();i++)
		{
			CCondition* cond = new CCondition(m_ReportMgr);
			cond->m_inst = ext[i];
			cond->Update(set);
			m_conditions.Add(cond);
		}
		m_groups.RemoveAll();
		m_sorts.RemoveAll();
		ext.Clear();
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_section_groups,ext);
		for(i=0; i<ext.Size;i++)
		{
			CGroupCol* col = new CGroupCol(m_ReportMgr);
			col->m_inst = ext[i];
			col->Update(set);
			m_groups.Add(col);
		}
		ext.Clear();
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_section_sort,ext);
		CSortColumn* sort_col;
		for(i=0; i<ext.Size;i++)
		{
			sort_col = new CSortColumn(m_ReportMgr);
			if(m_ReportMgr->m_data->IsKindOf(ext[i], m_ReportMgr->e_apl_sort_column))
			{
				sort_col->m_inst = ext[i];
				sort_col->Update(set);
			}
			else
			{
				sort_col->m_column = m_ReportMgr->FindColumnByInst(ext[i]);
				sort_col->Update(true);
			}
			m_sorts.Add(sort_col);
		}
	}
}

void CSectionLevelArray::GetExtent(aplExtent &ext)
{
	ext.Clear();
	for(int i=0;i<m_Data.GetSize();i++)
		ext.Add(m_Data.GetAt(i)->m_inst);
}

CColumn* CSectionLevelArray::GetTitleColumn(CaplInstance *inst)
{
	if(inst==NULL) return NULL;
	int ind=-1;
	for(int i=0;i<m_Data.GetSize();i++)
	{
		ind = m_Data.GetAt(i)->m_columns.Find(inst);
		if(ind>-1) return m_Data.GetAt(i)->m_columns.GetAt(ind);
	}
	return NULL;
}

int CReportSection::GetRows()
{
	int rows, cols;
	m_ReportMgr->m_data_source.GetSize(rows,cols);
	int res = 1;
	if(m_show_empty_string_in_title>0) res=3;
	for(int i=0; i<rows;i++)
	{
		bool ok = true;
		ok = m_conditions.Compare(i);
		if(!ok) continue;
		for(int j=0; j<m_groups.GetSize();j++)
		{
			if(m_groups.GetAt(j)->m_conditions.Compare(i))
			{
				if(m_groups.GetAt(j)->m_row.GetSize()>0)
				res++;
			}
			else
			{
				ok = false;
				break;
			}
		}
		if(ok) res++;
	}
	return res;
}

CReportSection& CReportSection::operator = (CReportSection &sec)
{
	int i;
	m_name = sec.m_name;
	m_num = sec.m_num;
	m_title = sec.m_title;
	m_inst = sec.m_inst;
	m_show_empty_string_in_title = sec.m_show_empty_string_in_title;
	//Уровни
	m_levels = sec.m_levels;
	for(i=0; i<sec.m_levels.GetSize();i++)
		for(int j=0; j<sec.m_levels.GetAt(i)->m_columns.GetSize();j++)
			if(sec.m_levels.GetAt(i)->m_columns.GetAt(j)==sec.m_title_column)
				m_title_column = m_levels.GetAt(i)->m_columns.GetAt(j);
	//Условия
	m_conditions = sec.m_conditions;
	//Группы и сортировка
	m_groups = sec.m_groups;
	m_sorts.RemoveAll();
	for(i=0; i<sec.m_sorts.GetSize(); i++)
	{
		CSortColumn* sort_col = new CSortColumn(m_ReportMgr);
		*sort_col = *sec.m_sorts.GetAt(i);
		m_sorts.Add(sort_col);
	}
	return *this;
}

CReportElement* CReportSection::GenSection(CReportElement *table, int &start_row, int &y_pos, UINT flag)
{
	int k;
	//Определение полей сортировки и сортировка ИД перед генерацией.
	if(_pPrinterDC==NULL)
	{
		_pPrinterDC = new CDC;
		if(AfxGetApp()->CreatePrinterDC(*_pPrinterDC)!=TRUE)
		{
			throw(CString(APL_T("Не удалось создать контекст принтера. Генерация отчета невозможна!")));
		}
	}
	ISortArray sort_indexes_array;
	CArray<CaplReportValue*, CaplReportValue*> gr_values;//Значения групп.
	//Groups;
	TSortParam SortParam;
	for(k=0; k<m_groups.GetSize();k++)
	{
		memset(&SortParam, 0, sizeof(TSortParam));
		CHeaderColumn* col = m_groups.GetAt(k)->m_col;
		int ind = m_ReportMgr->m_data_source.GetColumnInd(col);
		if(ind<0) 
		{
			CString buf;
			buf.Format(APL_T("Не корректный шаблон: Не найдено поле источника данных (%s)."), col->GetName());
			throw(buf);
			return NULL;
		}
		SortParam.col_num = ind;
		SortParam.bSortAsString = m_groups.GetAt(k)->m_bSortAsString;
		SortParam.direction = m_groups.GetAt(k)->m_SortDirection;
		SortParam.m_Flags = m_groups.GetAt(k)->m_Flags;

		sort_indexes_array.Add(SortParam);
		gr_values.Add(NULL);
	}
	for(k=0; k<m_sorts.GetSize();k++)
	{
		memset(&SortParam, 0, sizeof(TSortParam));
		CSortColumn* col = m_sorts.GetAt(k);
		int ind = m_ReportMgr->m_data_source.GetColumnInd(col->m_column);
		if(ind<0) 
		{
			CString buf;
			buf.Format(APL_T("Не корректный шаблон: Не найдено поле источника данных (%s)."), col->m_column->GetName());
			throw(buf);
			return NULL;
		}
		SortParam.col_num = ind;
		SortParam.bSortAsString = col->m_bSortAsString;
		SortParam.direction = col->m_SortDirection;
		
		sort_indexes_array.Add(SortParam);
	}
	SaveToFile(m_ReportMgr);

	m_ReportMgr->m_data_source.Sort(&sort_indexes_array);

	SaveToFile(m_ReportMgr);

	int rows_cnt = GetRows();
	if((rows_cnt==3 && m_show_empty_string_in_title>0) || (rows_cnt==1 && m_show_empty_string_in_title==0))
	{
		if(flag&APL_SECTION_LINING_TO_END)
		{
			int row = start_row;
			while(AddTitle(table,row,y_pos)==0);
			start_row = 0;
			y_pos = 0;
		}
		return table;
	}
	CTableElement* tb = NULL;
	if(table->GetType()==E_TABLE)
		tb = (CTableElement*)table;
	else if(table->GetType()==E_TABLE_MAP)
		tb = ((CTableMapElement*)table)->m_table;
	else return NULL;

	//Создаем раздел содержания
	CTableContent* TableContent;
	if(!m_title.GetText().IsEmpty())
		 TableContent = new CTableContent(m_ReportMgr);
	else
		TableContent = NULL;
	m_CurTableContent = TableContent;
	if(TableContent)
	{
		TableContent->m_Title = m_title.GetText();
		m_ReportMgr->m_TableContents.Add(TableContent);
	}
	CArray<CTableContent*, CTableContent*> TableContents;
	TableContents.SetSize(m_groups.GetSize());

	CDataSource* ds = &table->m_ReportMgr->m_data_source;
	int tmp, rows;
	ds->GetSize(rows,tmp);
	int cur_page = 0;
	if(!m_title.GetText().IsEmpty() && m_title_column)
	{
		int tst_res = 0;
		tmp = 0;
		int tmp_y_pos = y_pos;
		int row = start_row;
		if(m_show_empty_string_in_title)
		{
			tmp = AddTitle(table, row, tmp_y_pos, AT_TEST);
			tst_res = tst_res>tmp ? tst_res : tmp;
			tmp = AddTitle(table, row, tmp_y_pos, AT_TEST);
			tst_res = tst_res>tmp ? tst_res : tmp;
		}
		tmp = AddTitle(table, row, tmp_y_pos, AT_TEST|AT_SHOW_TEXT);
		tst_res = tmp!=0 ? tmp:tst_res;
		//Определяем первую строку, которую необходимо отобразить и тестируем на ней
// 		tmp = AddTitle(table, row, tmp_y_pos,AT_TEST);
		for(int i=0; i<rows;i++)
		{
			if(!m_conditions.Compare(i)) continue;
			//Проверка на группы если новая то вывести наименование.
			bool ok = true;
			for(int g=0; g<m_groups.GetSize();g++)
			{
				if(m_groups.GetAt(g)->m_conditions.Compare(i)==false) 
				{
					ok = false;
					break;
				}
			}
			//Если не удовлетворяет условию то пропускаем.
			if(!ok) continue;
			
			if(m_groups.GetSize()>0)
			{
				for(int g=0; g<m_groups.GetSize();g++)
				{
					tmp = AddRow(ds, &table, i, row, tmp_y_pos, m_groups.GetAt(g), AT_TEST);
					if(tmp!=0) break;
				}
			}
			else
				tmp = AddRow(ds, &table, i, row, tmp_y_pos, NULL, AT_TEST);

			break;
		}

		tst_res = tmp!=0 ? tmp:tst_res;

		if(tst_res!=0)
		{
			//Разлиновка по предыдущей секции.
			int i(0);
			int sec_cnt = tb->m_sections.GetSize();
			CReportSection* sec = NULL;
			for(i=0; i<sec_cnt;i++)
			{
				if(tb->m_sections.GetAt(i)==this)
				{
					if(i>0)
						sec = tb->m_sections.GetAt(i-1);
					break;
				}
			}
			if(sec==NULL)
			{
				if(i==0)
					throw(CString(APL_T("Ошибка при генерации отчета: При данных параметрах шаблона невозможно на одной странице разместить строку!")));
				else
					throw(CString(APL_T("Ошибка при генерации отчета: Невозможно провести разлиновку секции!")));
				return NULL;
			}
			while(sec->AddTitle(table,row,y_pos)==0);
			start_row = 0;
			y_pos = 0;
			table = GetNextSheet(table->m_owner_sheet, table);
			if(table==0) return NULL;
		}
		row = start_row;
		if(m_show_empty_string_in_title>0) AddTitle(table, row, y_pos);
		AddTitle(table, row, y_pos, AT_SHOW_TEXT);
		if(m_show_empty_string_in_title>0) AddTitle(table, row, y_pos);
		start_row=row;
	}
	if(TableContent)
		TableContent->AddSheet(table->m_owner_sheet);

	//Заполнение данными
	CGroupCol* pGroup(NULL);
	bool bLRIsGroup = false;
	int row = start_row;
	m_CurentDrawRow = 1;
	for(int i=0; i<rows;i++)
	{
		if(!m_conditions.Compare(i)) continue;
		//Проверка на группы если новая то вывести наименование.
		bool ok = true;
		for(int g=0; g<m_groups.GetSize();g++)
		{
			pGroup =m_groups.GetAt(g);
			if(pGroup->m_conditions.Compare(i)==false) 
			{
				ok = false;
				break;
			}
			CaplReportValue* val = gr_values.GetAt(g);
			
			CaplReportValue* curent_val = m_ReportMgr->m_data_source.GetAt(i,m_groups.GetAt(g)->m_col);
			CString str1 = GetAsString(val);
			CString str2 = GetAsString(curent_val);
			if(val==NULL || str1!=str2)//Значение первое или новое
			{
				//Завершение предыдущей группы
				if(val!=NULL)
				{
					for(int tmp_g = m_groups.GetSize()-1; tmp_g>=g; tmp_g--)
					{
						if(m_groups.GetAt(tmp_g)->m_last_draw_row<0) continue;
						int res(0);
						
						// ЯАИ:  подитог группы из нескольких элементов (наверное)
						res = AddRow(ds, &table, m_groups.GetAt(tmp_g)->m_last_draw_row, row, y_pos,m_groups.GetAt(tmp_g), AT_FINISH_GROUP);
						if(res>0)//Неверные данные
						{
							throw(CString(APL_T("Ошибка при генерации отчета: Не удалось добавить строку (подитог группы)!")));
						}
						if(res<0)//нет места на странице
						{
							while(AddTitle(table,row,y_pos)==0);
							start_row = 0;
							y_pos = 0;
							//Следующая страница
							CReportElement* next = GetNextSheet(table->m_owner_sheet,table);
							if(next!=0 && next->GetType()==E_TABLE_MAP)
							{
								table = next;
								row = 0;
							}
							else
							{
								throw(CString(APL_T("Ошибка при генерации отчета: Не удалось найти следующую страницу или дублировать страницу.")));
							}
							//Пробуем на другой странице
							int res_L = AddRow(ds, &table, m_groups.GetAt(tmp_g)->m_last_draw_row, row, y_pos, m_groups.GetAt(tmp_g), AT_FINISH_GROUP);
							if(res_L!=0)
							{//если не удалось. то далее нет смысла продолжать.
								throw(CString(APL_T("Ошибка при генерации отчета: При данных параметрах шаблона невозможно на одной странице разместить строку.")));
							}
						}
					}
				}
				for(int tmp_g = g; tmp_g<m_groups.GetSize(); tmp_g++)
					gr_values.SetAt(tmp_g, NULL);
				//Отображение значение по группе и изменение текущих значений.
				for(int gd=g; gd<m_groups.GetSize(); gd++)
				{
					if(m_groups.GetAt(gd)->m_conditions.Compare(i)==false) 
					{
						ok = false;
						break;
					}

					if(gd>0)
					{
						CGroupCol* pPrevGroup = m_groups[gd-1];
						CGroupCol* pCurGroup = m_groups[gd];
						
						if(pPrevGroup->m_draw_first_row==pCurGroup->m_draw_first_row && pCurGroup->m_draw_first_row==1 && bLRIsGroup && val==NULL)
						{
							pCurGroup->m_last_draw_row = i;
							break;
						}
					}

					CaplReportValue* c_val = m_ReportMgr->m_data_source.GetAt(i, m_groups.GetAt(gd)->m_col);
					// ЯАИ: заголовок группы  (наверное)
					int res = AddRow(ds, &table, i, row, y_pos, m_groups.GetAt(gd));
					bLRIsGroup = true;
					if(res>0)//Неверные данные
					{
						throw(CString(APL_T("Ошибка при генерации отчета: Не удалось добавить строку в отчет.")));
					}
					if(res<0)//нет места на странице
					{				
						while(AddTitle(table,row,y_pos)==0);
						start_row = 0;
						y_pos = 0;
						//Следующая страница
						CReportElement* next = GetNextSheet(table->m_owner_sheet,table);
						if(next!=0 && next->GetType()==E_TABLE_MAP)
						{
							table = next;
							row = 0;
						}
						else
						{
							throw(CString(APL_T("Ошибка при генерации отчета: Не удалось найти следующую страницу или дублировать страницу.")));
						}
						//Пробуем на другой странице
						int res_L = AddRow(ds, &table, i, row, y_pos,m_groups.GetAt(gd));
						if(res_L!=0)
						{//если не удалось. то далее нет смысла продолжать.
							throw(CString(APL_T("Ошибка при генерации отчета: При данных параметрах шаблона невозможно на одной странице разместить строку.")));
						}
					}
					m_groups.GetAt(gd)->m_last_draw_row = i;
					gr_values.SetAt(gd, c_val);
					CString GroupName;
					m_CurTableContent = new CTableContent(m_ReportMgr);
					if(TableContents.GetSize()==0)
					{
						if(TableContent)
							TableContent->m_Childs.Add(m_CurTableContent);
						else
							m_ReportMgr->m_TableContents.Add(m_CurTableContent);
					}
					else
					{
						if(gd>0)
							TableContents.GetAt(gd-1)->m_Childs.Add(m_CurTableContent);
						else
						{
							if(TableContent)
								TableContent->m_Childs.Add(m_CurTableContent);
							else
								m_ReportMgr->m_TableContents.Add(m_CurTableContent);
						}
					}
					CString sFucnt = m_groups.GetAt(gd)->m_name;
					if(sFucnt.IsEmpty())
						sFucnt = m_groups.GetAt(gd)->m_col->m_name;
					sFucnt = sFucnt.Right(sFucnt.GetLength() - sFucnt.Find(_T('='))-1); 
					CDataSource::ParseFunction(sFucnt, GroupName, ds->GetRow(i), ds->GetHeader(), NULL, &ds->m_params, ds);
					m_CurTableContent->m_Title = GroupName;
					m_CurTableContent->AddSheet(table->m_owner_sheet);
					TableContents.SetAt(gd, m_CurTableContent);
					if(m_groups.GetAt(gd)->m_draw_first_row!=0)
					{
						ok = false;
						break;
					}
				}
			

				if(!ok)
					break;
			}
			if(!ok)
				break;
			m_groups.GetAt(g)->m_last_draw_row = i;
		}


		//Если не удовлетворяет условию то пропускаем.
		if(!ok) continue;

		bLRIsGroup = false;
		int res=AddRow(ds, &table, i, row, y_pos);
		if(res>0)
		{
			throw(CString(APL_T("Ошибка при генерации отчета: Не удалось добавить строку в отчет.")));
		}
		else if(res<0)
		{
			while(AddTitle(table,row,y_pos)==0);
			start_row = 0;
			y_pos = 0;

			// если отчет должен состоять только из одной страницы
			if(table->m_ReportMgr->GetReportOneSheetOnly())
			{
				// запомним на какой строке остановились
				for(int Inner=i-1; Inner>=0; --Inner)
					table->m_ReportMgr->m_data_source.DeleteRow(Inner);

				return table;
			}

			//Следующая страница
			CReportElement* next = GetNextSheet(table->m_owner_sheet,table);
			if(next!=0 && next->GetType()==E_TABLE_MAP)
			{
				table = next;
				row = 0;
			}
			else
			{
				throw(CString(APL_T("Ошибка при генерации отчета: Не удалось найти следующую страницу или дублировать страницу.")));
			}
			res = AddRow(ds, &table, i, row, y_pos);
			if(res>0)
			{
				return NULL;
			}
			else if(res<0)
			{
				throw(CString(APL_T("Ошибка при генерации отчета: В таблицу не помещается ни одна строка!")));
			}
			if(m_CurTableContent)
				m_CurTableContent->AddSheet(table->m_owner_sheet);
		}
	}

	{
		for(int tmp_g = m_groups.GetSize()-1; tmp_g>=0; tmp_g--)
		{
			if(m_groups.GetAt(tmp_g)->m_last_draw_row<0) continue;
			
			//ЯАИ: подитог группы из одной строки (наверное)
			int res = AddRow(ds, &table, m_groups.GetAt(tmp_g)->m_last_draw_row, row, y_pos, m_groups.GetAt(tmp_g), AT_FINISH_GROUP);
			if(res>0)//Неверные данные
			{
				throw(CString(APL_T("Ошибка при генерации отчета (подитог группы).")));
			}
			if(res==-1)//нет места на странице
			{
				while(AddTitle(table,row,y_pos)==0);
				start_row = 0;
				y_pos = 0;
				//Следующая страница
				CReportElement* next = GetNextSheet(table->m_owner_sheet,table);
				if(next!=0 && next->GetType()==E_TABLE_MAP)
				{
					table = next;
					row = 0;
				}
				else
				{
					throw(CString(APL_T("В таблицу не помещается ни одна строка!")));
				}
				//Пробуем на другой странице
				int res_L = AddRow(ds, &table, m_groups.GetAt(tmp_g)->m_last_draw_row, row, y_pos,m_groups.GetAt(tmp_g), AT_FINISH_GROUP);
				if(res_L!=0)
				{//если не удалось. то далее нет смысла продолжать.
					throw(CString(APL_T("В таблицу не помещается ни одна строка!")));
				}
			}
			else if(res<-1)//Прочая критическая ошибка.
			{
				throw(CString(APL_T("Ошибка при генерации отчета (-2).")));
			}
		}
	}

	// если стоит режим "отчет на одной странице" и все смогло поместилось на одну страницу
	if(table->m_ReportMgr->GetReportOneSheetOnly())
	{
		const int nRows = table->m_ReportMgr->m_data_source.GetRows();
		for(int Inner=nRows-1; Inner>=0; --Inner)
			table->m_ReportMgr->m_data_source.DeleteRow(Inner);
	}

	if(flag&APL_SECTION_LINING_TO_END)
		while(AddTitle(table,row,y_pos)==0);
	start_row = row;

	if(m_ColumnsWithZerroWidth.GetSize()>0)
	{
		CString buf, msg_text;
		for(int i=0; i<m_ColumnsWithZerroWidth.GetSize(); i++)
			buf=buf+m_ColumnsWithZerroWidth[i]+_T("\n");
		msg_text.Format(APL_T("При формировании секции \"%s\" в следующие поля таблицы не помещается ни один символ: %sЗначения данных полей пусты!"), m_name, buf);
		TRACE_TO_FILE(msg_text);
	}

	return table;
}

#define REP_MULTIROW_FONT_HEIGHT_KOEF	1.4

int CReportSection::AddRow(CDataSource *ds, CReportElement **table,int ind, int &row, int &y_pos, CGroupCol* group_col, UINT flag)
{
	if(_pPrinterDC==NULL) throw(CString(APL_T("Принтер не задан или невозможно создать контекст принтера. Генерация отчета невозможна!")));
	if(table==NULL) return -2;
	CTableElement* tb = NULL;
	if((*table)->GetType()==E_TABLE)
		tb = (CTableElement*)(*table);
	else if((*table)->GetType()==E_TABLE_MAP)
		tb = ((CTableMapElement*)(*table))->m_table;
	else return 1;
	//Область таблицы
	CRect rect;
	(*table)->GetRect(rect,1,1);
	rect.NormalizeRect();
	//Проверка сколько строк нужно чтобы вывести данную строку;
	CArray<CStringArray*, CStringArray*> m_strings;
	//контекст устройства
	int mm = _pPrinterDC->SetMapMode(MM_LOMETRIC);
	CFont font;
	if(group_col==0)
		font.CreatePointFontIndirect(&tb->m_row_lf, _pPrinterDC);
	else
		font.CreatePointFontIndirect(&group_col->m_lf, _pPrinterDC);
	CFont *old = _pPrinterDC->SelectObject(&font);

	bool bIncrDR(false);
	TEXTMETRIC tm;
	_pPrinterDC->GetTextMetrics(&tm);

	int cnt = 0;
	int max_row = 0, max_ = 0;
	CString error_msg;
	CUIntArray rows_array;
	CSectionLevelArray* pLArray = NULL;
	bool bOneRow = false;
	int lev_cnt = 0;
	if(group_col)
	{
		if(flag&AT_FINISH_GROUP)
		{
			if(group_col->m_Flags&APL_GROUP_DONOT_SHOW_LAST_ROW_IF_ONE_ROW_IN_GROUP)
			{
				double ds_cnt = ds->GetCountInGroup(ind, &m_groups, group_col, NULL, _T(""), &m_conditions);
				if(ds_cnt==1)
					return 0;
			}
			pLArray = &group_col->m_last_row;
		}
		else
		{
			double ds_cnt = ds->GetCountInGroup(ind, &m_groups, group_col, NULL, _T(""), &m_conditions);
			bOneRow = (ds_cnt==1 && group_col->m_Flags&APL_GROUP_SHOW_OTHER_ROW_IF_ONE_ROW_IN_GROUP);
			if(bOneRow)
			{
				pLArray = &group_col->m_one_row; 

				//ЯАИ: тут печатается одна строка
				//ЯАИ: если группа из одной строки, то все подгруппы типа тоже
				{
					for(int k=m_groups.GetSize()-1; k>0; k--)
					{
						if(m_groups.GetAt(k)==group_col)break;
						m_groups.GetAt(k)->m_last_draw_row=ind;
					}
				}
			}
			else
				pLArray = &group_col->m_row;
		}
	}
	else
		pLArray = &m_levels;
	lev_cnt = pLArray->GetSize();
	if(lev_cnt==0) return 0;
	BOOL *empty = new BOOL[lev_cnt];
	for(int ei=0; ei<lev_cnt; ++ei) empty[ei]=true;
	int tmp_y_pos(y_pos);
	int r(0);
	for(r=0; r<lev_cnt;r++)
	{
		empty[r] = TRUE;
		CSectionLevel* lev = pLArray->GetAt(r);
		if(lev->m_height==0)
			lev->m_height = tb->m_row_height*10;
		max_ = 0;

		//  [10/21/2013 lobanov]
		// не знаю откуда взялся этот код - но он неправильный - нумерация m_CurentDrawRow - это номер строки из источника данных,
		// а не номер уровня - фигня какая-то, из-за этого для многоуровневых строк нумерация была неправильной, убрал из-за бага №20655 в ILS
/*
		if(bIncrDR)
		{
			bIncrDR= false;
			m_CurentDrawRow++;
		}
*/

		for(int i=0; i<lev->m_columns.GetSize();i++)
		{
			CColumn* col = lev->m_columns.GetAt(i);
			//Берем значение из ист. данных и преобразуем его к строке
			CaplReportValue* val=0;
			CString str=_T("");
			if(col->m_ds_column!=0)
			{
				if(col->m_ColumnType==aplVALUE)
				{
					val = ds->GetAt(ind,col->m_ds_column);
					if(val==0) continue;
					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);
						if(col->m_ds_column)
						{
							int iColInd(ds->GetHeader()->Find(col->m_ds_column->m_name));
							if(iColInd>-1)
							{
								CHeaderColumn *pCol = ds->GetHeader()->GetColumn(iColInd);
								str.Format(pCol->m_sFormat, tmp);
							}
						}
						else
							str.Format(_T("%g"),tmp);
					}
					else if(val->type==aplBINARY)
					{
						CaplDataBuf *buf;
						val->Get(&buf);
						if(buf->m_Size>0)
							empty[r]=FALSE;
					}
				}
				else if(col->m_ColumnType==aplSUMM)
				{
					int Rows;
					double Value = ds->GetSummInGroup(ind, &m_groups, group_col, col->m_ds_column, &m_conditions, &Rows);
					if(Rows>1 || !(col->m_params&APL_COLUMN_NOT_SHOW_ZERO))
					{
						if(col->m_ds_column)
						{
							int iColInd(ds->GetHeader()->Find(col->m_ds_column->m_name));
							if(iColInd>-1)
							{
								CHeaderColumn *pCol = ds->GetHeader()->GetColumn(iColInd);
								str.Format(pCol->m_sFormat, Value);
							}
						}
						else
							CDataSource::GetDoubleAsString(Value, str);
					}
					else
						str=_T("");
				}
				else if(col->m_ColumnType==aplAVERANGE)
				{
					double Value = ds->GetAverangeInGroup(ind, &m_groups, group_col, col->m_ds_column, &m_conditions);
				}
				else if(col->m_ColumnType==aplSTRCONST)
					str = col->m_TextCnst;
				else if(col->m_ColumnType==aplCOUNT)
				{
					double Value = ds->GetCountInGroup(ind, &m_groups, group_col, NULL, col->m_sCondition, &m_conditions);
					if(Value!=0 || !(col->m_params&APL_COLUMN_NOT_SHOW_ZERO))
					{
						if(col->m_ds_column)
						{
							int iColInd(ds->GetHeader()->Find(col->m_ds_column->m_name));
							if(iColInd>-1)
							{
								CHeaderColumn *pCol = ds->GetHeader()->GetColumn(iColInd);
								str.Format(pCol->m_sFormat, Value);
							}
						}
						else
							CDataSource::GetDoubleAsString(Value, str);
					}
					else
						str = _T("");
				}
			}
			else if(col->m_ColumnType==aplSTRCONST)
				str = col->m_TextCnst;
			else if(col->m_ColumnType==aplCOUNT)
			{
				double Value = ds->GetCountInGroup(ind, &m_groups, group_col, NULL, col->m_sCondition, &m_conditions);
				if(Value!=0 || !(col->m_params&APL_COLUMN_NOT_SHOW_ZERO))
				{
					if(col->m_ds_column)
					{
						int iColInd(ds->GetHeader()->Find(col->m_ds_column->m_name));
						if(iColInd>-1)
						{
							CHeaderColumn *pCol = ds->GetHeader()->GetColumn(iColInd);
							str.Format(pCol->m_sFormat, Value);
						}
					}
					else
						CDataSource::GetDoubleAsString(Value, str);
				}
				else
					str = _T("");
			}
			if(col->m_params&APL_COLUMN_SHOWASDATE)
			{
				if(str.GetLength()==14)
				{
					aplGetFormatedDate(str, str);
				}
			}
			if(col->m_params&APL_COLUMN_SHOWASTIME)
			{
				double dVal(__atof(str));
				aplGetAsHM(dVal, str);
			}
			if(!str.IsEmpty()/* && col->m_ColumnType==aplVALUE*/)
				empty[r]=FALSE;
			if(col->m_show_flag==APL_COLUMN_SHOW_LEVEL_NAME)
				str = lev->m_name;
			else if(col->m_show_flag==APL_COLUMN_SHOW_ROW_NUM)
			{
				str.Format(_T("%i"), m_CurentDrawRow);
				bIncrDR = true;
			}
			//разбиваем строку если необходимо
			CStringArray *strs = new CStringArray;
			cnt = 1;
			if(col->m_fit_to_rect==0)
			{
				CFont tmpFont, *oldFont(NULL);
//!!				[Колесников А.С. 28.01.2011] По согласованию с Нахимовичем убрали уменьшение шрифта при печати нескольких строк внутри одной ячейки
 				if(col->m_RowsCount>1)
 				{
 					LOGFONT lf;
 					if(group_col==0)
 						lf = tb->m_row_lf;
 					else
 						lf = group_col->m_lf;

 					// ayatsk 08.02.2011 Изменил для корректного изменения шрифта при кол-ве строк более 2
					// актуально в спецификации и КВЗ
					//lf.lfHeight = (int)((double)lf.lfHeight/(col->m_RowsCount)*REP_MULTIROW_FONT_HEIGHT_KOEF);
					
					//int h1= (int)((double)lf.lfHeight/(col->m_RowsCount)*REP_MULTIROW_FONT_HEIGHT_KOEF);
					
					double interval=0;
					if(lev->m_space_para==aplSpacePara15)	interval=0.5;		
					else if(lev->m_space_para==aplSpacePara2)	interval=1;					
					interval*=(col->m_RowsCount-1);
					int max_h= (int)((254/72)*(double)lev->m_height/ (col->m_RowsCount + interval));//максимально возможная высота
					if(lf.lfHeight>max_h)lf.lfHeight=max_h;

 					tmpFont.CreatePointFontIndirect(&lf, _pPrinterDC);
 					oldFont = _pPrinterDC->SelectObject(&tmpFont);
 				}
			cnt = CTextValue::BreakString(strs, col->m_width-12-col->m_border*4, _pPrinterDC, str);
				if(cnt<0)
				{
					error_msg.Format(APL_T("строка: %d, поле:%s, ширина: %d исходная строка %s. В заданную ширину не умещается ни один символ!"), ind, col->m_name, col->m_width, str);
					TRACE_TO_FILE(error_msg);
				}
 				if(col->m_RowsCount>1)
 				{
 					_pPrinterDC->SelectObject(oldFont);
 					tmpFont.DeleteObject();
 				}
				if(cnt<=0)
				{
					strs->Add(_T(""));
					cnt=1;
					if(col->m_ds_column && cnt<0)
					{
						bool bfind;
						for(int cur_ind = 0; cur_ind<m_ColumnsWithZerroWidth.GetSize(); cur_ind++)
						{
							if(m_ColumnsWithZerroWidth.GetAt(cur_ind)==col->m_ds_column->GetName())
							{
								bfind = true;
								break;
							}
						}
						if(!bfind)
							m_ColumnsWithZerroWidth.Add(col->m_ds_column->GetName());
					}
				}
			}
			else
				strs->Add(str);
			int br_str_cnt = strs->GetSize();
			int v=0;
			CString brBuf;
			CStringArray tmpArrStr;				
			int sz;
			for(sz = 0; sz<br_str_cnt; sz++)
			{
				brBuf+=strs->GetAt(sz);
				v++;
				if(v==col->m_RowsCount)
				{
					tmpArrStr.Add(brBuf);
					brBuf=_T("");
					v=0;
				}
				else if(sz<br_str_cnt-1 && !brBuf.IsEmpty())
					brBuf+=_T("\n");
			}
			if(v>0 && v<col->m_RowsCount)
				tmpArrStr.Add(brBuf);
			strs->RemoveAll();
			for(sz=0; sz<tmpArrStr.GetSize(); sz++)
				strs->Add(tmpArrStr.GetAt(sz));
			max_ = max_>strs->GetSize() ? max_ : strs->GetSize();
			m_strings.Add(strs); //Добавили в массив строк для отображения
		}
		bool bSkip = lev->m_flag&APL_SEC_LEVEL_SKIP_IF_EMPTY && empty[r];
		if(!bSkip)
			tmp_y_pos-=lev->m_height;
		if(tmp_y_pos<rect.top-rect.bottom && !bSkip)
		{
			CStringArray* strarr;
			for(int m=0; m<m_strings.GetSize();m++)
			{
				strarr = m_strings.GetAt(m);
				DELETE_OBJECT(strarr);
			}
			m_strings.RemoveAll();
			delete []empty;
			_pPrinterDC->SelectObject(old);
			_pPrinterDC->SetMapMode(mm);
			return -1;//Не влезает на страницу
		}
		if(!bSkip)
		{
			//Рассчитываем высоту
			if((lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT) && !(lev->m_flag&APL_SEC_LEVEL_USE_MULTIPLE_HEIGHT))
			{
				int h = (tm.tmAscent)*max_+tm.tmExternalLeading*(max_-1)+28+(tm.tmDescent+tm.tmExternalLeading);
				if(lev->m_space_para==aplSpacePara15)
					h = (tm.tmAscent)*max_+(tm.tmDescent+tm.tmExternalLeading)*(max_-1)+28+(tm.tmDescent+tm.tmExternalLeading);
				else if(lev->m_space_para==aplSpacePara2)
					h = (tm.tmAscent)*max_+(tm.tmDescent+tm.tmExternalLeading)*2*(max_-1)+28+(tm.tmDescent+tm.tmExternalLeading);
				if(h<lev->m_height)
					h = lev->m_height;

				tmp_y_pos-=h-lev->m_height;
			}
			else
			{
				tmp_y_pos-=lev->m_height*(max_-1);
			}
		}
		if(tmp_y_pos<rect.top-rect.bottom && !bSkip && lev->m_flag&APL_SEC_LEVEL_NOT_BREAK_STRING)
		{
			CStringArray* strarr;
			for(int m=0; m<m_strings.GetSize();m++)
			{
				strarr = m_strings.GetAt(m);
				DELETE_OBJECT(strarr);
			}
			m_strings.RemoveAll();
			DELETE_OBJECT([]empty);
			_pPrinterDC->SelectObject(old);
			_pPrinterDC->SetMapMode(mm);
			return -1;//Не влезает на страницу
		}
		max_row+=max_;
		rows_array.Add(max_);
	}
	_pPrinterDC->SelectObject(old);
	_pPrinterDC->SetMapMode(mm);
	if(group_col && !(group_col->m_Flags&APL_GROUP_ALLOW_BREAK_ROWS))//
	{
		int iRow = ind;
		int gr_ind = -1, tmp_row = row;
		bool bUseTest = true;
		CGroupCol* col = NULL;

		if(bOneRow)
			bUseTest = false;
		else
		{
			if(group_col->m_draw_first_row!=0)
				iRow++;
			for(int j=0; j<m_groups.GetSize(); j++)
			{
				if(m_groups.GetAt(j)==group_col)
				{
					gr_ind = j;
					break;
				}
			}
			if(gr_ind>=0 && gr_ind<m_groups.GetSize()-1)
			{
				gr_ind++;
				col = m_groups.GetAt(gr_ind);
			}
			if(col)
			{
				if(col->m_conditions.Compare(iRow)==false) 
					bUseTest = false;
			}
		}
		if(bUseTest && !(flag&AT_FINISH_GROUP))
		{
			int res = AddRow(ds, table, iRow, tmp_row, tmp_y_pos, col, AT_TEST);
			if(res!=0)
			{
				CStringArray* strarr;
				for(int m=0; m<m_strings.GetSize();m++)
				{
					strarr = m_strings.GetAt(m);
					DELETE_OBJECT(strarr);
				}
				m_strings.RemoveAll();
				delete []empty;
				return res;
			}
		}
	}
	if(flag&AT_TEST)
	{
		CStringArray* strarr;
		for(int m=0; m<m_strings.GetSize();m++)
		{
			strarr = m_strings.GetAt(m);
			DELETE_OBJECT(strarr);
		}
		m_strings.RemoveAll();
		delete []empty;
		return 0; //все нормально
	}
	int dx;
	int str_array_ind = 0;
	CRectReportElement *pRectElem = NULL;
	for(r=0; r<lev_cnt;r++)
	{
		//Цикл для отображения всех строк.
		CSectionLevel *lev = pLArray->GetAt(r);
		if(empty[r]==TRUE && lev->m_flag&APL_SEC_LEVEL_SKIP_IF_EMPTY)
		{
			for(int j=0; j<lev->m_columns.GetSize();j++)
				str_array_ind++;
			continue;
		}
		max_=rows_array.GetAt(r);
		int start_ind = str_array_ind;
		if(!(lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT) || (lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT && lev->m_flag&APL_SEC_LEVEL_USE_MULTIPLE_HEIGHT))
		{
			if(lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT)
			{
				dx = 0;
				int old_y_pos = y_pos;
				y_pos-=lev->m_height*max_;
				for(int j=0; j<lev->m_columns.GetSize();j++)
				{
					CColumn* col = lev->m_columns.GetAt(j);
					//Берем значение из ист. данных и преобразуем его к строке
					CaplReportValue* val=NULL;
					val = ds->GetAt(ind,col->m_ds_column);
					CRectReportElement* elem = NULL;
					elem = new CRectReportElement(m_ReportMgr);//elem->m_type = E_RECT;
					elem->m_org_pt.x = rect.left+dx;
					elem->m_org_pt.y = rect.bottom+y_pos;
					elem->m_size = CSize(col->m_width,lev->m_height*max_);
					elem->m_value.SetText(_T(""));
					elem->m_value.m_text_params |=APL_TP_NOTBREAKSTRING;
					if(col->m_params&APL_COLUMN_SHOW_TOP_LINE)
						elem->m_Flags |=APL_RRE_SHOW_TOP_LINE;
					if(group_col==0)
						elem->m_value.m_font = tb->m_row_lf;
					else
						elem->m_value.m_font = group_col->m_lf;
					elem->m_value.m_align = col->m_align;
					elem->m_value.m_text_params = col->m_fit_to_rect;
					elem->m_line_width = col->m_border;
					if(val)
					{
						elem->m_color = val->m_line_color;
						elem->m_value.m_color = val->m_text_color;
						if (val->m_bold)
							elem->m_value.m_font.lfWeight = FW_BOLD;
						if (val->m_italic)
							elem->m_value.m_font.lfItalic = TRUE;
					}
 					if(col->m_RowsCount>1)
					{
						// ayatsk 08.02.2011 Изменил для корректного изменения шрифта при кол-ве строк более 2
 						//elem->m_value.m_font.lfHeight = (int)((elem->m_value.m_font.lfHeight/col->m_RowsCount)*REP_MULTIROW_FONT_HEIGHT_KOEF);

						double interval=0;
						if(lev->m_space_para==aplSpacePara15)	interval=0.5;		
						else if(lev->m_space_para==aplSpacePara2)	interval=1;					
						interval*=(col->m_RowsCount-1);
						int max_h= (int)((254/72)*(double)lev->m_height/ (col->m_RowsCount + interval));//максимально возможная высота
						if(elem->m_value.m_font.lfHeight>max_h)elem->m_value.m_font.lfHeight=max_h;

					}
					elem->m_value.m_space_para = col->m_SpacePara;
					elem->m_dsfrow = ind;
					elem->m_dsfcol = ds->GetColumnInd(col->m_ds_column);
					elem->m_bNeedFillBackground = (lev->m_flag&APL_SEC_LEVEL_USE_ROW_COLOR)!=0?true:false;
					if(elem->m_bNeedFillBackground)
						elem->m_background_color = lev->m_row_color;
					dx+=col->m_width;
					(*table)->m_owner_sheet->Add(elem);
					str_array_ind++;
				}
				y_pos = old_y_pos;
			}

			bool bMergeMultiRow = m_ReportMgr->GetMergeMultiRow();
			std::vector<CReportElement*> cur_elements;
			cur_elements.resize(lev->m_columns.GetSize(), NULL);
			for(int i=0; i<(max_>lev->m_MinRows?max_:lev->m_MinRows);i++)
			{
				str_array_ind = start_ind;
				dx=0;
				y_pos-=lev->m_height;
				if(lev->m_name==_T("picture")) // ЯАИ:  Моя затычка чтобы менять высоту уровня под картинку
				{
					//if(lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT)
					{
						int img_cx=0,img_cy=0;
						GetHighSectionLevelWithPict(m_ReportMgr, lev,ds, ind,img_cx,img_cy);
						if(img_cy!=0)
							y_pos-=(img_cy-lev->m_height);
					}
				}
				if(y_pos<rect.top-rect.bottom)
				{
					if(lev->m_flag&APL_SEC_LEVEL_NOT_SHOW_EMPTY_ROWS_ON_NEW_PAGE && i>max_-1)
						break;
					//Необходимо получить указатель на следующую страницу и там продолжить отрисовку.
					CReportElement* next = GetNextSheet((*table)->m_owner_sheet, (*table));
					if(next!=0 && next->GetType()==E_TABLE_MAP)
					{
						(*table) = next;
						y_pos = -lev->m_height;
						if(lev->m_name==_T("picture"))  // ЯАИ: Копия затычки (см. чуть выше)
						{
							//if(lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT)
							{
								int img_cx=0,img_cy=0;
								GetHighSectionLevelWithPict(m_ReportMgr,lev,ds, ind,img_cx,img_cy);
								if(img_cy!=0)
									y_pos-=(img_cy-lev->m_height);
							}
						}
					}
					else
					{
						for(int m=0; m<m_strings.GetSize();m++)
							delete m_strings.GetAt(m);
						m_strings.RemoveAll();
						return -2;
					}
					(*table)->GetRect(rect,1,1);
					rect.NormalizeRect();
					if(y_pos<rect.top-rect.bottom)
					{
						for(int m=0; m<m_strings.GetSize();m++)
							delete m_strings.GetAt(m);
						m_strings.RemoveAll();
						return -2;
					}

					// очищаем прмоугольники для объединения, т.к. начинаем с новой страницы
					for (size_t c = 0; c < cur_elements.size(); ++c)
					{
						cur_elements[c] = NULL;
					}
				}
				for(int j=0; j<lev->m_columns.GetSize();j++)
				{
					CColumn* col = lev->m_columns.GetAt(j);
					//Берем значение из ист. данных и преобразуем его к строке
					CaplReportValue* val=NULL;
					val = ds->GetAt(ind, col->m_ds_column);
					CReportElement* elem = NULL;
					if (bMergeMultiRow)
					{
						if (cur_elements[j])
						{
							elem = cur_elements[j];
							elem->m_org_pt.y -= lev->m_height;
							elem->m_size.cy += lev->m_height;
							if (str_array_ind < m_strings.GetSize())
							{
								pRectElem = (CRectReportElement*)elem;
								CStringArray* strs = m_strings.GetAt(str_array_ind);
								if (strs->GetSize() > i)
								{
									CString str = pRectElem->m_value.m_text;
									if (!str.IsEmpty())
									{
										str += _T("\n");
									}
									str += strs->GetAt(i);
									pRectElem->m_value.SetText(str);
								}
							}

							str_array_ind++;
							continue;
						}
					}

					if (elem==NULL)
					{
						if (val != NULL && val->type == aplBINARY)
							elem = new CPictureElement(m_ReportMgr);
						else
						{
							elem = new CRectReportElement(m_ReportMgr);//elem->m_type = E_RECT;
							if (col->m_params & APL_COLUMN_SHOW_TOP_LINE)
								((CRectReportElement*)elem)->m_Flags |= APL_RRE_SHOW_TOP_LINE;
							cur_elements[j] = elem;
						}
					}
					elem->m_org_pt.x = rect.left+dx;
					elem->m_org_pt.y = rect.bottom+y_pos;
					elem->m_size = CSize(col->m_width,lev->m_height);
					elem->m_bNeedFillBackground = (lev->m_flag&APL_SEC_LEVEL_USE_ROW_COLOR)!=0?true:false;
					if(elem->m_bNeedFillBackground)
						elem->m_background_color = lev->m_row_color;
					if(elem->GetType()!=E_PICTURE)
					{
						pRectElem = (CRectReportElement*)elem;
						pRectElem->m_value.SetText(_T(""));
						pRectElem->m_value.m_text_params |=APL_TP_NOTBREAKSTRING;
						if(str_array_ind<m_strings.GetSize())
						{
							CStringArray *strs = m_strings.GetAt(str_array_ind);
							if(strs->GetSize()>i)
							{
								CString str = strs->GetAt(i);
								pRectElem->m_value.SetText(str);
							}
						}
						if(group_col==0)
							pRectElem->m_value.m_font = tb->m_row_lf;
						else
							pRectElem->m_value.m_font = group_col->m_lf;
						pRectElem->m_value.m_align = col->m_align;
						pRectElem->m_value.m_text_params = col->m_fit_to_rect;
						if(lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT)
							pRectElem->m_line_width = 0;
						else
							pRectElem->m_line_width = col->m_border;
 						if(col->m_RowsCount>1)
						{
								// ayatsk 08.02.2011 Изменил для корректного изменения шрифта при кол-ве строк более 2
								//pRectElem->m_value.m_font.lfHeight = (int)((pRectElem->m_value.m_font.lfHeight/col->m_RowsCount)*REP_MULTIROW_FONT_HEIGHT_KOEF);
								double interval=0;
								if(lev->m_space_para==aplSpacePara15)	interval=0.5;		
								else if(lev->m_space_para==aplSpacePara2)	interval=1;					
								interval*=(col->m_RowsCount-1);
								int max_h= (int)((254/72)*(double)lev->m_height/ (col->m_RowsCount + interval));//максимально возможная высота
								if(pRectElem->m_value.m_font.lfHeight>max_h)pRectElem->m_value.m_font.lfHeight=max_h;
						}
						pRectElem->m_value.m_space_para = col->m_SpacePara;

						pRectElem->m_dsfrow = ind;
						pRectElem->m_dsfcol = ds->GetColumnInd(col->m_ds_column);

						if(val)
						{
							pRectElem->m_color = val->m_line_color;
							pRectElem->m_value.m_color = val->m_text_color;
							if (val->m_bold)
								pRectElem->m_value.m_font.lfWeight = FW_BOLD;
							if (val->m_italic)
								pRectElem->m_value.m_font.lfItalic = TRUE;
						}
					}
					else
					{
						// Фиксированная высота строки
						CaplDataBuf *buf;
						val->Get(&buf);
						CFile f;
						CString tmp; tmp.GetEnvironmentVariable(_T("temp"));
						tmp+=_T("\\picture.png");
						if(f.Open(tmp,CFile::modeCreate|CFile::modeWrite))
						{
							f.Write(buf->GetBuffer(),buf->m_Size);
							f.Close();
						}
						((CPictureElement*)elem)->m_mode = DM_FIT_TO_RECT;
						((CPictureElement*)elem)->LoadPicture(tmp);
						CFile::Remove(tmp);

						CPictureElement *pict_el=(CPictureElement*)elem;
						CSize sz0= pict_el->m_size; // размер поля в шаблоне 
						int img_cx=0,img_cy=0;
						GetCPictureElementProportionalSize(pict_el,sz0.cx,img_cx,img_cy);
						elem->m_size.cy=img_cy;
						elem->m_size.cx=img_cx;
					}
					dx+=col->m_width;
					(*table)->m_owner_sheet->Add(elem);
					str_array_ind++;
				}
				row++;
			}
		}
		else if(lev->m_flag&APL_SEC_LEVEL_AUTOCLAC_HEIGHT && !(lev->m_flag&APL_SEC_LEVEL_USE_MULTIPLE_HEIGHT))
		{
			int h = (tm.tmAscent)*max_+tm.tmExternalLeading*(max_-1)+28+(tm.tmDescent+tm.tmExternalLeading);
			if(lev->m_space_para==aplSpacePara15)
				h = (tm.tmAscent)*max_+(tm.tmDescent+tm.tmExternalLeading)*(max_-1)+28+(tm.tmDescent+tm.tmExternalLeading);
			else if(lev->m_space_para==aplSpacePara2)
				h = (tm.tmAscent)*max_+(tm.tmDescent+tm.tmExternalLeading)*2*(max_-1)+28+(tm.tmDescent+tm.tmExternalLeading);
			if(h<lev->m_height)
				h = lev->m_height;

			y_pos-=h;

			dx = 0;
			for(int j=0; j<lev->m_columns.GetSize();j++)
			{
				CColumn* col = lev->m_columns.GetAt(j);
				//Берем значение из ист. данных и преобразуем его к строке
				CaplReportValue* val=NULL;
				val = ds->GetAt(ind,col->m_ds_column);
				CReportElement* elem = NULL;
				if(val!=NULL && val->type==aplBINARY)
					elem = new CPictureElement(m_ReportMgr);
				else
					elem = new CRectReportElement(m_ReportMgr);//elem->m_type = E_RECT;
				elem->m_org_pt.x = rect.left+dx;
				elem->m_org_pt.y = rect.bottom+y_pos;
				elem->m_size = CSize(col->m_width, h);

				elem->m_line_width = col->m_border;
				if(elem->m_bNeedFillBackground)
					elem->m_background_color = lev->m_row_color;

				if(elem->GetType()!=E_PICTURE)
				{
					((CRectReportElement*)elem)->m_value.SetText(_T(""));
					((CRectReportElement*)elem)->m_value.m_text_params |=APL_TP_NOTBREAKSTRING;
					((CRectReportElement*)elem)->m_bNeedFillBackground = (lev->m_flag&APL_SEC_LEVEL_USE_ROW_COLOR)!=0?true:false;
					if(val)
					{
						((CRectReportElement*)elem)->m_color = val->m_line_color;
						((CRectReportElement*)elem)->m_value.m_color = val->m_text_color;
					}
					if(col->m_params&APL_COLUMN_SHOW_TOP_LINE)
						((CRectReportElement*)elem)->m_Flags |=APL_RRE_SHOW_TOP_LINE;
					if(str_array_ind<m_strings.GetSize())
					{
						CStringArray *strs = m_strings.GetAt(str_array_ind);
						int str_i;
						CString str;
						str.Empty();
						for(str_i=0; str_i<strs->GetSize(); str_i++)
						{
							str += strs->GetAt(str_i);
							if(str_i<strs->GetSize()-1)
								str += _T("\r\n");
						}
						((CRectReportElement*)elem)->m_value.SetText(str);
					}
					if(group_col==0)
						((CRectReportElement*)elem)->m_value.m_font = tb->m_row_lf;
					else
						((CRectReportElement*)elem)->m_value.m_font = group_col->m_lf;
					if (val)
					{
						if (val->m_bold)
							((CRectReportElement*)elem)->m_value.m_font.lfWeight = FW_BOLD;
						if (val->m_italic)
							((CRectReportElement*)elem)->m_value.m_font.lfItalic = TRUE;
					}
					((CRectReportElement*)elem)->m_value.m_align = col->m_align;
					((CRectReportElement*)elem)->m_value.m_text_params = col->m_fit_to_rect;
 					if(col->m_RowsCount>1)
					{
						// ayatsk 08.02.2011 Изменил для корректного изменения шрифта при кол-ве строк более 2
 						//((CRectReportElement*)elem)->m_value.m_font.lfHeight = (int)((((CRectReportElement*)elem)->m_value.m_font.lfHeight/col->m_RowsCount)*REP_MULTIROW_FONT_HEIGHT_KOEF);
						double interval=0;
						if(lev->m_space_para==aplSpacePara15)	interval=0.5;		
						else if(lev->m_space_para==aplSpacePara2)	interval=1;					
						interval*=(col->m_RowsCount-1);
						int max_h= (int)((254/72)*(double)lev->m_height/ (col->m_RowsCount + interval));//максимально возможная высота
						if(((CRectReportElement*)elem)->m_value.m_font.lfHeight>max_h)((CRectReportElement*)elem)->m_value.m_font.lfHeight=max_h;
					}
					((CRectReportElement*)elem)->m_value.m_space_para = lev->m_space_para;
					((CRectReportElement*)elem)->m_dsfrow = ind;
					((CRectReportElement*)elem)->m_dsfcol = ds->GetColumnInd(col->m_ds_column);
				}
				else
				{
					// Вариант с автоподбором высоты строки
					CaplDataBuf *buf;
					val->Get(&buf);
					CFile f;
					CString tmp; tmp.GetEnvironmentVariable(_T("temp"));
					tmp+=_T("\\picture.png");
					if(f.Open(tmp,CFile::modeCreate|CFile::modeWrite))
					{
						f.Write(buf->GetBuffer(),buf->m_Size);
						f.Close();
					}
					((CPictureElement*)elem)->m_mode = DM_FIT_TO_RECT;
					((CPictureElement*)elem)->LoadPicture(tmp);
					CFile::Remove(tmp);

					CPictureElement *pict_el=(CPictureElement*)elem;
					CSize sz0= pict_el->m_size; // размер поля в шаблоне 
					int img_cx=0,img_cy=0;
					GetCPictureElementProportionalSize(pict_el,sz0.cx,img_cx,img_cy);
					elem->m_size.cy=img_cy;
					elem->m_size.cx=img_cx;
				}

				dx+=col->m_width;
				(*table)->m_owner_sheet->Add(elem);
				str_array_ind++;
			}
		}
	}
	for(int m=0; m<m_strings.GetSize();m++)
		delete m_strings.GetAt(m);
	m_strings.RemoveAll();
	delete []empty;

 	if(bIncrDR)
 		m_CurentDrawRow++;

	return 0;
}

int CReportSection::AddTitle(CReportElement *table, int &row, int &y_pos, UINT flag)
{
	if(_pPrinterDC==NULL) throw(CString(APL_T("Принтер не задан или невозможно создать контекст принтера. Генерация отчета невозможна!")));
	if(m_levels.GetSize()==0) return -1;
	CTableElement* tb = NULL;
	if(table->GetType()==E_TABLE)
		tb = (CTableElement*)table;
	else if(table->GetType()==E_TABLE_MAP)
		tb = ((CTableMapElement*)table)->m_table;
	else return 1;

	// Лобанов по вопросу ILS 36582
	// Когда в секции не задан заголовочный столбец кодом ниже добавляются в таблицу
	// пустые строки по количеству равному количеству столбцов в секции, что само уже
	// странно - как из количества столбцов может получиться количество строк
	// В этом сложно разобраться, но сделал прием который есть в функции GenSection - 
	// при отсутствии заданного заголовка он просто не рисуется
	if (m_title.GetText().IsEmpty() || (m_title_column == NULL))
	{
		return 1;
	}

	//Область таблицы
	CRect rect;
	table->GetRect(rect,1,1);
	rect.NormalizeRect();
	//Проверка сколько строк нужно чтобы вывести данную строку;
	CArray<CStringArray*, CStringArray*> m_strings;
	//контекст устройства
	int mm = _pPrinterDC->SetMapMode(MM_LOMETRIC);
	CFont font;
	font.CreatePointFontIndirect(&tb->m_row_lf, _pPrinterDC);
	CFont *old = _pPrinterDC->SelectObject(&font);
	int max_row = 0;
	int max_ = 0;
	CUIntArray rows_array;
	int lev_cnt = m_levels.GetSize();
	BOOL *empty = new BOOL[lev_cnt];
	CString str;
	CColumn* col;

	int tmp_y_pos = y_pos;
	int r;

	for(r=0; r<lev_cnt;r++)
	{
		empty[r] = TRUE;
		max_ = 0;
		CSectionLevel* lev = m_levels.GetAt(r);
		if(lev->m_height==0)
			lev->m_height = tb->m_row_height*10;
		for(int i=0; i<lev->m_columns.GetSize();i++)
		{
			str.Empty();
			col = lev->m_columns.GetAt(i);
			if(flag&AT_SHOW_TEXT && col==m_title_column)
				str = m_title.GetText();

			if(!str.IsEmpty())
				empty[r] = FALSE;
			//Берем значение из ист. данных и преобразуем его к строке
			//разбиваем строку если необходимо
			CStringArray *strs = new CStringArray;
			strs->SetSize(0);
			int cnt = CTextValue::BreakString(strs,col->m_width-60-col->m_border, _pPrinterDC, str);
			if(cnt<=0)
				strs->Add(str);
			m_strings.Add(strs); //Добавили в массив строк для отображения
			max_ = max_>strs->GetSize() ? max_ : strs->GetSize();
		}
		if(!(empty[r] && lev->m_flag&APL_SEC_LEVEL_SKIP_IF_EMPTY && flag!=0))
			tmp_y_pos-=lev->m_height*max_;
		if(tmp_y_pos<rect.top-rect.bottom && !(empty[r]==TRUE && lev->m_flag&APL_SEC_LEVEL_SKIP_IF_EMPTY && flag!=0))
		{
			CStringArray* strarr;
			for(int m=0; m<m_strings.GetSize();m++)
			{
				strarr = m_strings.GetAt(m);
				DELETE_OBJECT(strarr);
			}
			m_strings.RemoveAll();
			DELETE_OBJECT([]empty);
			return -1;//Не влезает на страницу
		}
		max_row+=max_;
		rows_array.Add(max_);
	}
	_pPrinterDC->SelectObject(old);
	_pPrinterDC->SetMapMode(mm);
	int str_array_ind = 0;
	if(flag&AT_TEST) 
	{
		y_pos = tmp_y_pos;			
		CStringArray* strarr;
		for(int m=0; m<m_strings.GetSize();m++)
		{
			strarr = m_strings.GetAt(m);
			DELETE_OBJECT(strarr);
		}
		m_strings.RemoveAll();
		delete []empty;
		return 0;
	}
	bool bDraw = false;
	for(r=0; r<lev_cnt;r++)
	{
		CSectionLevel* lev = m_levels.GetAt(r);
		//Цикл для отображения всех строк.
		if(empty[r] && lev->m_flag&APL_SEC_LEVEL_SKIP_IF_EMPTY && flag!=0) continue;
		max_=rows_array.GetAt(r);
		int start_ind = str_array_ind;
		for(int i=0; i<max_;i++)
		{
			str_array_ind = start_ind;
			int dx=0;
			y_pos-=lev->m_height;
			for(int j=0; j<lev->m_columns.GetSize();j++)
			{
				bDraw = true;
				CRectReportElement* elem = new CRectReportElement(m_ReportMgr);//elem->m_type = E_RECT;
				elem->m_org_pt.x = rect.left+dx;
				elem->m_org_pt.y = rect.bottom+y_pos;
				CColumn* col_L = m_levels.GetAt(r)->m_columns.GetAt(j);
				elem->m_size = CSize(col_L->m_width,lev->m_height);
				elem->m_value.SetText(_T(""));
				if(str_array_ind<m_strings.GetSize())
				{
					CStringArray *strs = m_strings.GetAt(str_array_ind);
					if(strs->GetSize()>i)
						elem->m_value.SetText(strs->GetAt(i));
				}
				elem->m_value.m_font = m_title.m_font;
				elem->m_value.m_align = AT_VCENTER|AT_CENTER;
				elem->m_value.m_text_params = col_L->m_fit_to_rect;
				elem->m_line_width = col_L->m_border;
				elem->m_value.m_space_para = col_L->m_SpacePara;
				dx+=col_L->m_width;
				table->m_owner_sheet->Add(elem);
				str_array_ind++;
			}
			row++;
		}
	}
	CStringArray* strarr;
	for(int m=0; m<m_strings.GetSize();m++)
	{
		strarr = m_strings.GetAt(m);
		DELETE_OBJECT(strarr);
	}
	m_strings.RemoveAll();
	delete []empty;
	if(bDraw)
		return 0;
	else
		return -1;
}

CReportElement* CReportSection::GetNextSheet(CReportSheet *current_sheet, CReportElement* table)
{
	//Следующая страница
	CTableElement* tb = NULL;
	if(table->GetType()==E_TABLE_MAP)
		tb = ((CTableMapElement*)table)->m_table;
	else
		tb = (CTableElement*)table;
	tb->m_cur_page++;
	TRACE(APL_T("Смена страницы\n"));
	int ind = -1;
	int m;
	for(m=0; m<m_ReportMgr->m_sheets.GetSize();m++)
		if(m_ReportMgr->m_sheets.GetAt(m)==current_sheet)
		{
			ind=m+1;
			break;
		}
	CReportSheet* sheet=NULL;
	if(ind>-1 && ind<m_ReportMgr->m_sheets.GetSize())
	{
		sheet = m_ReportMgr->m_sheets.GetAt(ind);
	}
	else
	{
		sheet = m_ReportMgr->CloneSheet(m_ReportMgr->m_dot_sheet);
		sheet->LoadElementsFromFile();
	}
	if(sheet==NULL)
	{
		AfxMessageBox(APL_T("Не могу создать страницу."));
		return NULL;
	}
	//поиск продолжения таблицы
	bool ok=false;
	for(m=0;m<sheet->m_els.GetSize();m++)
	{
		if(sheet->m_els[m]->GetType()==E_TABLE_MAP)
		{
			CTableMapElement* tme = (CTableMapElement*)sheet->m_els[m];
			CTableElement* tb_l = NULL;
			if(table->GetType()==E_TABLE_MAP)
				tb_l = ((CTableMapElement*)table)->m_table;
			else if(table->GetType()==E_TABLE)
				tb_l = (CTableElement*)table;
			if(tme->m_table==tb_l)
			{
				table = tme;
				ok = true;
				break;
			}
		}
	}
	if(!ok)
	{
		ind = m_ReportMgr->FindSheetInd(current_sheet);
		sheet = m_ReportMgr->CloneSheet(m_ReportMgr->m_dot_sheet, ind+1);
		sheet->LoadElementsFromFile();
		ok=false;
		for(m=0;m<sheet->m_els.GetSize();m++)
		{
			if(sheet->m_els[m]->GetType()==E_TABLE_MAP)
			{
				CTableMapElement* tme = (CTableMapElement*)sheet->m_els[m];
				CTableElement* tb_l = NULL;
				if(table->GetType()==E_TABLE_MAP)
					tb_l = ((CTableMapElement*)table)->m_table;
				else if(table->GetType()==E_TABLE)
					tb_l = (CTableElement*)table;
				if(tme->m_table==tb_l)
				{
					table = tme;
					ok = true;
					break;
				}
			}
		}
		if(!ok)
		{
			CString buf;
			buf.Format(APL_T("Не корректный шаблон:\nНе удалось создать продолжение таблицы (%s)."), table->m_name);
			AfxMessageBox(buf);
			return NULL;
		}
	}
	tb->cur_sheet = sheet;
	if(m_CurTableContent)
		m_CurTableContent->AddSheet(sheet);

	return table;
}

int CReportSection::GetMemSize()
{
	int size = 0;
	int int_size = sizeof(int);
	size+=int_size;//длина текста;
	size+=m_name.GetLength();//строка;
	size+=int_size;//длина m_levels;
	size+=m_levels.GetMemSize();//размер уровней и колонок.
	size+=m_title.GetMemSize();
	//условия надо накладывать новые нановом месте.
	return size;		
}

int CSectionLevelArray::GetMemSize()
{
	int size = 0;
	for(int i=0; i<m_Data.GetSize();i++)
		size+=m_Data.GetAt(i)->GetMemSize();
	return size;
}

void CSectionLevelArray::CopyToMem(BYTE *pByte, int &ind)
{
	for(int i=0; i<m_Data.GetSize();i++)
		m_Data.GetAt(i)->CopyToMem(pByte,ind);
}

void CReportSection::CopyToMem(BYTE *pByte, int &ind)
{
	int int_size =sizeof(int);
	int* pInt = NULL;
	DWORD* pDw = NULL;
	TCHAR* pCh = NULL;

	pInt = (int*)&pByte[ind];//запись наименования
	*pInt = m_name.GetLength();
	ind+=int_size;
	for(int i=0; i<m_name.GetLength();i++)
	{
		pCh = (TCHAR*)&pByte[ind];
		*pCh = m_name[i];
		ind+=sizeof(TCHAR);
	}
	m_title.CopyToMem(pByte, ind);

	pInt = (int*)&pByte[ind];//запись level.size
	*pInt = m_levels.GetSize();
	ind+=int_size;

	m_levels.CopyToMem(pByte, ind);
}

bool CReportSection::LoadDataFromMem(BYTE *pByte, int &ind)
{
	int i;
	int int_size =sizeof(int);
	int* pInt = NULL;
	DWORD* pDw = NULL;
	TCHAR* pCh = NULL;

	pInt = (int*)&pByte[ind];//запись наименования
	int cnt = *pInt;
	ind+=int_size;
	m_name.Empty();
	for(i=0; i<cnt;i++)
	{
		pCh = (TCHAR*)&pByte[ind];
		m_name+=*pCh;
		ind+=sizeof(TCHAR);
	}
	m_title.LoadDataFromMem(pByte, ind);

	pInt = (int*)&pByte[ind];
	cnt = *pInt;
	ind+=int_size;

	m_levels.RemoveAll();
	for(i=0; i<cnt;i++)
	{
		CSectionLevel* level = new CSectionLevel(m_ReportMgr);
		m_levels.Add(level);
	}
	m_levels.LoadDataFromMem(pByte, ind);
	return true;
}

bool CSectionLevelArray::LoadDataFromMem(BYTE *pByte, int &ind)
{
	for(int i=0; i<m_Data.GetSize();i++)
		m_Data.GetAt(i)->LoadDataFromMem(pByte,ind);
	return true;
}

void CReportSection::DeleteSection()
{
	if(m_inst!=0)	
		m_ReportMgr->m_data->DeleteInstance(m_inst);
	int cnt = m_levels.GetSize();
	int i;
	for(i=0; i<cnt;i++)
	{
		m_levels.GetAt(i)->Delete();
	}
	m_levels.RemoveAll();
	cnt = m_conditions.GetSize();
	m_title.Delete(m_ReportMgr);
	for(i=0; i<cnt;i++)
	{
		if(m_conditions.GetAt(i)->m_inst!=0)
			m_ReportMgr->m_data->DeleteInstance(m_conditions.GetAt(i)->m_inst);
	}
	m_conditions.RemoveAll();
	cnt = m_groups.GetSize();
	for(i=0; i<cnt; i++)
	{
		CGroupCol* gc = m_groups.GetAt(i);
		if(gc->m_inst==NULL) continue;
		CaplInstance* font_inst;
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_apl_gr_font, font_inst);
		m_ReportMgr->m_data->DeleteInstance(gc->m_inst);
		m_ReportMgr->m_data->DeleteInstance(font_inst);
	}
}

void CReportSection::Delete()
{
	//Удаление условий.
	int cnt = m_conditions.GetSize();
	int i;
	for(i=0; i<cnt; i++)
	{
		CCondition* cond = m_conditions.GetAt(i);
		if(cond==0) continue;
		cond->Delete(m_ReportMgr);
	}
	//Удаление уровней
	cnt = m_levels.GetSize();
	for(i=0; i<cnt; i++)
	{
		CSectionLevel* level = m_levels.GetAt(i);
		if(level==0) continue;
		level->Delete();
	}
	//Удаление групп
	cnt = m_groups.GetSize();
	for(i=0; i<cnt; i++)
	{
		CGroupCol* group = m_groups.GetAt(i);
		if(group==0) continue;
		group->Delete();
	}
}

CSectionLevelArray::CSectionLevelArray()
{
	m_Data.RemoveAll();
}

CSectionLevelArray::~CSectionLevelArray()
{
	RemoveAll();
}

CSectionLevelArray& CSectionLevelArray::operator = (CSectionLevelArray& SLA)
{
	RemoveAll();
	int cnt = SLA.GetSize();
	if(cnt==0) return *this;
	CaplReportMgr* Mgr = SLA.GetAt(0)->m_ReportMgr;
	for(int i=0; i<cnt; i++)
	{
		CSectionLevel* nLevel = new CSectionLevel(Mgr);
		CSectionLevel* Level = SLA.GetAt(i);
		*nLevel = *Level;
		m_Data.Add(nLevel);
	}
	return *this;
}

CSectionArray::CSectionArray()
{
	m_Data.RemoveAll();
}

CSectionArray::~CSectionArray()
{
	RemoveAll();
}

int CSectionArray::Add(CReportSection* nSec)
{
	if(nSec==0) return -1;
	return m_Data.Add(nSec);
}

void CSectionArray::RemoveAll()
{
	int cnt = m_Data.GetSize();
	for(int i=0; i<cnt; i++)
		delete m_Data[i];
	m_Data.RemoveAll();
}

int CSectionArray::GetSize()
{
	return m_Data.GetSize();
}

CReportSection* CSectionArray::GetAt(int i)
{
	if(i<0) return NULL;
	if(i>m_Data.GetSize()) return NULL;
	return m_Data.GetAt(i);
}

void CSectionArray::RemoveAt(int i)
{
	if(i<0) return;
	if(i>m_Data.GetSize()) return;
	CReportSection* sec = m_Data.GetAt(i);
	delete sec;
	m_Data.RemoveAt(i);
}

void CReportSection::ZerroInsts()
{
	m_inst = NULL;
	int i;
	for(i=0; i<m_levels.GetSize();i++)
	{
		m_levels.GetAt(i)->m_inst = NULL;
		for(int j=0; j<m_levels.GetAt(i)->m_columns.GetSize();j++)
			m_levels.GetAt(i)->m_columns.GetAt(j)->m_inst = NULL;
	}
	//Условия
	for(i=0; i<m_conditions.GetSize();i++)
		m_conditions.GetAt(i)->m_inst = NULL;
	//Группы и сортировка
	for(i=0; i<m_groups.GetSize();i++)
	{
		CGroupCol* et = m_groups.GetAt(i);
		et->m_inst = NULL;
		//Уровни
		for(int r=0; r<et->m_row.GetSize();r++)
		{
			et->m_row.GetAt(r)->m_inst = NULL;
			for(int j=0; j<et->m_row.GetAt(r)->m_columns.GetSize();j++)
			{
				CColumn* old_col = et->m_row.GetAt(r)->m_columns.GetAt(j);
				old_col->m_inst = NULL;
			}
		}
		//Условия
		int count = et->m_conditions.GetSize();
		for(int j=0; j<count;j++)
		{
			CCondition* Cond = et->m_conditions.GetAt(j);
			Cond->m_inst = NULL;
		}
	}
}

void CSectionArray::Replace(CReportSection* sec, int delta)
{
	if(sec==0) return;
	int ind = -1;
	for(int i=0; i<m_Data.GetSize(); i++)
	{
		if(m_Data[i]==sec)
		{
			ind = i;
			break;
		}
	}
	if(ind<0)
		return;
	if(ind+delta>-1 && ind+delta<m_Data.GetSize())
	{
		CReportSection* sec1 = m_Data[ind];
		CReportSection* sec2 = m_Data[ind+delta];
		m_Data.SetAt(ind, sec2);
		m_Data.SetAt(ind+delta, sec1);
	}
}

void CSectionArray::Replace(int oPos, int nPos)
{
	if(oPos<0 || oPos>=m_Data.GetSize() || nPos<0 || nPos>=m_Data.GetSize())
		return;
	CReportSection* sec1 = m_Data[oPos];
	CReportSection* sec2 = m_Data[nPos];
	m_Data.SetAt(oPos, sec2);
	m_Data.SetAt(nPos, sec1);
}

void CSectionLevelArray::Delete()
{
	int cnt = m_Data.GetSize();
	for(int i=0; i<cnt; i++)
	{
		CSectionLevel* level = m_Data.GetAt(i);
		level->Delete();
		DELETE_OBJECT(level);
	}
	m_Data.RemoveAll();
}

