// EffectivityView.cpp : implementation file
//

#include "stdafx.h"
#include "aplAggr.h"
#include "StepData.h"
#include "EffectivityView.h"
#include "ManagerEffGanttDlg.h"
#include "AddRuleDate.h"
#include "AddSerialNum.h"

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

//////////////////////////////////////////////////////////////////////////
// CSerialNumberStrMap

CSerialNumberStrMap::CSerialNumberStrMap()
{
	m_bCompareCase = TRUE;
}

CSerialNumberStrMap::~CSerialNumberStrMap()
{

}

int CSerialNumberStrMap::CompareSN(CString strSN1, CString strSN2)
{
	// Форматы:
	// Ми-8  - 093NNSSS
	// Ансат - 033NNSSS
	// Ми-8 (лопасти) - 855NNSSS, 
	// где 033, 093 и 855 - префиксы; NN - номера изделий; SSS - номера серий.

	if ((strSN1.GetLength() != 8) || (strSN2.GetLength() != 8))
		return strSN1.Compare(strSN2);

	int iSerialNumber1 = _atoi(strSN1.Right(3));
	int iSerialNumber2 = _atoi(strSN2.Right(3));
	int iProductNumber1 = _atoi(strSN1.Mid(3, 2));
	int iProductNumber2 = _atoi(strSN2.Mid(3, 2));

	// Сравнение серий
	if (iSerialNumber1 > iSerialNumber2)
		return 1;
	else if (iSerialNumber1 < iSerialNumber2)
		return -1;

	// Сравнение номеров
	if (iProductNumber1 > iProductNumber2)
		return 1;
	else if (iProductNumber1 < iProductNumber2)
		return -1;

	return 0;
}

int CSerialNumberStrMap::CallbackCompareSN(const void *arg1, const void *arg2)
{
	CString sn1 = (*(CaplStrMapItem**)arg1)->str;
	CString sn2 = (*(CaplStrMapItem**)arg2)->str;

	if ((sn1.GetLength() != 8) || (sn2.GetLength() != 8))
		return sn1.Compare(sn2);

	int iSerialNumber1 = _atoi(sn1.Right(3));
	int iSerialNumber2 = _atoi(sn2.Right(3));
	int iProductNumber1 = _atoi(sn1.Mid(3, 2));
	int iProductNumber2 = _atoi(sn2.Mid(3, 2));

	// Сравнение серий
	if (iSerialNumber1 > iSerialNumber2)
		return 1;
	else if (iSerialNumber1 < iSerialNumber2)
		return -1;

	// Сравнение номеров
	if (iProductNumber1 > iProductNumber2)
		return 1;
	else if (iProductNumber1 < iProductNumber2)
		return -1;

	return 0;
}

void CSerialNumberStrMap::SortSerial()
{
	if (items.GetSize() < 2)
		return;

	qsort(items.GetData(), items.GetSize(), sizeof(CaplStrMapItem*), CallbackCompareSN);
}

int CSerialNumberStrMap::FindSerial(LPCTSTR str)
{
	if (items.GetSize() < 1)
		return -1;

	int i = 0; 
	int i0 = 0;
	int i1 = items.GetSize() - 1;
	int io = -1;
	int index = -1;

	// поиск упорядоченного значения
	do
	{
		io = i;
		i = (i0 + i1) >> 1;

		if (io == i)
			break;

		if (items[i]->str == str)
		{
			index = i; 
			break;
		}

		if (CompareSN(items[i]->str, str) == -1)
			i0 = i;
		else
			i1 = i;
	}
	while(1);

	if (index != -1)
		return index;

	if (items[i1]->str == str)
		return i1;

	if (items[i0]->str == str)
		return i0;

	return -1;
}

/////////////////////////////////////////////////////////////////////////////
// CEffectivityView

IMPLEMENT_DYNCREATE(CEffectivityView, CScrollView)

CEffectivityView::CEffectivityView()
{
	m_api=0;
	m_items=0; 
	m_all_items=0;
	m_items_MaxSize=0;
	m_items_size=0;
	m_all_items_MaxSize=0;
	m_all_items_size=0;

	m_bReadOnly=true;

	m_first_eff_offset=15;
	m_undef_offset=15;
	m_pixelsInItem=50;
	m_nDiagramWidth=0;
	m_min_pixels_in_item=60;

	m_eff_mgr_dlg=0;

	m_sel_nItem=-1;
	m_sel_item_rect.SetRect(0,0,0,0);

	m_cur_date_item_index=-1;
	m_cur_ass_item_id=_T("");

	m_eff_brush.CreateSolidBrush(RGB(102,153,255));
	m_eff_border_brush.CreateSolidBrush(RGB(0,0,0));
	m_arrow_brush.CreateSolidBrush(RGB(255,0,0));
	m_cur_date_brush.CreateSolidBrush(RGB(255,255,204));
	m_select_brush.CreateSolidBrush(RGB(204,204,204));
	m_inner_code_select_brush.CreateSolidBrush(RGB(204,255,204));
	
	CBitmap pattern_bmp;
	COLORMAP  cm[2];
	cm[0].from=RGB(255,255,255);
	cm[0].to=RGB(255,0,0);
	cm[1].from=RGB(0,0,128);
	cm[1].to=RGB(0,0,128);
	pattern_bmp.LoadMappedBitmap(IDB_PATTERN,0,cm,2);
	m_inters_brush.CreatePatternBrush(&pattern_bmp);

	m_pen.CreatePen(PS_SOLID,1,RGB(192,192,192));
	m_red_pen.CreatePen(PS_SOLID,2,RGB(255,0,0));
	m_black_pen.CreatePen(PS_SOLID,1,RGB(0,0,0));
}

CEffectivityView::~CEffectivityView()
{
	if(m_items) delete [] m_items; 
	if(m_all_items) delete [] m_all_items; 

}


BEGIN_MESSAGE_MAP(CEffectivityView, CScrollView)
	//{{AFX_MSG_MAP(CEffectivityView)
	ON_WM_PAINT()
	ON_WM_CREATE()
	ON_WM_HSCROLL()
	ON_WM_SIZE()
	ON_WM_MOUSEACTIVATE()
	ON_WM_MOUSEMOVE()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_CONTEXTMENU()
	ON_WM_LBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CEffectivityView drawing

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

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

void CEffectivityView::OnDraw(CDC* pDC)
{
	CDocument* pDoc = GetDocument();
	// TODO: add draw code here

	int oldMM = pDC->SetMapMode(MM_TEXT);
	unsigned int cx = 0;
	CRect clRect;
	
	CDC memDC;
	CBitmap bmp;
	CBitmap *old = NULL;

	memDC.CreateCompatibleDC(pDC);

	GetClientRect(clRect);
	if(m_nDiagramWidth<clRect.Width())
		cx = clRect.Width();
	else
		cx = m_nDiagramWidth;

	int DPI = 300;
	
	BITMAPINFO bmi;
	bmi.bmiColors[0].rgbBlue = 255;
	bmi.bmiColors[0].rgbRed = 255;
	bmi.bmiColors[0].rgbGreen = 255;
	bmi.bmiColors[0].rgbReserved = 0;
	
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = cx;
	bmi.bmiHeader.biHeight= clRect.Height();
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 32;
	bmi.bmiHeader.biCompression = BI_RGB;
	bmi.bmiHeader.biSizeImage = 0;
	bmi.bmiHeader.biXPelsPerMeter = DPI;
	bmi.bmiHeader.biYPelsPerMeter = DPI;
	bmi.bmiHeader.biClrUsed = 0;
	bmi.bmiHeader.biClrImportant = 0;

	void *buf;
	HBITMAP hBm = ::CreateDIBSection(memDC.m_hDC, &bmi, DIB_RGB_COLORS, &buf,NULL, NULL);
	if(!hBm)
	{
		AfxMessageBox( APL_T("Невозможно выделить необходимое количество памяти!"));
		return;
	}

	bmp.Attach(hBm);
	old = memDC.SelectObject(&bmp);
	OnPrepareDC(&memDC);

	memDC.SetViewportOrg(-GetScrollPosition().x, 0);
	memDC.FillSolidRect(0, 0, cx, clRect.Height(), ::GetSysColor(COLOR_WINDOW));

	PaintHeader(memDC,APL_MODE_EDIT);
	//PaintSelection(memDC,APL_MODE_EDIT);
	PaintItems(memDC,APL_MODE_EDIT);
	PaintIntersection(memDC,APL_MODE_EDIT);

	pDC->BitBlt(0, 0, cx, clRect.Height(), &memDC, 0, 0, SRCCOPY);

	memDC.SelectObject(old);
	bmp.DeleteObject();
	
	ReleaseDC(&memDC);

	memDC.DeleteDC();	
	pDC->SetMapMode(oldMM);	
	
}


/////////////////////////////////////////////////////////////////////////////
// CGanttDiagramView message handlers

void CEffectivityView::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
		
	OnPrepareDC(&dc);
	OnDraw(&dc);
	ReleaseDC(&dc);
}


int CEffectivityView::OnMouseActivate( CWnd* pDesktopWnd, 
                                  UINT nHitTest, 
                                  UINT message )
{
  return MA_ACTIVATE;
}
/////////////////////////////////////////////////////////////////////////////
// CEffectivityView diagnostics

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

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

/////////////////////////////////////////////////////////////////////////////
// CEffectivityView message handlers

void CEffectivityView::Update(bool bUpdateCalendar,bool bAutoResize)
{
	if(bUpdateCalendar) UpdateCalendar(bAutoResize);

	//if(bUpdateCalendar) ScrollDiagramToCurrentDate();
	Invalidate();
}

void CEffectivityView::RemoveAllItems(int mode)
{
	if(m_items) 
	{
		if(m_items_size) delete [] m_items;
	}
	m_items_size=0;
	m_items_MaxSize=0;
	m_items=0;
	
	if(mode==APL_MODE_ALL)
	{
		if(m_all_items) 
		{
			if(m_all_items_size) delete [] m_all_items;
		}
		m_all_items_size=0;
		m_all_items_MaxSize=0;
		m_all_items=0;
	}

}

bool CEffectivityView::SetArraySize(int new_size,int mode)
{
	if(mode==APL_MODE_VISIBLE)
	{
		if(new_size<m_items_MaxSize) return false;
		if(new_size==m_items_MaxSize) return true;
		
		EffItem *data=new EffItem[new_size];

		if(m_items!=0)
		{
			for(int i=0;i<m_items_size;i++)
			{
				data[i]=m_items[i];
			}
			if(m_items_size) delete [] m_items;
		}
		m_items=data;
		m_items_MaxSize=new_size;
	}
	else
	{
		if(new_size<m_all_items_MaxSize) return false;
		if(new_size==m_all_items_MaxSize) return true;
		
		EffItem *data=new EffItem[new_size];

		if(m_all_items!=0)
		{
			for(int i=0;i<m_all_items_size;i++)
			{
				data[i]=m_all_items[i];
			}
			if(m_all_items_size) delete [] m_all_items;
		}
		m_all_items=data;
		m_all_items_MaxSize=new_size;
	}

	return true;
}

int CEffectivityView::InsertItem(EffItem &new_item,int mode)
{
	int return_value=0;
	if(mode==APL_MODE_VISIBLE)
	{
		if(m_items_size+1>m_items_MaxSize) 
			SetArraySize((m_items_size+1)*2,mode);
		m_items[m_items_size]=new_item;
		return_value=m_items_size++;
	}
	else
	{
		if(m_all_items_size+1>m_all_items_MaxSize) 
			SetArraySize((m_all_items_size+1)*2,mode);
		m_all_items[m_all_items_size]=new_item;

		return_value=m_all_items_size++;
	}
	return return_value;

}

void CEffectivityView::UpdateCalendar(bool bAutoResize)
{
	int i;
	m_eff_map.Clear();
	for(i=0;i<m_all_items_size;i++)
	{
		if(m_all_items[i].m_eff_type!=m_eff_mode) continue;
		
		if(m_eff_map.Find(m_all_items[i].m_start)<0)
		{
			m_eff_map.Add(m_all_items[i].m_start,(long)m_all_items[i].m_eff);
		}
		if(m_eff_map.Find(m_all_items[i].m_end)<0)
		{
			if(m_all_items[i].m_end!=_T("")) m_eff_map.Add(m_all_items[i].m_end,(long)m_all_items[i].m_eff);
		}
	}

//	m_eff_map.Sort();
//*
	if (m_eff_mode == APL_EFF_DATE)
		m_eff_map.Sort();
	else
		m_eff_map.SortSerial();
//*/
	m_cur_date_item_index=-1;
	COleDateTime dt=COleDateTime::GetCurrentTime();
	CString buf,cur_dt_s;
	aplDate2String(dt,cur_dt_s);
	if(m_eff_mode==APL_EFF_DATE)
	{
		for(i=0;i<m_eff_map.GetSize();i++)
		{
			buf=m_eff_map.GetAt(i)->str;	
			if(buf>cur_dt_s || i==m_eff_map.GetSize()-1)
			{
				m_cur_date_item_index=i;
				break;
			}
		}
	}
	if(bAutoResize) AutoResizeDiagram();
	m_nDiagramWidth = (m_eff_map.GetSize())*m_pixelsInItem+m_first_eff_offset*2;
	SetScrollSizes(MM_TEXT, CSize(m_nDiagramWidth,1));
}


void CEffectivityView::PaintDiagram(CDC &dc,long mode)
{
	dc.SetViewportOrg(-GetScrollPosition().x, 0);
	 
	// First let the control do its default drawing.
	CWnd::DefWindowProc( WM_PAINT, (WPARAM)dc.m_hDC, 0 );
	PaintHeader(dc,mode);
	//PaintSelection(dc,mode);
	PaintItems(dc,mode);
	PaintIntersection(dc,mode);
}

void CEffectivityView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	Invalidate();

	CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CEffectivityView::PaintHeader(CDC &dc,long mode)
{

	if(m_all_items_size==0) return;

	CRect rcClient;
	GetClientRect(&rcClient);

	// First let the control do its default drawing.
	CWnd::DefWindowProc( WM_PAINT, (WPARAM)dc.m_hDC, 0 );
	dc.SelectObject(GetStockObject(DEFAULT_GUI_FONT));
	
	int i;
	CString buf;
	CPen *oldPen=dc.SelectObject(&m_pen);

	CRect list_header_rect;
	m_prd_view->GetListCtrl().GetHeaderCtrl()->GetClientRect(list_header_rect);
	dc.MoveTo(m_first_eff_offset,list_header_rect.bottom);
	dc.LineTo(m_nDiagramWidth-m_first_eff_offset,list_header_rect.bottom);

	int Top = 0;
	int Bottom=rcClient.Height();
	int Left=m_first_eff_offset;	
	dc.MoveTo(Left,Top);
	dc.LineTo(Left,Bottom);

	CRect cur_date_rect;

	m_cal_rect_array.RemoveAll();
	COleDateTime dt;
	for(i=0;i<m_eff_map.GetSize();i++)
	{
		int Right=Left+m_pixelsInItem;

		//отрисовка текущего периода
		if(m_eff_mode==APL_EFF_DATE && i==m_cur_date_item_index)
		{
			cur_date_rect.SetRect(Left+1,list_header_rect.bottom+1,Right-1,Bottom);
			dc.FillRect(cur_date_rect,&m_cur_date_brush);
		}
		// Отрисовка вертикальных линий 
		dc.MoveTo(Right,Top);
		dc.LineTo(Right,Bottom);
		
		buf=m_eff_map.GetAt(i)->str;
		if(m_eff_mode==APL_EFF_DATE)
		{
			if(buf==_T("19010101000000")) buf=_T("");
			aplString2Date(buf,dt);
			if(dt.GetStatus()==COleDateTime::valid)
			{
				if(m_pixelsInItem<80) buf=dt.Format(_T("%d.%m.%y"));
				else buf=dt.Format(_T("%d.%m.%Y"));
			}
		}	
		CRect title_rect;
		title_rect.SetRect(Left,Top,Right,Bottom);
		dc.DrawText(buf, title_rect,DT_LEFT);
		m_cal_rect_array.Add(title_rect);
		
		Left+=m_pixelsInItem;
	}
	dc.SelectStockObject(SYSTEM_FONT);
	dc.SelectObject(&oldPen);

}

void CEffectivityView::PaintItems(CDC &dc,long mode)
{
	CBrush *oldBrush=NULL;
	CPen *oldPen=dc.SelectObject(&m_pen);
	
	COleDateTimeSpan dt_span1,dt_span2;
	COleDateTime dt_begin,dt_end;
	int i;
	
	//вывод прямоугольников 
	for(i=0;i<m_items_size;i++)
	{
		if(m_items[i].m_eff_type!=m_eff_mode) continue; 
		GetEffRect(&m_items[i]);
		CBrush *item_brush=&m_eff_brush;
		if((m_sel_nItem==m_items[i].m_nItem) || 
		  (m_cur_ass_item_id!=_T("") && m_items[i].m_ass_item_id==m_cur_ass_item_id))
		{
			item_brush=&m_inner_code_select_brush;
		}
		dc.FillRect(m_items[i].m_item_rect, item_brush);
	}
	dc.SelectObject(&m_black_pen);
	for(i=0;i<m_items_size;i++)
	{
		if(m_items[i].m_eff_type!=m_eff_mode) continue; 
		CRect eff_rect=m_items[i].m_item_rect;
		//рамочки
		dc.FrameRect(eff_rect,&m_eff_border_brush);
		//отрисовка стрелок, показывающих не заданные даты
		//oldBrush=dc.SelectObject(&m_arrow_brush);
		CBrush *arrow_brush=&m_eff_brush;
		if((m_sel_nItem==m_items[i].m_nItem) || 
		  (m_cur_ass_item_id!=_T("") && m_items[i].m_ass_item_id==m_cur_ass_item_id))
		{
			arrow_brush=&m_inner_code_select_brush;
		}
		oldBrush=dc.SelectObject(arrow_brush);
		if(m_items[i].m_start==_T(""))
		{
			dc.MoveTo(eff_rect.left,eff_rect.top-2);
			dc.LineTo(eff_rect.left-m_undef_offset,eff_rect.top+(int)(eff_rect.bottom-eff_rect.top)/2);
			dc.LineTo(eff_rect.left,eff_rect.bottom+1);
			dc.LineTo(eff_rect.left,eff_rect.top-2);
			dc.FloodFill((int)m_undef_offset/2,eff_rect.top+(int)(eff_rect.bottom-eff_rect.top)/2,RGB(0,0,0));
		}
		if(m_items[i].m_end==_T(""))
		{
			dc.MoveTo(eff_rect.right,eff_rect.top-2);
			dc.LineTo(eff_rect.right+m_undef_offset,eff_rect.top+(int)(eff_rect.bottom-eff_rect.top)/2);
			dc.LineTo(eff_rect.right,eff_rect.bottom+1);
			dc.LineTo(eff_rect.right,eff_rect.top-2);
			dc.FloodFill(eff_rect.right+(int)m_undef_offset/2,eff_rect.top+(int)(eff_rect.bottom-eff_rect.top)/2,RGB(0,0,0));
		}
		dc.SelectObject(oldBrush);
	}
	dc.SelectObject(&oldPen);
	
}

void CEffectivityView::PaintIntersection(CDC &dc,long mode)
{
	int i=0;
	for(i=0;i<m_items_size;i++)
	{
		if(m_items[i].m_eff_type!=m_eff_mode) continue;
		for(int j=0;j<m_items_size;j++)
		{
			if(m_items[i].m_rel!=m_items[j].m_rel) continue;
			if(m_items[j].m_eff_type!=m_eff_mode) continue;
			CRect inters_rect;
			bool b_intersect=false;			

			if ((m_eff_map.CompareSN(m_items[i].m_start, m_items[j].m_start) == -1) && 
				(m_eff_map.CompareSN(m_items[i].m_end, m_items[j].m_end) == 1) && 
				!m_items[j].m_end.IsEmpty())
			{
				inters_rect.SetRect(m_items[j].m_item_rect.left, 
					                m_items[j].m_item_rect.top,
									m_items[j].m_item_rect.right,
									m_items[j].m_item_rect.bottom);
				b_intersect = true;
			}
			else if ((m_eff_map.CompareSN(m_items[i].m_start, m_items[j].m_start) == -1) && 
				     (m_eff_map.CompareSN(m_items[i].m_end, m_items[j].m_start) == 1))
			{
				inters_rect.SetRect(m_items[j].m_item_rect.left,
					                m_items[j].m_item_rect.top,
									m_items[i].m_item_rect.right,
									m_items[i].m_item_rect.bottom);
				b_intersect = true;
			}

/*
			if(m_items[i].m_start<m_items[j].m_start && (m_items[i].m_end>m_items[j].m_end && m_items[j].m_end!=_T("")))
			{
				inters_rect.SetRect(m_items[j].m_item_rect.left,m_items[j].m_item_rect.top,m_items[j].m_item_rect.right,m_items[j].m_item_rect.bottom);
				b_intersect=true;
			}
			else if(m_items[i].m_start<m_items[j].m_start && m_items[i].m_end>m_items[j].m_start)
			{
				inters_rect.SetRect(m_items[j].m_item_rect.left,m_items[j].m_item_rect.top,m_items[i].m_item_rect.right,m_items[i].m_item_rect.bottom);
				b_intersect=true;
			}
*/
			if(b_intersect)
			{
				inters_rect.DeflateRect(1,1);
				dc.FillRect(inters_rect, &m_inters_brush);
			}
			j++;
		}
	}
}

void CEffectivityView::PaintSelection(CDC &dc,long mode)
{
	CRect select_rect;
	//выделение выделенной строки в контроле 
	CRect cl_rect;
	GetClientRect(cl_rect);
	if(m_sel_nItem!=-1)
	{
		select_rect=m_sel_item_rect;
		select_rect.left=0;
		select_rect.right=max(cl_rect.right,m_nDiagramWidth);

		CRect list_header_rect;
		m_prd_view->GetListCtrl().GetHeaderCtrl()->GetClientRect(list_header_rect);
		if(select_rect.top>=list_header_rect.bottom)
		{
			dc.FillRect(select_rect,&m_select_brush);
		}
	}
}

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

void CEffectivityView::OnSize(UINT nType, int cx, int cy) 
{
	CScrollView::OnSize(nType, cx, cy);
	
	if(!::IsWindow(m_hWnd)) return;
	if(m_nDiagramWidth)
	{
		CPoint cur_pos=GetScrollPosition(); 
		AutoResizeDiagram();
		SetScrollSizes(MM_TEXT, CSize(m_nDiagramWidth,1));
		ScrollToPosition(cur_pos);
	}

}

int CEffectivityView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CScrollView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	LOGFONT lf;
	CFont *font=(CFont*)CFont::FromHandle((HFONT)GetStockObject(ANSI_VAR_FONT));
	font->GetLogFont(&lf);
	lf.lfWeight=FW_NORMAL;
	m_pFont.CreateFontIndirect(&lf);
	m_ToolTip.m_pFont=&m_pFont;
	
	return 0;
}

BOOL CEffectivityView::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class
	if(pMsg!=0)
	{
		if(m_ToolTip.IsNeedHideOnMessage(pMsg->message))
			m_ToolTip.Hide();
	}
	return CScrollView::PreTranslateMessage(pMsg);
}

void CEffectivityView::OnMouseMove(UINT nFlags, CPoint point) 
{
	m_ToolTip.Hide();

	EffItem *effItem=0;

	CWnd::OnMouseMove(nFlags,point); 
	
	DisplayToolTip(point);

	TRACKMOUSEEVENT		csTME;
	csTME.cbSize = sizeof(csTME);
	csTME.dwFlags = TME_LEAVE;
	csTME.hwndTrack = m_hWnd;
	::_TrackMouseEvent(&csTME);
}

void CEffectivityView::DisplayToolTip(CPoint point)
{
	CIntArray itemsArray;
	if(!PointToVals(&point,itemsArray)) return;
	CString buf;
	CString tooltip_text=_T("");
	for(int i=0;i<itemsArray.GetSize();i++)
	{
		EffItem *effItem=&m_items[itemsArray[i]];
		if(i==0)
		{
			if(effItem->m_pdf_id!=_T(""))
			{
				tooltip_text+= APL_T("Изделие: ")+effItem->m_pdf_id;
			}
		}
		if(effItem->m_b_no_effectivity)
		{
			tooltip_text+= APL_T("\nПравил применяемости не задано");
			break;
		}
		tooltip_text+= APL_T("\nПравило применяемости: ");
		tooltip_text+=effItem->m_id;
		COleDateTime dt;
		if(effItem->m_start!=_T(""))
		{
			//tooltip_text+=APL_T("\nC:   ");
			// Так для удобства перевода
			tooltip_text+=APL_NO_T("\n");
			tooltip_text+=APL_T("С:");
			tooltip_text+=APL_NO_T("   ");
			buf=effItem->m_start;
			if(m_eff_mode==APL_EFF_DATE)
			{
				aplString2Date(effItem->m_start,dt);
				buf=dt.Format(_T("%d.%m.%Y"));
			}
			tooltip_text+=buf;
		}
		if(effItem->m_end!=_T(""))
		{
			//tooltip_text+= APL_T("\nПо: ");
			// Так для удобства перевода
			tooltip_text+= APL_NO_T("\n");
			tooltip_text+= APL_T("По:");
			tooltip_text+= APL_NO_T(" ");
			buf=effItem->m_end;
			if(m_eff_mode==APL_EFF_DATE)
			{
				aplString2Date(effItem->m_end,dt);
				buf=dt.Format(_T("%d.%m.%Y"));
			}
			tooltip_text+=buf;
		}
	}

	
	CPoint pnt;
	pnt.x=point.x+10;
	pnt.y=point.y;
	ClientToScreen(&pnt);

	m_ToolTip.Show(pnt.x, pnt.y, tooltip_text);  
}

void CEffectivityView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	//if(!m_api) return;
	Update(true);
}

bool CEffectivityView::PointToVal(CPoint *point, EffItem **effItem)
{
	*effItem=0;
	CPoint abs_point=*point;
	abs_point.x+=GetScrollPosition().x;

	for(int i=0;i<m_items_size;i++)
	{
		if(m_items[i].m_eff_type!=m_eff_mode) continue;
		if(m_items[i].m_b_no_effectivity) continue;
		if(m_items[i].m_item_rect.PtInRect(abs_point)) 
		{
			*effItem=&m_items[i];
			return true;
		}
	}
	return false;
}

bool CEffectivityView::PointToVals(CPoint *point, CIntArray &i_itemsArray)
{
	bool res=false;
	i_itemsArray.RemoveAll();
	CPoint abs_point=*point;
	abs_point.x+=GetScrollPosition().x;

	for(int i=0;i<m_items_size;i++)
	{
		if(m_items[i].m_eff_type!=m_eff_mode) continue;
		if(m_items[i].m_item_rect.PtInRect(abs_point)) 
		{
			i_itemsArray.Add(i);
			res=true;
		}
	}
	return res;
}

void CEffectivityView::GetEffRect(EffItem *effItem)
{
	effItem->m_item_rect.left = m_first_eff_offset;
	effItem->m_item_rect.right = m_nDiagramWidth - m_first_eff_offset;

	int index;

	if (m_eff_mode == APL_EFF_DATE)
	{
		if (!effItem->m_start.IsEmpty()) 
		{
			index = m_eff_map.Find(effItem->m_start);
			
			if (index >= 0)
				effItem->m_item_rect.left = m_first_eff_offset + index * m_pixelsInItem;
		}

		if (!effItem->m_end.IsEmpty()) 
		{
			index = m_eff_map.Find(effItem->m_end);

			if (index >= 0)
				effItem->m_item_rect.right = m_first_eff_offset + index * m_pixelsInItem;
		}
	}
	else if (m_eff_mode == APL_EFF_SN)
	{
		if (!effItem->m_start.IsEmpty()) 
		{
			index = m_eff_map.FindSerial(effItem->m_start);

			if (index >= 0)
				effItem->m_item_rect.left = m_first_eff_offset + index * m_pixelsInItem;
		}

		if (!effItem->m_end.IsEmpty()) 
		{
			index = m_eff_map.FindSerial(effItem->m_end);

			if (index >= 0)
				effItem->m_item_rect.right = m_first_eff_offset + (index + 1) * m_pixelsInItem - 5;
		}	
	}
	else
	{
		if (!effItem->m_start.IsEmpty()) 
		{
			index = m_eff_map.Find(effItem->m_start);

			if (index >= 0)
				effItem->m_item_rect.left = m_first_eff_offset + index * m_pixelsInItem;
		}

		if (!effItem->m_end.IsEmpty()) 
		{
			index = m_eff_map.Find(effItem->m_end);

			if (index >= 0)
				effItem->m_item_rect.right = m_first_eff_offset + (index + 1) * m_pixelsInItem - 5;
		}	
	}
}

void CEffectivityView::AutoResizeDiagram()
{
	CRect cl_rect;
	GetClientRect(&cl_rect);
	//if(m_nDiagramWidth<cl_rect.Width())
	//{
		if(m_eff_map.GetSize()) 
		{
			m_pixelsInItem=(int)((cl_rect.Width()-m_first_eff_offset*2)/m_eff_map.GetSize());
			if(m_pixelsInItem<m_min_pixels_in_item) m_pixelsInItem=m_min_pixels_in_item;
			m_nDiagramWidth = (m_eff_map.GetSize())*m_pixelsInItem+m_first_eff_offset*2;
			if(m_eff_mgr_dlg->m_width!=m_pixelsInItem)
			{
				m_eff_mgr_dlg->m_width=m_pixelsInItem;
				m_eff_mgr_dlg->UpdateData(false);
			}
		}
		
	//}
}


void CEffectivityView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	EffItem *effItem=0;

	if(false==PointToVal(&point,&effItem)) return;
	if(!effItem) return;

	ShowEffProperties(effItem);

	
	CScrollView::OnLButtonDblClk(nFlags, point);
}

bool CEffectivityView::ShowEffProperties(EffItem *effItem)
{
	if(!effItem) return false;
	bool b_refresh_needed=false;
	if(m_eff_mode==APL_EFF_DATE)
	{
		//по дате
		CAddRuleDate dlg;
		dlg.m_RO=m_bReadOnly;
		dlg.m_data=&m_api->m_data;
		dlg.m_eff=effItem->m_eff;
		dlg.m_PrMan=&m_api->m_prd_mgr;
		if(dlg.DoModal()==IDOK) b_refresh_needed=true;
	}
	else
	{
		//по серийному номеру
		CAddSerialNum dlg;
		dlg.m_data=&m_api->m_data;
		dlg.m_PrMan=&m_api->m_prd_mgr;
		dlg.m_eff=effItem->m_eff;
		if(dlg.DoModal()==IDOK) b_refresh_needed=true;
	}
	if(b_refresh_needed) m_prd_view->UpdateDiagramSource();
	
	return true;
}

void CEffectivityView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	OnLButtonDown(nFlags,point);
	CMenu menu;
 	CMenu* pPopup =0;
	//загружаем контекстное меню
 	VERIFY(menu.LoadMenu(IDR_CONTEXT_MENU));
 	pPopup = menu.GetSubMenu(0);

	EffItem *effItem=0;
	PointToVal(&point,&effItem);
	if(m_sel_nItem<0 && !effItem) return;

	CaplInstance *pdr=0;
	CString start_value;
	Point2Start(point,start_value);
	if(effItem) 
	{
		pdr=effItem->m_rel;
	}
	else
	{
		if(m_sel_nItem>-1) pdr=(CaplInstance*)m_prd_view->GetListCtrl().GetItemData(m_sel_nItem);
	}

	if(!effItem || effItem->m_b_no_effectivity)
	{
		pPopup->RemoveMenu(IDC_DELETE,MF_BYCOMMAND);
		pPopup->RemoveMenu(IDC_CHANGE,MF_BYCOMMAND);
	}
	if(m_bReadOnly)
	{
		pPopup->RemoveMenu(IDC_ADD,MF_BYCOMMAND);
		pPopup->RemoveMenu(IDC_DELETE,MF_BYCOMMAND);
		pPopup->ModifyMenu(IDC_CHANGE,MF_BYCOMMAND,IDC_CHANGE, APL_T("Показать"));
	}

	CaplMenu::Install(this);
	ClientToScreen(&point);
  	BOOL res=pPopup->TrackPopupMenu(TPM_LEFTALIGN|
  		TPM_RIGHTBUTTON|TPM_RETURNCMD,point.x, point.y,this);
	//в зависимости от выбора строки контекстного меню :
	switch (res)
 	{
 		case IDC_ADD: OnAdd(pdr,start_value);break;
 		case IDC_DELETE:OnDelete(effItem);break;
  		case IDC_CHANGE:ShowEffProperties(effItem);break;
 		default:break;
	}
	
	CScrollView::OnRButtonDown(nFlags, point);
}

void CEffectivityView::OnAdd(CaplInstance *pdr,CString &start_value)
{
	if(!pdr) return;
	bool b_refresh_needed=false;
	if(m_eff_mode==APL_EFF_DATE)
	{
		//по дате
		CAddRuleDate dlg;
		dlg.m_data=&m_api->m_data;
		dlg.m_rel=pdr;
		dlg.m_PrMan=&m_api->m_prd_mgr;
		if(start_value!=_T(""))
		{
			aplString2Date(start_value,dlg.m_start_date);
		}
		if(dlg.DoModal()==IDOK) b_refresh_needed=true;
	}
	else
	{
		//по серийному номеру
		CAddSerialNum dlg;
		dlg.m_data=&m_api->m_data;
		dlg.m_PrMan=&m_api->m_prd_mgr;
		dlg.m_rel=pdr;
		dlg.m_start_sn=start_value;
		if(dlg.DoModal()==IDOK) b_refresh_needed=true;
	}
	if(b_refresh_needed) m_prd_view->UpdateDiagramSource();
}

void CEffectivityView::OnDelete(EffItem *effItem)
{
	if(!effItem) return;
	CString pde_id;
	m_api->m_data.GetAttrBN(effItem->m_eff,_T("id"),pde_id);
	if(pde_id==_T("")) pde_id= APL_T("< не задано >");
	CString buf;
	buf.Format( APL_T("Удаление правила применяемости\nОбозначение: %s\n\nВы уверены?"),pde_id);
	if(AfxMessageBox(buf, MB_YESNO|MB_ICONSTOP)==IDYES)
	{
		m_api->m_data.DeleteInstance(effItem->m_eff);
		m_prd_view->UpdateDiagramSource();
	}

}

void CEffectivityView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	int nItem=Point2PrdItem(point);
	if(nItem>-1) 
	{
		m_sel_nItem=nItem;
		CListCtrl &in_prd_ctrl=m_prd_view->GetListCtrl();
		in_prd_ctrl.SetItemState(m_sel_nItem,LVIS_SELECTED| LVIS_FOCUSED,LVIS_SELECTED| LVIS_FOCUSED);
		m_prd_view->OnSelChanged(false);
	}
	
	CScrollView::OnLButtonDown(nFlags, point);
}

int CEffectivityView::Point2PrdItem(CPoint point)
{
	CListCtrl &in_prd_ctrl=m_prd_view->GetListCtrl();
	int top_vis_index=in_prd_ctrl.GetTopIndex();
	CRect item_rect,cl_rect;
	in_prd_ctrl.GetClientRect(cl_rect);
	int i=top_vis_index;
	while(i<in_prd_ctrl.GetItemCount())
	{
		in_prd_ctrl.GetItemRect(i,item_rect,LVIR_BOUNDS);
		if(item_rect.bottom>cl_rect.bottom) 
			break;
		if(item_rect.top<=point.y && item_rect.bottom>=point.y)
			return i;
		i++;
	}
	return -1;
}

bool CEffectivityView::Point2Start(CPoint point,CString &start_value)
{
	start_value=_T("");
	CPoint abs_point=point;
	abs_point.x+=GetScrollPosition().x;

	for(int i=0;i<m_cal_rect_array.GetSize();i++)
	{
		if(m_cal_rect_array[i].PtInRect(abs_point))
		{
			start_value=m_eff_map.GetAt(i)->str;
			return true;
		}
	}
	return false;
}
