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

CDiagramElement::CDiagramElement(CaplReportMgr* ReportMgr):CReportElement(ReportMgr, E_DIAGRAM), m_XLine(ReportMgr), m_YLine(ReportMgr), m_Legend(ReportMgr), m_DataSource(NULL, ReportMgr)
{
	m_name = APL_T("График");

	m_pGroupColumn = NULL;

	m_XLine.m_name = _T("X");
	m_YLine.m_name = _T("Y");
	m_YLine.m_bCalcFromZero = true;

	m_background_color = RGB(220, 220, 220);

	m_dXMin = 0;
	m_dXMax = 0;
	m_dYMin = 0;
	m_dYMax = 0;
	m_dXRange = 0;
	m_dYRange = 0;

	m_XIndex = 0;

	m_SortDirection = aplAZ;
}

CDiagramElement::~CDiagramElement()
{
}

BOOL CDiagramElement::Draw(CDC* pDC, double scale, int draw_mode, UINT flag /* = DRAW_SEL|DRAW_PICTURE|DRAW_TEXT */)
{
	CRgn rgn1, rgn2;
	HRGN OldRgn = CreateRectRgn(0,0,1,1);
	int res = GetClipRgn(pDC->m_hDC, OldRgn);
	ASSERT(res>-1);
	CRect rect;
	CRect RgnRect;
	GetRect(rect, scale, pDC->IsPrinting());
	RgnRect = rect;
	RgnRect.NormalizeRect();
	RgnRect.DeflateRect(-m_line_width, -m_line_width);
	ConvertLOMETRICtoTEXT(pDC, RgnRect);
	rgn1.CreateRectRgnIndirect(RgnRect);
	if(res==1)
	{
		rgn2.Attach(OldRgn);
		rgn1.CombineRgn(&rgn1, &rgn2, RGN_AND);
		rgn2.Detach();
	}
	int Result = -1;

	int rows, cols;
	m_DataSource.GetSize(rows, cols);

	if(draw_mode==0 && rows<2 || cols==0)//Значит это режим редактирования
	{
		CPoint pt[6];
		CPen obj_pen, *old_pen;
		CPen red_pen, green_pen;

		obj_pen.CreatePen(PS_SOLID | PS_GEOMETRIC, (int)((double)m_line_width*scale), m_color);
		red_pen.CreatePen(PS_SOLID | PS_GEOMETRIC, (int)((double)m_line_width*scale), RGB(200, 0, 0));
		green_pen.CreatePen(PS_SOLID | PS_GEOMETRIC, (int)((double)m_line_width*scale), RGB(0, 200, 0));
		old_pen = pDC->SelectObject(&obj_pen);
		
		DrawRect(pDC, rect);

		Result = pDC->SelectClipRgn(&rgn1);
		if(m_select && !pDC->IsPrinting() && flag&DRAW_SEL) 
			DrawSelPoints(pDC, scale); // отрисовка рамки выделения

		//рисуем подобие графика
		rect.DeflateRect(m_line_width, m_line_width);
		pt[0].x = rect.left;
		pt[0].y = rect.bottom-(int)(rect.Height()*0.6);
		pt[1].x = rect.left+(int)(rect.Width()*0.15);
		pt[1].y = rect.bottom-(int)(rect.Height()*0.75);
		pt[2].x = rect.left+(int)(rect.Width()*0.4);
		pt[2].y = rect.bottom-(int)(rect.Height()*0.45);
		pt[3].x = rect.left+(int)(rect.Width()*0.5);
		pt[3].y = rect.bottom-(int)(rect.Height()*0.5);
		pt[4].x = rect.left+(int)(rect.Width()*0.75);
		pt[4].y = rect.bottom-(int)(rect.Height()*0.95);
		pt[5].x = rect.right;
		pt[5].y = rect.bottom-(int)(rect.Height()*0.2);

		pDC->SelectObject(&red_pen);
		pDC->Polyline(&pt[0], 6);

		pt[0].x = rect.left;
		pt[0].y = rect.bottom-(int)(rect.Height()*0.7);
		pt[1].x = rect.left+(int)(rect.Width()*0.2);
		pt[1].y = rect.bottom-(int)(rect.Height()*0.5);
		pt[2].x = rect.left+(int)(rect.Width()*0.35);
		pt[2].y = rect.bottom-(int)(rect.Height()*0.9);
		pt[3].x = rect.left+(int)(rect.Width()*0.6);
		pt[3].y = rect.bottom-(int)(rect.Height()*0.4);
		pt[4].x = rect.left+(int)(rect.Width()*0.85);
		pt[4].y = rect.bottom-(int)(rect.Height()*0.8);
		pt[5].x = rect.right;
		pt[5].y = rect.bottom-(int)(rect.Height()*0.9);
		
		pDC->SelectObject(&green_pen);
		pDC->Polyline(&pt[0], 6);
		
		pDC->SelectObject(old_pen);
	}
	else
	{
		int i;
		int iDI;
		int ind;

		int x, y;

		double dVal;
		CString sVal;
		CPen obj_pen, *old_pen;
		
		GetRect(rect, scale, pDC->IsPrinting());
		
		if(m_line_width!=0)
			obj_pen.CreatePen(PS_SOLID|PS_GEOMETRIC, (int)((double)m_line_width*scale), m_color);
		else if(draw_mode==0)
			obj_pen.CreatePen(PS_SOLID|PS_GEOMETRIC, (int)1, RGB(192,192,192));
		old_pen = pDC->SelectObject(&obj_pen);

		if(draw_mode==0 || m_line_width>0)
			DrawRect(pDC, rect);
		if(m_select && !pDC->IsPrinting() && flag&DRAW_SEL && draw_mode==0) 
			DrawSelPoints(pDC, scale); // отрисовка рамки выделения

		Result = pDC->SelectClipRgn(&rgn1);
		//Отрисовываем графики
		//пропорционально
		if(rows>1 && m_Elements.GetSize()>0)
		{
			//Легенда
			DrawLegeng(pDC, rect);
			//отрисовка
			int defl;
			defl = (int)(rect.Width()>-rect.Height()?-rect.Height()*0.03:rect.Width()*0.03);
			defl = defl>50?50:defl;

			rect.DeflateRect(defl/2, -defl/2);
			m_background_color = RGB(255, 255, 255);
			pDC->FillSolidRect(rect, m_background_color);
			rect.DeflateRect(defl/2, -defl/2);

			m_XLine.OffsetDrawRect(pDC, rect, scale, &m_DataSource, m_dXMin, m_dXRange);
			m_YLine.OffsetDrawRect(pDC, rect, scale, &m_DataSource, m_dYMin, m_dYRange);
			
			m_XLine.Draw(pDC, rect, scale, &m_DataSource, m_dXMin, m_dXRange);
			m_YLine.Draw(pDC, rect, scale, &m_DataSource, m_dYMin, m_dYRange);

			CString sTmpVal;
			CPen pen, *old;
			for(iDI=0; iDI<m_Elements.GetSize(); iDI++)
			{
				ind = m_DataSource.GetHeader()->Find(m_Elements[iDI]->GetColumnName());
				if(ind<0) continue;
				
				int start_ind=0;
				do 
				{
					m_DataSource.GetAt(start_ind++, ind, sTmpVal);
				}while(sTmpVal.IsEmpty() && start_ind<rows);
				start_ind--;
				do 
				{
					m_DataSource.GetAt(start_ind++, m_XIndex, sTmpVal);
				}while(sTmpVal.IsEmpty() && start_ind<rows);

				if(start_ind>=rows) continue;

				start_ind--;

				pen.CreatePen(PS_SOLID, (int)(m_Elements[iDI]->m_line_width*scale), m_Elements[iDI]->m_color);
				old = pDC->SelectObject(&pen);

				m_DataSource.GetAt(start_ind, m_XIndex, dVal);
				if(m_XLine.m_bProRata)
					x = rect.left+(int)(i*(double)(rect.Width())/(rows-1));
				else
					x = rect.left+(int)((dVal-m_dXMin)*(double)(rect.Width())/m_dXRange);

				m_DataSource.GetAt(start_ind, ind, dVal);
				y = rect.bottom-(int)((dVal-m_dYMin)*(double)(rect.Height())/m_dYRange);
				pDC->MoveTo(x, y);

				for(i=start_ind; i<rows; i++)
				{
					m_DataSource.GetAt(i, m_XIndex, sTmpVal);
					if(sTmpVal.IsEmpty()) continue;
					dVal = __atof(sTmpVal);

					if(m_XLine.m_bProRata)
						x = rect.left+(int)(i*(double)(rect.Width())/(rows-1));
					else
						x = rect.left+(int)((dVal-m_dXMin)*(double)(rect.Width())/m_dXRange);
					m_DataSource.GetAt(i, ind, sTmpVal);
					if(sTmpVal.IsEmpty()) continue;
					dVal = __atof(sTmpVal);

					y = rect.bottom-(int)((dVal-m_dYMin)*(double)(rect.Height())/m_dYRange);
					pDC->LineTo(x, y);
				}
				pDC->SelectObject(old);
				pen.DeleteObject();
			}
		}
		pDC->SelectObject(old_pen);
	}
	
	rgn1.DeleteObject();
	rgn1.Attach(OldRgn);
	if(res==1)
		pDC->SelectClipRgn(&rgn1);
	else
		pDC->SelectClipRgn(NULL);
	rgn1.DeleteObject();

	return TRUE;
}

void CDiagramElement::Update(bool set /* = true */)
{
	if(set) //storing
	{
		int i;
		aplExtent ext;

		m_XLine.Update(true);
		m_YLine.Update(true);

		if(m_inst==NULL)
			m_inst = m_ReportMgr->m_data->CreateInstance(m_ReportMgr->e_apl_diagram_element);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_elem_name,m_name);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_elem_line_width,m_line_width);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_elem_fixed,m_fixed);

		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_diagram_element_xline, m_XLine.m_inst);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_diagram_element_yline, m_YLine.m_inst);

		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_elem_textcolor, (int)m_color);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_elem_backgroundcolor, (int)m_background_color);
		
		m_ReportMgr->PutPoint(m_inst,m_ReportMgr->a_elem_org_pt, m_org_pt);
		m_ReportMgr->PutPoint(m_inst,m_ReportMgr->a_elem_size, m_size);

		m_Legend.Update(set);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_diagram_element_legend, m_Legend.m_inst);
		if(m_pGroupColumn)
		{
			if(m_pGroupColumn->m_inst==NULL)
			{
				m_ReportMgr->m_base_query->Update(true);
				m_ReportMgr->m_header->Update(true);
			}
			m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_diagram_element_group_column, m_pGroupColumn->m_inst);
		}
		else
			m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_diagram_element_group_column, (CaplInstance*)NULL);

		for(i=0; i<m_Elements.GetSize(); i++)
		{
			m_Elements[i]->Update(true);
			ext.Add(m_Elements[i]->m_inst);
		}
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_diagram_element_elements, ext);
		m_DataSource.Update(true);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_diagram_element_data_source, m_DataSource.m_inst);
	}
	else
	{
		if(m_inst==0) return;
		
		int tmpInt;
		int i;
		aplExtent ext;
		CaplInstance *Inst;
		CDiagramItem* pItem;

		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_elem_name,m_name);
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_elem_line_width,m_line_width);
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_elem_fixed,m_fixed);
		
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_elem_textcolor, tmpInt);
		m_color = (COLORREF)tmpInt;
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_elem_backgroundcolor, tmpInt);
		m_background_color= (COLORREF)tmpInt;
		
		m_ReportMgr->GetPoint(m_inst,m_ReportMgr->a_elem_org_pt,m_org_pt);
		m_ReportMgr->GetPoint(m_inst,m_ReportMgr->a_elem_size,m_size);
		
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_diagram_element_legend, m_Legend.m_inst);
		m_Legend.Update(set);
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_diagram_element_group_column, Inst);
		if(Inst)
		{
			m_pGroupColumn = m_ReportMgr->FindColumnByInst(Inst);
			if(m_pGroupColumn==NULL)
					TRACE_TO_FILE(APL_T("Не удалось восстановить ссылку на поле иcточника данных!"));
		}
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_diagram_element_elements, ext);
		m_Elements.Clear();
		for(i=0; i<ext.GetSize(); i++)
		{
			pItem = new CDiagramItem(m_ReportMgr);
			pItem->m_inst = ext[i];
			pItem->Update(false);
			m_Elements.Add(pItem);
		}

		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_diagram_element_xline, m_XLine.m_inst);
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_diagram_element_yline, m_YLine.m_inst);

		m_XLine.Update(set);
		m_YLine.Update(set);

		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_diagram_element_data_source, m_DataSource.m_inst);
		if(m_DataSource.m_inst)
		{
			m_DataSource.Update(false);
			m_DataSource.Sort(m_XLine.m_pDSColumn, false, m_SortDirection);
			
			RecalcLayout();
		}
	}
}

bool CDiagramElement::LoadDataFromMem(BYTE *pByte, int &ind)
{
	int* pInt = NULL;
	int int_size = sizeof(int);
	TCHAR* pCh = NULL;
	
	pInt = (int*)&pByte[ind];
	m_org_pt.x = *pInt;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	m_org_pt.y = *pInt;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	m_size.cx = *pInt;//прочитал cx;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	m_size.cy = *pInt;//прочитал cy;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	m_line_width = *pInt;//прочитал толщину линии;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	int cnt = *pInt;
	ind+=int_size;
	m_name.Empty();
	for(int i=0; i<cnt;i++)
	{
		pCh = (TCHAR*)&pByte[ind];
		m_name+=*pCh;
		ind+=sizeof(TCHAR);
	}

	m_Legend.LoadDataFromMem(pByte, ind);

	m_XLine.LoadDataFromMem(pByte, ind);
	m_YLine.LoadDataFromMem(pByte, ind);
	
	return true;
}

void CDiagramElement::CopyToMem(BYTE* pByte, int &ind)
{
	int* pInt = NULL;
	int int_size = sizeof(int);
	TCHAR* pCh = NULL;
	
	pInt = (int*)&pByte[ind];
	*pInt = m_type;//записал тип элемента;
	ind+=sizeof(TReportElementType);
	
	pInt = (int*)&pByte[ind];
	*pInt = m_org_pt.x;//записал x;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	*pInt = m_org_pt.y;//записал y;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	*pInt = m_size.cx;//записал cx;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	*pInt = m_size.cy;//записал cy;
	ind+=int_size;
	
	pInt = (int*)&pByte[ind];
	*pInt = m_line_width;//записал толщину линии;
	ind+=int_size;
	
	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_Legend.CopyToMem(pByte, ind);

	m_XLine.CopyToMem(pByte, ind);
	m_YLine.CopyToMem(pByte, ind);
}

int CDiagramElement::GetMemSize()
{
	int int_size = sizeof(int);
	int size = 4*int_size;//размер элемента;

	size+=sizeof(TReportElementType);//тип элемента;
	size+=int_size;//толщина линии;
	size+=int_size;//наименование;
	size+=m_name.GetLength()*sizeof(TCHAR);

	//совйства легенды
	size+=m_Legend.GetMemSize();
	//свойства осей
	size+=m_XLine.GetMemSize();
	size+=m_YLine.GetMemSize();

	return size;
}

void CDiagramElement::Delete()
{
	if(m_ReportMgr==NULL) return;
	if(m_ReportMgr->m_data==NULL) return;

	if(m_inst==NULL) return;

	CaplInstance *inst;
	m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_elem_org_pt, inst);
	if(inst)
		m_ReportMgr->m_data->DeleteInstance(inst);
	m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_elem_size, inst);
	if(inst)
		m_ReportMgr->m_data->DeleteInstance(inst);

	m_ReportMgr->m_data->DeleteInstance(m_inst);
	m_DataSource.Delete();
	//Items
	for(int i=0; i<m_Elements.GetSize(); i++)
		m_Elements[i]->Delete();
	
	m_XLine.Delete();
	m_YLine.Delete();
	m_Legend.Delete();

	m_Elements.Clear();
}

CDiagramElement& CDiagramElement::operator = (const CDiagramElement& Elem)
{
	int i;
	CDiagramItem* pItem;

	*((CReportElement*)this) = *((CReportElement*)&Elem);
	m_inst = Elem.m_inst;
	m_XLine = Elem.m_XLine;
	m_YLine = Elem.m_YLine;
	m_Legend = Elem.m_Legend;
	m_pGroupColumn = Elem.m_pGroupColumn;
	m_Elements.Clear();
	for(i=0; i<Elem.m_Elements.Size; i++)
	{
		pItem = new CDiagramItem(m_ReportMgr);
		*pItem = *Elem.m_Elements[i];
		m_Elements.Add(pItem);
	}
	
	return *this;
}

bool CDiagramElement::GetLegendNeedSizes(CDC *pDC, CRect rect, CSize &sizes, int &cols)
{
	//если отображение слева или справа, то всегда отображаем в столибик, иначе пытаемся разбить столбцы
	cols = 1;
	sizes = CSize(0, 0);
	if(m_Legend.m_LegendPosition==aplLegendPositionNone) return false;

	int i;
	int max;
	int tmp;
	int elems_size(0);
	CString buf;

	for(i=0; i<m_Elements.GetSize(); i++)
	{
		if(!m_Elements[i]->NeedDraw(&m_DataSource)) continue;
		elems_size++;
	}


	if(m_Legend.m_LegendPosition==aplLegendPositionLeft || m_Legend.m_LegendPosition==aplLegendPositionRight)
	{
		//определяем наиболее широкий элемент
		max = 0;
		for(i=0; i<m_Elements.GetSize(); i++)
		{
			if(!m_Elements[i]->NeedDraw(&m_DataSource)) continue;

			tmp = pDC->GetTextExtent(m_Elements[i]->m_name).cx;
			max = tmp>max?tmp:max;
		}
	
		if(m_Legend.m_LegendMode!=aplLegendMode_3)
			max+=75;
		sizes.cx = max+50;
		sizes.cy = pDC->GetTextExtent(_T("Ag")).cy*m_Elements.GetSize()+pDC->GetTextExtent(_T("Ag")).cy/4*(m_Elements.GetSize()-1)+50;
	}
	else
	{
		int cnt;
		int rows;

		max = 0;
		for(i=0; i<m_Elements.GetSize(); i++)
		{
			if(!m_Elements[i]->NeedDraw(&m_DataSource)) continue;

			tmp = pDC->GetTextExtent(m_Elements[i]->m_name).cx;
			max = tmp>max?tmp:max;
		}
		//Определяем сколько таких уместится в ширину элемента
		cnt = (rect.Width()-15)/(max+15);
		cols = cnt<0?1:elems_size<cnt?elems_size:cnt;

		rows = elems_size/cnt;

		sizes.cx = cols*(max+75)+75;
		sizes.cy = pDC->GetTextExtent(_T("Ag")).cy*rows+pDC->GetTextExtent(_T("Ag")).cy/4*(rows-1)+75;
	}
	return true;
}

bool CDiagramElement::DrawLegeng(CDC *pDC, CRect &rect)
{
	if(m_Legend.m_LegendPosition==aplLegendPositionNone) return false;

	CRect MyRect = rect;
	CSize sizes;
	int i;
	int tmp;
	int h, dH;
	int dXText;
	int cols;
	int oldBkMode;
	CString buf;
	CFont font, *pOld;
	CPen pen, *pOldPen;
	COLORREF OldColor;
	LOGBRUSH lb;
	lb.lbStyle = BS_SOLID;
	lb.lbHatch = 0;
	font.CreatePointFontIndirect(&m_Legend.m_LogFont, pDC);
	pOld = pDC->SelectObject(&font);
	oldBkMode = pDC->SetBkMode(TRANSPARENT);

	GetLegendNeedSizes(pDC, rect, sizes, cols);

	if(m_Legend.m_LegendPosition==aplLegendPositionLeft || m_Legend.m_LegendPosition==aplLegendPositionRight)
	{
		//определяем наиболее широкий элемент
		dH = pDC->GetTextExtent(_T("Ag")).cy/4;
		h = pDC->GetTextExtent(_T("Ag")).cy;

		if(m_Legend.m_LegendPosition==aplLegendPositionLeft)
		{
			rect.right-=sizes.cx;
			MyRect.left = MyRect.right-sizes.cx;
		}
		else
		{
			rect.left+=sizes.cx;
			MyRect.right = MyRect.left+sizes.cx;
		}
		if(m_Legend.m_LegendPosition2==aplLegendPositionLess)
			MyRect.top -= 15;
		else if(m_Legend.m_LegendPosition2==aplLegendPositionMore)
			MyRect.top = MyRect.bottom+sizes.cy;
		else
			MyRect.top = MyRect.bottom-(MyRect.Height()-sizes.cy)/2;
		for(i=0; i<m_Elements.GetSize(); i++)
		{
			if(!m_Elements[i]->NeedDraw(&m_DataSource)) continue;

			dXText = 15;
			if(m_Legend.m_LegendMode==aplLegendMode_1)
			{
				lb.lbColor = m_Elements[i]->m_color;
				pen.CreatePen(PS_SOLID|PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_ROUND, m_Elements[i]->m_line_width, &lb);
				pOldPen = pDC->SelectObject(&pen);

				pDC->MoveTo(MyRect.left+15, MyRect.top-i*(h+dH)-h/2);
				pDC->LineTo(MyRect.left+70, MyRect.top-i*(h+dH)-h/2);

				pDC->SelectObject(pOldPen);
				pen.DeleteObject();

				dXText = 75;
			}
			else if(m_Legend.m_LegendMode==aplLegendMode_2)
			{
				lb.lbColor = m_Elements[i]->m_color;
				pen.CreatePen(PS_SOLID|PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_ROUND, m_Elements[i]->m_line_width, &lb);
				pOldPen = pDC->SelectObject(&pen);
				
				pDC->MoveTo(MyRect.right-15, MyRect.top-i*(h+dH)-h/2);
				pDC->LineTo(MyRect.right-70, MyRect.top-i*(h+dH)-h/2);
				
				pDC->SelectObject(pOldPen);
				pen.DeleteObject();
			}
			else if(m_Legend.m_LegendMode==aplLegendMode_3)
				OldColor = pDC->SetTextColor(m_Elements[i]->m_color);

			pDC->TextOut(MyRect.left+dXText, MyRect.top-i*(h+dH), m_Elements[i]->m_name);

			if(m_Legend.m_LegendMode==aplLegendMode_3)
				pDC->SetTextColor(OldColor);
		}
	}
	else
	{
		int j;
		int ind, max;
		int rows = 0;
		int cnt_l(0);
		for(i=0; i<m_Elements.GetSize(); i++)
		{
			if(!m_Elements[i]->NeedDraw(&m_DataSource)) continue;
			cnt_l++;
		}

		rows = cnt_l/cols;

		dH = pDC->GetTextExtent(_T("Ag")).cy/4;
		h = pDC->GetTextExtent(_T("Ag")).cy;

		if(m_Legend.m_LegendPosition==aplLegendPositionTop)
		{
			rect.top-=sizes.cy;
			MyRect.top-=15;
			MyRect.bottom = rect.top-15;
		}
		else
		{
			rect.bottom+=sizes.cy;
			MyRect.top = rect.bottom+15;
		}
		if(m_Legend.m_LegendPosition2==aplLegendPositionLess)
			MyRect.left += 15;
		else if(m_Legend.m_LegendPosition2==aplLegendPositionMore)
			MyRect.left = MyRect.right-sizes.cx;
		else
			MyRect.left = MyRect.left+(MyRect.Width()-sizes.cx)/2;

		max = 0;
		for(i=0; i<m_Elements.GetSize(); i++)
		{
			if(!m_Elements[i]->NeedDraw(&m_DataSource)) continue;

			tmp = pDC->GetTextExtent(m_Elements[i]->m_name).cx;
			max = tmp>max?tmp:max;
		}

		ind = 0;
		for(i=0; i<cols; i++)
		{
			for(j=0; j<rows; j++, ind++)
			{
				while(!m_Elements[ind]->NeedDraw(&m_DataSource))
				{
					ind++;
				}
				dXText = 15;
				if(m_Legend.m_LegendMode==aplLegendMode_1)
				{
					lb.lbColor = m_Elements[ind]->m_color;
					pen.CreatePen(PS_SOLID|PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_ROUND, m_Elements[ind]->m_line_width, &lb);
					pOldPen = pDC->SelectObject(&pen);
					pDC->MoveTo(MyRect.left+(max+75)*i, MyRect.top-j*(h+dH)-h/2);
					pDC->LineTo(MyRect.left+50+(max+75)*i, MyRect.top-j*(h+dH)-h/2);
					pDC->SelectObject(pOldPen);
					pen.DeleteObject();
					dXText = 50;
					OldColor = pDC->SetTextColor(m_Legend.m_TextColor);
				}
				else if(m_Legend.m_LegendMode==aplLegendMode_2)
				{
					lb.lbColor = m_Elements[ind]->m_color;
					pen.CreatePen(PS_SOLID|PS_GEOMETRIC|PS_ENDCAP_FLAT|PS_JOIN_ROUND, m_Elements[ind]->m_line_width, &lb);
					pOldPen = pDC->SelectObject(&pen);
					pDC->MoveTo(MyRect.left+(max+75)*(i+1), MyRect.top-j*(h+dH)-h/2);
					pDC->LineTo(MyRect.left+(max+75)*(i+1)-50, MyRect.top-j*(h+dH)-h/2);
					pDC->SelectObject(pOldPen);
					pen.DeleteObject();
					OldColor = pDC->SetTextColor(m_Legend.m_TextColor);
				}
				else if(m_Legend.m_LegendMode==aplLegendMode_3)
					OldColor = pDC->SetTextColor(m_Elements[ind]->m_color);
				
				pDC->TextOut(MyRect.left+(max+75)*i+dXText, MyRect.top-j*(h+dH), m_Elements[ind]->m_name);
				
				pDC->SetTextColor(OldColor);
			}
		}
	}
	pDC->SetBkMode(oldBkMode);
	pDC->SelectObject(pOld);
	font.DeleteObject();
	return true;
}

bool CDiagramElement::GenerateDiagram()
{
	//Если указано поле группировки, то сортируем сначала по этому полю, затем формируем расширенный ИД.
	int i;
	int j;
	int rows, cols;
	int ind;
	int row_ind;
	int show_mode;
	int group_ind = -1;
	int elem_ind = -1;
	CaplReportValue *val = NULL, *cur_val = NULL;
	CDiagramItem *pItem;
	CHeader *pHeader = NULL, *pOldHeader;
	CString buf;
	double dVal;
	
	m_DataSource.RemoveAll();
	
	if(m_pGroupColumn)
		m_ReportMgr->m_data_source.Sort(m_pGroupColumn, false, m_SortDirection);
	
	m_ReportMgr->m_data_source.GetSize(rows, cols);
	
	//формируем заголовок
	pHeader = new CHeader;
	for(i=0; i<m_Elements.GetSize(); i++)
	{
		pItem = m_Elements[i];
		if(pItem->m_show_mode==aplShowValue)
			pHeader->AddColumn(m_Elements[i]->m_pDSColumn->GetName(), m_Elements[i]->m_pDSColumn->m_type);
		else if(pItem->m_show_mode==aplShowCount)
			pHeader->AddColumn(m_Elements[i]->m_pDSColumn->GetName()+_T("_Count"), m_Elements[i]->m_pDSColumn->m_type);
		else if(pItem->m_show_mode==aplShowSumm)
			pHeader->AddColumn(m_Elements[i]->m_pDSColumn->GetName()+_T("_Summ"), m_Elements[i]->m_pDSColumn->m_type);
		else if(pItem->m_show_mode==aplShowAverage)
			pHeader->AddColumn(m_Elements[i]->m_pDSColumn->GetName()+_T("_Average"), m_Elements[i]->m_pDSColumn->m_type);
	}
	
	if(pHeader->Find(m_XLine.m_pDSColumn->GetName())<0)
		pHeader->AddColumn(m_XLine.m_pDSColumn->GetName(), m_XLine.m_pDSColumn->m_type);
	
	pOldHeader = m_DataSource.SetHeader(pHeader);
	if(pOldHeader) delete pOldHeader;
	
	if(m_pGroupColumn==NULL)
	{
		for(j=0; j<rows; j++)
			m_DataSource.AddRow();
	}
	else
	{
		val = NULL;
		group_ind = m_ReportMgr->m_data_source.GetHeader()->Find(m_pGroupColumn->GetName());
		for(j=0; j<rows; j++)
		{
			cur_val = m_ReportMgr->m_data_source.GetAt(j, group_ind);
			if(val==NULL || *val!=*cur_val)
			{
				val = cur_val;
				m_DataSource.AddRow();
			}
		}
	}
	
	cols = pHeader->GetSize();

	for(i=0; i<cols; i++)
	{
		buf = pHeader->GetColumn(i)->GetName();
		ind = m_ReportMgr->m_data_source.GetHeader()->Find(buf);
		if(m_pGroupColumn==NULL)
		{
			if(ind<0) continue;
			for(j=0; j<rows; j++)
			{
				buf = m_ReportMgr->m_data_source.GetRow(j)->GetAsString(ind);
				m_DataSource.SetAt(j, i, buf);
			}
		}
		else
		{
			if(ind<0)
			{
				buf.Replace(_T("_Count"), _T(""));
				buf.Replace(_T("_Summ"), _T(""));
				buf.Replace(_T("_Average"), _T(""));
				ind = m_ReportMgr->m_data_source.GetHeader()->Find(buf);
				if(ind<0) continue;
			}

			show_mode = -1;
			elem_ind = -1;
			for(j=0; j<m_Elements.GetSize(); j++)
			{
				pItem = m_Elements[j];
				if(pItem->GetColumnName()==pHeader->GetColumn(i)->GetName())
				{
					elem_ind = j;
					show_mode = m_Elements[j]->m_show_mode;
					break;
				}
			}
			if(show_mode<0)
			{
				if(m_XLine.m_pDSColumn->GetName()==pHeader->GetColumn(i)->GetName())
				{
					show_mode = aplShowValue;
				}
				else
				{
					TRACE_TO_FILE(APL_T("Не удалось определить тип отображаетмого значения!"));
					continue;
				}
			}
			val = NULL;
			row_ind = 0;
			for(j=0; j<rows; j++)
			{
				cur_val = m_ReportMgr->m_data_source.GetAt(j, group_ind);
				if(val==NULL || *val!=*cur_val)
				{
					val = cur_val;
					if(show_mode==aplShowValue)
					{
						buf = m_ReportMgr->m_data_source.GetRow(j)->GetAsString(ind);
						m_DataSource.SetAt(row_ind, i, buf);
					}
					else if(show_mode==aplShowSumm)
					{
						dVal = m_ReportMgr->m_data_source.GetSummInGroup(j, m_pGroupColumn, m_Elements[elem_ind]->m_pDSColumn);
						m_DataSource.SetAt(row_ind, i, dVal);
					}
					else if(show_mode==aplShowAverage)
					{
						dVal = m_ReportMgr->m_data_source.GetAverangeInGroup(j, m_pGroupColumn, m_Elements[elem_ind]->m_pDSColumn);
						m_DataSource.SetAt(row_ind, i, dVal);
					}
					else if(show_mode==aplShowCount)
					{
						dVal = m_ReportMgr->m_data_source.GetCountInGroup(j, m_pGroupColumn, m_Elements[elem_ind]->m_pDSColumn, _T(""));
						m_DataSource.SetAt(row_ind, i, dVal);
					}
					row_ind++;
				}
			}
		}
	}
	
	m_DataSource.Sort(m_XLine.m_pDSColumn, false, m_SortDirection);
//	m_DataSource.SaveToFile(_T("D:\\1.csv"));
	m_DataSource.Update(true);

	CTableContent *pTableContent = new CTableContent(m_ReportMgr);
	pTableContent->m_sheets.Add(m_owner_sheet);
	pTableContent->m_Title = m_name;
	m_ReportMgr->m_TableContents.Add(pTableContent);
	
	return true;
}

bool CDiagramElement::RecalcLayout()
{
	int iDI;
	int i;
	int ind;
	int rows, cols;

	double dVal;

	m_dXRange = 0;
	m_dXMax = m_dXMin = 0;
	m_dYRange = 0;
	m_dYMax = m_dYMin = 0;

	m_XIndex = m_DataSource.GetHeader()->Find(m_XLine.m_pDSColumn->GetName());
	if(m_XIndex<0) return false;
	
	m_DataSource.GetSize(rows, cols);
	if(!m_XLine.m_bProRata)
	{
		m_DataSource.GetAt(0, m_XIndex, m_dXMin);
		m_DataSource.GetAt(rows-1, m_XIndex, m_dXMax);
		
		m_dXRange = m_dXMax-m_dXMin>m_dXRange?m_dXMax-m_dXMin:m_dXRange;
	}
	
	ind = m_DataSource.GetHeader()->Find(m_Elements[0]->GetColumnName());
	m_DataSource.GetAt(0, ind, m_dYMin);
	m_dYMax = m_dYMin;
	for(iDI=0; iDI<m_Elements.GetSize(); iDI++)
	{
		ind = m_DataSource.GetHeader()->Find(m_Elements[iDI]->GetColumnName());
		if(ind<0) continue;
		for(i=0; i<rows; i++)
		{
			m_DataSource.GetAt(i, ind, dVal);
			m_dYMax = dVal>m_dYMax?dVal:m_dYMax;
			m_dYMin = dVal<m_dYMin?dVal:m_dYMin;
		}
	}
	if(m_YLine.m_bCalcFromZero)
		m_dYMin = m_dYMin<0?m_dYMin:0;
	m_dYRange = m_dYMax-m_dYMin>m_dYRange?m_dYMax-m_dYMin:m_dYRange;

	return true;
}