// ReportSheet.cpp: implementation of the CReportSheet class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "ReportDict.h"

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

#define TEST_RECT_SIZE 50

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

CReportSheet::CReportSheet(CaplReportMgr* dict)
{
	m_ReportMgr = dict;
	m_inst  = NULL;

	m_print_offset_rect.SetRect(0,0,0,0);
	m_org_pt = CPoint(0,0);
	m_size = CSize(2100, 2970);
	m_index =-1;
	m_isLoaded = false;

	m_type = 0;
	m_sheet_num = -1;
}

CReportSheet::~CReportSheet()
{
	DeleteItems();

	int cnt = m_els.GetSize();
	for(int i=0; i<cnt; i++)
	{
		CReportElement* elem = m_els.GetAt(i);
		if(elem->GetType()==E_TABLE)
		{
			int t_cnt = m_ReportMgr->m_tables.GetSize();
			for(int t=0; t<t_cnt; t++)
			{
				if(m_ReportMgr->m_tables[t]==elem)
				{
					m_ReportMgr->m_tables.RemoveAt(t);
					break;
				}
			}
		}
		delete elem;
	}
	m_els.RemoveAll();
}

BOOL CReportSheet::Draw(CDC *pDC, double scale)
{
	if(!pDC) return false;
	CRect rect = GetRect(scale);
	CBrush m_bg_brush(BG_COLOR), *old_br;;
	CPen m_border_pen(PS_SOLID | PS_GEOMETRIC,1, ::GetSysColor(COLOR_WINDOWTEXT)), *old_pen;
	old_br = pDC->SelectObject(&m_bg_brush);
	old_pen = pDC->SelectObject(&m_border_pen);
	pDC->Rectangle(rect);
	pDC->SelectObject(old_br);
	pDC->SelectObject(old_pen);
	return true;
}

void CReportSheet::SetRect(CRect & r)
{
	m_org_pt = r.TopLeft();
	m_size = r.Size();
}

bool CReportSheet::UnselectAll()
{
	bool res = false;
	while(m_sel_els.GetSize() > 0)
	{
		if(Select(m_sel_els[0], 0)<0)
			m_sel_els.RemoveAt(0);
		res = true;
	}
	return res;
}

int CReportSheet::Add(CReportElement *elem)
{
	if(elem==0) return -1;
	int cnt = m_els.GetSize();
	int i;
	for(i=0; i<cnt;i++)
	{
		if(m_els[i]==elem) return i;
	}

	elem->m_owner_sheet = this;

	if(elem->GetType()==E_TABLE)
	{
		int cnt_L = m_ReportMgr->m_tables.GetSize();
		bool find = false;
		for(i=0;i<cnt_L;i++)
			if(m_ReportMgr->m_tables.GetAt(i)==elem)
			{
				find = true;
				break;
			}
		if(!find)
			m_ReportMgr->m_tables.Add((CTableElement*)elem);
	}
	
	return m_els.Add(elem);
}

int CReportSheet::Select(CReportElement *elem, int sel)
{
	if(elem==0) return -1;
	if(sel == 1 && elem->m_select>0)
	{
		if(FindElement(&m_sel_els, elem)<0)
			m_sel_els.Add(elem);
		return elem->m_select;
	}

	if(sel == 0 && elem->m_select==0)
	{
		int ind = FindElement(&m_sel_els, elem);
		if(ind>-1)
			m_sel_els.RemoveAt(ind);
		return elem->m_select;
	}

	if(sel == 2)
		sel = elem->m_select>0 ? 0 : 1;

	if(sel)
		m_sel_els.Add(elem);		
	else
	{
		// стираем выделеный элемент
		int ind = FindElement(&m_sel_els,elem);
		if(ind>-1)
		{
			m_sel_els.RemoveAt(ind);
		}
	}	
	elem->m_select = sel;
	return elem->m_select;


}

// pt в логических координатах 
void CReportSheet::TestElem(CPoint pt,RE_Array & out_elems, double scale)
{
	CReportElement * cur_elem = NULL;
	int i;
	bool bOnItem;
	int flag;
	CRect elem_rect;

	for(i=0; i<m_els.GetSize(); i++)
	{
		bOnItem = false;
		cur_elem = m_els[i];
		//если он единственный выделенный, то используем его маску
		if(m_sel_els.GetSize()==1)
		{
			if(m_sel_els[0]==cur_elem)
			{
				if(cur_elem->GetDragMode(pt, flag, scale)!=0)
					bOnItem = true;
			}
		}
		if(cur_elem->GetType()!=E_LINE)
		{
			cur_elem->GetRect(elem_rect, scale);
			elem_rect.NormalizeRect();
			if(elem_rect.PtInRect(pt))
				bOnItem = true;
		}
		else
		{
			cur_elem->GetRect(elem_rect, scale);
			CRect wr = elem_rect;
			elem_rect.NormalizeRect();
			elem_rect.DeflateRect(-10, -10);
			if(elem_rect.PtInRect(pt))
			{
				double dx1, dy1, dx2, dy2;
				dx1 = wr.left - pt.x;
				dy1 = wr.top - pt.y;
				dx2 = wr.right - pt.x;
				dy2 = wr.bottom - pt.y;

				double a = sqrt(dx1*dx1 + dy1*dy1);
				double b = sqrt(dx2*dx2 + dy2*dy2);
				double c = sqrt((double)((wr.right-wr.left)*(wr.right-wr.left)+(wr.bottom-wr.top)*(wr.bottom-wr.top)));
				double d = (a*a+c*c-b*b)/(2*c);
				double h = sqrt(a*a-d*d);
				if(h<=10)
					bOnItem = true;
			}
		}
		if(bOnItem)
			out_elems.InsertAt(0, cur_elem);
	}
}

CRect CReportSheet::GetRect(double scale)
{
	CPoint pt = CPoint(int(m_org_pt.x*scale),int(m_org_pt.y*scale));
	CSize sz = CSize(int(m_size.cx*scale),int(m_size.cy*scale));
	return CRect(pt, sz);
}

void CReportSheet::PtLogToSheet(CPoint &pt)
{
	pt -= CPoint(m_org_pt.x,-m_org_pt.y);
}

void CReportSheet::PtSheetToLog(CPoint &pt)
{
	pt += CPoint(m_org_pt.x,-m_org_pt.y);
}

CReportElement * CReportSheet::CreateReportElem(CPoint pt, CSize sz, TReportElementType type )
{
	CReportElement * elem = NULL;

	switch(type)
	{
		case E_RECT : elem = new CRectReportElement(m_ReportMgr); break;
		case E_LINE : elem = new CLineReportElement(m_ReportMgr); break;
		case E_TABLE : elem = new CTableElement(m_ReportMgr); break;
		case E_TABLE_MAP : elem = new CTableMapElement(m_ReportMgr);break;
		case E_PICTURE : elem = new CPictureElement(m_ReportMgr);break;
		case E_TABLE_CONTENT_TITLE : elem = new CTableContentElement(m_ReportMgr);break;
		case E_REFERENCE_ELEMENT : elem = new CPageReferenceElement(m_ReportMgr);break;
		case E_DIAGRAM : elem = new CDiagramElement(m_ReportMgr);break;
		case E_GISTOGRAM : elem = new CGistogramElement(m_ReportMgr);break;
		default : return NULL;
	}

	elem->m_org_pt = pt;
	elem->m_size = sz;	
	elem->m_owner_sheet = this;

	return elem;
}

// возвращает инстанс группы элементов если тестируемый этемент входит туда
BOOL CReportSheet::SelectByFrame(CPoint pt, CSize sz, double scale)
{
	CRect r(pt,sz), inter;
	r.NormalizeRect();
	r.DeflateRect(-1, -1, -1, -1);
	if(m_els.GetSize()==0) return FALSE;
	int res = FALSE;
	for(int i = 0; i < m_els.GetSize(); i++)
	{
		CRect el_rect;
		m_els[i]->GetRect(el_rect,scale);
		el_rect.DeflateRect(-1,-1);
		el_rect.NormalizeRect();
		if(inter.IntersectRect(r,el_rect)!= 0)
		{
			// есть пересечение
			if(inter == el_rect)
			{
				// элемент входит в рамку выделения
				res = TRUE;
				Select(m_els[i],1);
			}
		}
	}

	return res;
}

void CReportSheet::DeleteElement(CReportElement *elem, bool showDlg)
{
	int i;
	if(elem == NULL) return;
	if(showDlg)
	{
		if(AfxMessageBox(APL_T("Вы действительно желаете удалить выделенный элемент?"),
			MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2)==IDNO) return;
	}
	if(elem->GetType()==E_TABLE)
	{
		CArray<CTableMapElement*, CTableMapElement*> m_table_map;
		CArray<CReportSheet*, CReportSheet*> free_sheets;
		int cnt = m_ReportMgr->m_sheets.GetSize();
		for(i=0; i<cnt;i++)
		{
			CReportSheet* sheet = m_ReportMgr->m_sheets.GetAt(i);
			bool loaded = false;
			if(!sheet->IsLoaded())//Загружаем если не загружено
			{
				loaded = true;
				sheet->LoadElementsFromFile();
			}
			int j, count = sheet->m_els.GetSize();
			for(j=0; j<count;j++)
			{
				if(sheet->m_els[j]->GetType()==E_TABLE_MAP)
				{
					CTableMapElement* tme = (CTableMapElement*)sheet->m_els[j];
					if(tme->m_table==elem)
						m_table_map.Add(tme);
				}
			}
			if(loaded)
				free_sheets.Add(sheet);
		}
		cnt = m_table_map.GetSize();
		if(showDlg && cnt>0)
		{
			if(AfxMessageBox(APL_T("Таблица имеет продолжение на других листах. Удалить таблицу и все ее продолжения?"),
				MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2)==IDNO) return;
		}
		for(i=0; i<cnt;i++)
		{
			CTableMapElement* tme = m_table_map.GetAt(i);
			tme->m_owner_sheet->DeleteElement(tme,false);
		}
		for(i=0; i<free_sheets.GetSize();i++)
			free_sheets.GetAt(i)->FreeElements();
		for(i=0; i<m_ReportMgr->m_tables.GetSize(); i++)
		{
			if(m_ReportMgr->m_tables.GetAt(i)==elem)
				m_ReportMgr->m_tables.RemoveAt(i--);
		}
	}
	int cnt = m_sel_els.GetSize();
	for(i=0; i<cnt;i++)
		if(m_sel_els.GetAt(i)==elem)
		{
			m_sel_els.RemoveAt(i);
			break;
		}
	cnt = m_els.GetSize();
	for(i=0; i<cnt;i++)
	{
		CReportElement* el = m_els.GetAt(i);
		if(el==elem) 
		{
			m_els.RemoveAt(i);
			m_DeletedItems.Add(elem);
			break;
		}
	}
}



CReportElement* CReportSheet::TestMoveRect(CReportElement *t_elem, CRect rect, CPoint &pt, UINT &flag)
{
	int stick_size = AfxGetApp()->GetProfileInt(_T("DefaultSettings"), _T("StickSize"), 5)*10;
	CReportElement *elem = NULL;
	CPoint tl_pt, tr_pt, bl_pt, br_pt;
	CRect test;
	int tmp;
	rect.NormalizeRect();
	tmp = rect.top;
	rect.top = rect.bottom;
	rect.bottom = tmp;
	tl_pt = rect.TopLeft();
	br_pt = rect.BottomRight();
	tr_pt = CPoint(br_pt.x,tl_pt.y);
	bl_pt = CPoint(tl_pt.x,br_pt.y);
	pt = CPoint(0,0);
	for(int i=0; i<m_els.GetSize();i++)
	{
		elem = m_els.GetAt(i);
		if(elem==NULL)
			continue;
		if(elem == t_elem) continue;
		test = elem->GetBottomRect(stick_size);
		if(test.PtInRect(tl_pt) || test.PtInRect(tr_pt))
		{
			pt.y = tl_pt.y - test.bottom+test.Height()/2;
			flag = STICK_BOTTOM;
			return elem;
		}
		test = elem->GetTopRect(stick_size);
		if(test.PtInRect(bl_pt) || test.PtInRect(br_pt))
		{
			pt.y = bl_pt.y - test.bottom+test.Height()/2;
			flag = STICK_TOP;
			return elem;
		}
		test = elem->GetLeftRect(stick_size);
		if(test.PtInRect(tr_pt) || test.PtInRect(br_pt))
		{
			pt.x = tr_pt.x - test.left-test.Width()/2;
			flag = STICK_LEFT;
			return elem;
		}
		test = elem->GetRightRect(stick_size);
		if(test.PtInRect(tl_pt) || test.PtInRect(bl_pt))
		{
			pt.x = tl_pt.x - test.left-test.Width()/2;
			flag = STICK_RIGHT;
			return elem;
		}
	}
	return NULL;
}

int CReportSheet::FindElement(RE_Array* array, CReportElement *elem)
{
	if(array==0 || elem==0) return -1;
	for(int i=0; i<array->GetSize();i++)
	{
		CReportElement* tmp = array->GetAt(i);
		if(tmp==elem) return i;
	}
	return -1;
}

CPoint CReportSheet::GetOrgPt()const
{
	return CPoint(m_org_pt.x,-m_org_pt.y);
}

CPoint CReportSheet::SetOrgPt(CPoint pt)
{
	CPoint old = m_org_pt;
	m_org_pt = pt;
	return old;
}

void CReportSheet::Update(bool set)
{
	DeleteItems();
	if(set)
	{
		if(m_inst==0)
			m_inst=m_ReportMgr->m_data->CreateInstance(m_ReportMgr->e_apl_report_sheet);
		m_ReportMgr->PutPoint(m_inst,m_ReportMgr->a_elem_size,m_size);
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_rep_sheet_type,m_type);
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_elem_name,m_name);

		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_report_sheet_top_offset, m_print_offset_rect.top);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_report_sheet_bottom_offset, m_print_offset_rect.bottom);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_report_sheet_left_offset, m_print_offset_rect.left);
		m_ReportMgr->m_data->PutAttr(m_inst, m_ReportMgr->a_apl_report_sheet_right_offset, m_print_offset_rect.right);
	}
	else
	{
		if(m_inst==0) return;

		int top, left, right, bottom;

		m_ReportMgr->GetPoint(m_inst,m_ReportMgr->a_elem_size,m_size);
		m_ReportMgr->m_data->GetAttr(m_inst,m_ReportMgr->a_rep_sheet_type,m_type);

		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_report_sheet_top_offset, top);
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_report_sheet_bottom_offset, bottom);
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_report_sheet_left_offset, left);
		m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_apl_report_sheet_right_offset, right);

		m_print_offset_rect.SetRect(left, top, right, bottom);
	}
	aplExtent ext;
	for(int i=0;i<m_els.GetSize();i++)
	{
		CReportElement* elem = m_els.GetAt(i);
		if(elem==0) continue;
		elem->Update(set);
		if(set)
			ext.Add(elem->m_inst);
	}
	if(set)
		m_ReportMgr->m_data->PutAttr(m_inst,m_ReportMgr->a_rep_sheet_els,ext);

}

bool CReportSheet::LoadElementsFromFile()
{
	if(m_isLoaded) return true;
	m_isLoaded = true;
	if(m_inst==0) return true;
	int cnt = m_els.GetSize();
	int i;
	for(i=0;i<cnt;i++)
	{
		if(m_els[i]->GetType()!=E_TABLE)
			delete m_els[i];
	}
	m_els.RemoveAll();
	aplExtent ext;
	m_ReportMgr->m_data->GetAttr(m_inst, m_ReportMgr->a_rep_sheet_els,ext);
	cnt = ext.GetSize();
	for(i=0; i<cnt; i++)
		CReportElement* elem = m_ReportMgr->CreateElemObj(ext[i],this);
	Update(false);
	return true;
}

void CReportSheet::FreeElements()
{
	DeleteItems();

	Update();
	int cnt = m_els.GetSize();
	for(int i=0;i<cnt;i++)
	{
		if(m_els[i]->GetType()!=E_TABLE)
			DELETE_OBJECT(m_els[i]);
	}
	m_els.RemoveAll();
	m_isLoaded = false;
}

bool CReportSheet::IsLoaded()
{
	return m_isLoaded;
}

void CReportSheet::DeleteItems()
{
	if(m_DeletedItems.GetSize())
	{
		if(!IsLoaded())
			LoadElementsFromFile();
	}
	for(int i=0; i<m_DeletedItems.GetSize(); i++)
	{
		m_DeletedItems[i]->Delete();
		delete m_DeletedItems[i];
	}
	m_DeletedItems.RemoveAll();
}

bool CReportSheet::RestoreItem(CReportElement *elem, int pos)
{
	for(int i=0; i<m_DeletedItems.GetSize(); i++)
	{
		if(m_DeletedItems[i]==elem)
		{
			if(pos<0 || pos>m_els.GetSize()-1)
				m_els.Add(elem);
			else
				m_els.InsertAt(pos, elem);
			m_DeletedItems.RemoveAt(i);
			return true;
		}
	}
	return false;
}

void CReportSheet::Delete()
{
	while(m_els.GetSize()>0)
		DeleteElement(m_els[0], false);
	DeleteItems();
	int cnt = m_ReportMgr->m_sheets.GetSize();
	for(int i=0; i<cnt; i++)
		if(m_ReportMgr->m_sheets.GetAt(i)==this)
		{
			m_ReportMgr->m_sheets.RemoveAt(i);
			break;
		}
	if(m_inst)
		m_ReportMgr->m_data->DeleteInstance(m_inst);

	delete this;
}

bool CReportSheet::SelectElement(CReportParam *param)
{
	if(!IsLoaded())
		LoadElementsFromFile();
	
	RE_Array rowElements;
	int i;
	
	for(i=0; i<m_els.GetSize(); i++)
	{
		if(m_els[i]->GetType()==E_RECT)
		{
			if(((CRectReportElement*)m_els[i])->m_value.GetParam()==param)
				rowElements.Add(m_els[i]);
		}
		m_els[i]->m_color = 0;
		m_els[i]->m_background_color = RGB(255, 255, 255);
	}
	
	COLORREF txtclr = ::GetSysColor(COLOR_CAPTIONTEXT), bgclr=::GetSysColor(COLOR_ACTIVECAPTION);
	BYTE rval, gval, bval;
	rval = GetRValue(bgclr);
	gval = GetGValue(bgclr);
	bval = GetBValue(bgclr);
	rval = (BYTE)((int)((int)(rval)+(int)255)/2);
	gval = (BYTE)((int)((int)(gval)+(int)255)/2);
	bval = (BYTE)((int)((int)(bval)+(int)255)/2);
	bgclr = RGB(rval, gval, bval);
	for(i=0; i<rowElements.GetSize(); i++)
	{
		rowElements[i]->m_color = txtclr;
		rowElements[i]->m_background_color = bgclr;
	}
	
	return true;
}


bool CReportSheet::SelectRow(int row)
{
	if(!IsLoaded())
		LoadElementsFromFile();
	
	RE_Array rowElements;
	int i;
	
	for(i=0; i<m_els.GetSize(); i++)
	{
		if(m_els[i]->GetType()==E_RECT)
		{
			if(((CRectReportElement*)m_els[i])->m_dsfrow==row)
				rowElements.Add(m_els[i]);
			else
				((CRectReportElement*)m_els[i])->m_value.m_color = 0;
		}
		m_els[i]->m_color = 0;
		m_els[i]->m_background_color = RGB(255, 255, 255);
		m_els[i]->m_bNeedFillBackground = false;
	}
	
	COLORREF txtclr = ::GetSysColor(COLOR_CAPTIONTEXT), bgclr=::GetSysColor(COLOR_ACTIVECAPTION);
	BYTE rval, gval, bval;
	rval = GetRValue(bgclr);
	gval = GetGValue(bgclr);
	bval = GetBValue(bgclr);
	rval = (BYTE)((int)((int)(rval)+(int)255)/2);
	gval = (BYTE)((int)((int)(gval)+(int)255)/2);
	bval = (BYTE)((int)((int)(bval)+(int)255)/2);
	bgclr = RGB(rval, gval, bval);
	for(i=0; i<rowElements.GetSize(); i++)
	{
		((CRectReportElement*)rowElements[i])->m_value.m_color = txtclr;
		rowElements[i]->m_background_color = bgclr;
		rowElements[i]->m_bNeedFillBackground = true;
	}
	
	return true;
}
