BOOL CBCGPPlannerViewMulti::SetCurrentResourceID (UINT nResourceID, 
												  BOOL bRedraw/* = TRUE*/, BOOL bNotify/* = FALSE*/)
{
	if (m_nResourceID != nResourceID)
	{
		m_nResourceID = nResourceID;

		if (bRedraw && GetPlanner()->GetSafeHwnd () != NULL)
		{
			GetPlanner()->RedrawWindow (NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
		}

		if (bNotify)
		{
			CBCGPPlannerManagerCtrl* pPlanner = GetPlanner ();

			if (pPlanner->IsNotifyParent () && pPlanner->GetSafeHwnd () != NULL)
			{
				pPlanner->GetParent ()->SendMessage (BCGP_PLANNER_RESOURCEID_CHANGED, 0, 0);
			}
		}
	}

	return TRUE;
}
BOOL CBCGPPlannerViewMulti::OnUpdateStorage ()
{
	if (GetPlanner () == NULL)
	{
		return FALSE;
	}

	CBCGPAppointmentBaseMultiStorage* pStorage = 
		(CBCGPAppointmentBaseMultiStorage*)GetPlanner ()->GetStorage ();

	CBCGPAppointmentBaseMultiStorage::XResourceIDArray ar;
	pStorage->GetResourceIDs (ar);

	const int count = (int) ar.GetSize ();
	ASSERT (count > 0);

	BOOL bRes = FALSE;

	if (count != m_Resources.GetSize ())
	{
		m_Resources.SetSize (count);
		bRes= TRUE;
	}

	for (int i = 0; i < count; i++)
	{
		XResource& resource = m_Resources[i];

		if (resource.m_ResourceID != ar[i])
		{
			resource.m_ResourceID = ar[i];
			bRes = TRUE;
		}

		const CBCGPAppointmentBaseResourceInfo* pInfo = pStorage->GetResourceInfo (ar[i]);

		if (pInfo != NULL)
		{
			if (resource.m_Description != pInfo->GetDescription ())
			{
				resource.m_Description = pInfo->GetDescription ();
				bRes = TRUE;
			}
			if (resource.m_WorkStart != pInfo->GetWorkStart ())
			{
				resource.m_WorkStart = pInfo->GetWorkStart ();
				bRes = TRUE;
			}
			if (resource.m_WorkEnd != pInfo->GetWorkEnd ())
			{
				resource.m_WorkEnd = pInfo->GetWorkEnd ();
				bRes = TRUE;
			}
		}
	}

	return bRes;
}
void CBCGPPlannerViewMonth::AddUpDownRect(BYTE nType, const CRect& rect)
{
	if (nType != 0)
	{
		CSize sz (GetPlanner ()->GetUpDownIconSize ());
		CRect rt (CPoint(rect.right - sz.cx, rect.bottom - sz.cy), sz);

		m_DownRects.Add (rt);
	}
}
CString CBCGPPlannerViewMulti::GetAccName() const
{
	CString strValue(CBCGPPlannerViewDay::GetAccName());

	const CBCGPAppointmentBaseMultiStorage* pStorage = 
		DYNAMIC_DOWNCAST(CBCGPAppointmentBaseMultiStorage, GetPlanner ()->GetStorage ());

	const CBCGPAppointmentBaseResourceInfo* pInfo = pStorage->GetResourceInfo (GetCurrentResourceID ());
	if (pInfo != NULL && !pInfo->GetDescription ().IsEmpty ())
	{
		strValue = pInfo->GetDescription () + _T(". ") + strValue;
	}

	return strValue;
}
void CBCGPPlannerViewMulti::OnDrawHeaderResource (CDC* pDC, const CRect& rectHeader)
{
	ASSERT_VALID (pDC);

	const int nDays = GetViewDuration ();

	DWORD dwFlags = GetPlanner ()->GetDrawFlags ();
	BOOL bBold = (dwFlags & BCGP_PLANNER_DRAW_VIEW_CAPTION_DAY_BOLD) ==
			BCGP_PLANNER_DRAW_VIEW_CAPTION_DAY_BOLD;

	HFONT hOldFont = NULL;
	if (bBold)
	{
		hOldFont = SetCurrFont (pDC, bBold);
	}

	for (int nDay = 0; nDay < nDays; nDay ++)
	{
		CRect rectCaption (rectHeader);
		rectCaption.left = m_ViewRects[nDay].left;
		rectCaption.right = m_ViewRects[nDay].right;

		DrawHeader (pDC, rectCaption, m_Resources [0].m_Rects[nDay].Width ());

		CRect rectResCaption (rectCaption);

		for (int i = 0; i < m_Resources.GetSize (); i++)
		{
			XResource& res = m_Resources[i];

			rectResCaption.left = res.m_Rects[nDay].left;
			rectResCaption.right = res.m_Rects[nDay].right;

			visualManager->PreparePlannerCaptionBackItem (TRUE);
			COLORREF clrText = OnFillPlannerCaption (
				pDC, rectResCaption, FALSE, FALSE, FALSE);

			DrawCaptionText (pDC, rectResCaption, res.m_Description, clrText, 
				res.m_bToolTipNeeded ? DT_LEFT : DT_CENTER);
		}
	}

	if (hOldFont != NULL)
	{
		::SelectObject (pDC->GetSafeHdc (), hOldFont);
	}
}
void CBCGPPlannerViewMonth::AdjustLayout (CDC* /*pDC*/, const CRect& /*rectClient*/)
{
	m_nHeaderHeight = m_nRowHeight;
	m_nWeekBarWidth = 0;

	if ((GetPlanner ()->GetDrawFlags () & BCGP_PLANNER_DRAW_VIEW_WEEK_BAR) ==
			BCGP_PLANNER_DRAW_VIEW_WEEK_BAR)
	{
		m_nWeekBarWidth = m_nHeaderHeight + 3;
	}

	m_rectApps.left += m_nWeekBarWidth;

	AdjustScrollSizes ();

	m_rectApps.top += m_nHeaderHeight;
}
void CBCGPPlannerViewMonth::OnDrawClient (CDC* pDC, const CRect& rect)
{
	ASSERT_VALID (pDC);

	CRect rectFill (rect);

	int nMonth = m_Date.GetMonth ();

	BOOL bIsWorking = nMonth % 2;

	const int nRows = GetViewDuration () / 7;

	COleDateTime day (GetDateStart ());

	COleDateTime dayCurrent = COleDateTime::GetCurrentTime ();
	dayCurrent.SetDateTime (dayCurrent.GetYear (), dayCurrent.GetMonth (), 
		dayCurrent.GetDay (), 0, 0, 0);

	int iRow = 0;

	int nStartColumn = 1;
	if (m_nWeekBarWidth != 0)
	{
		nStartColumn = 0;
	}

	{
		CPen penBlack (PS_SOLID, 0, visualManager->GetPlannerSeparatorColor (this));
		CPen* pOldPen = pDC->SelectObject (&penBlack);

		const int nEnd = 7;

		int nCol = 0;
		int iColumn = 1;

		for (iColumn = 1; iColumn < 7; iColumn++)
		{
			if (m_ViewRects [iColumn - 1].right == m_ViewRects [iColumn].right)
			{
				nCol = iColumn - 1;
				break;
			}
		}

		for (iColumn = nStartColumn; iColumn < nEnd; iColumn++)
		{
			pDC->MoveTo (m_ViewRects [iColumn].left - 1, rect.top);
			pDC->LineTo (m_ViewRects [iColumn].left - 1, rect.bottom);
		}

		for (iRow = 0; iRow < nRows; iRow++)
		{
			int nIndex = iRow * 7 + 6;

			pDC->MoveTo (rect.left , m_ViewRects [nIndex].bottom);
			pDC->LineTo (rect.right, m_ViewRects [nIndex].bottom);

			if (m_bCompressWeekend)
			{
				nIndex -= (6 - nCol);
				pDC->MoveTo (m_ViewRects [nIndex].left, m_ViewRects [nIndex].bottom);
				pDC->LineTo (m_ViewRects [nIndex].right, m_ViewRects [nIndex].bottom);
			}
		}

		pDC->SelectObject (pOldPen);
	}

	DWORD dwFlags = GetPlanner ()->GetDrawFlags ();
	BOOL bBold = (dwFlags & BCGP_PLANNER_DRAW_VIEW_CAPTION_DAY_BOLD) ==
			BCGP_PLANNER_DRAW_VIEW_CAPTION_DAY_BOLD;
	BOOL bCompact = (dwFlags & BCGP_PLANNER_DRAW_VIEW_CAPTION_DAY_COMPACT) ==
			BCGP_PLANNER_DRAW_VIEW_CAPTION_DAY_COMPACT;

	HFONT hOldFont = NULL;
	if (bBold)
	{
		hOldFont = SetCurrFont (pDC, bBold);
	}

	const BOOL bDateBeforeMonth = CBCGPPlannerView::IsDateBeforeMonth ();

	for (iRow = 0; iRow < nRows; iRow++)
	{
		for (int iDay = 0; iDay < 7; iDay++)
		{
			int nDay = iRow * 7 + iDay;

			CRect rectDayCaption (m_ViewRects [nDay]);

			BOOL bToday = day == dayCurrent;
			BOOL bSelected = IsDateInSelection (day);

			bIsWorking = day.GetMonth () % 2;

			visualManager->PreparePlannerBackItem (bToday, bSelected);
			OnFillPlanner (pDC, rectDayCaption, bIsWorking);

			rectDayCaption.bottom = rectDayCaption.top + m_nRowHeight + 1;

			CString strFormat (_T("d"));
			CString strDate;

			BOOL bNewYear = FALSE;

			if (!bCompact)
			{
				if ((iRow == 0 && iDay == 0) || day.GetDay () == 1)
				{
					if (bDateBeforeMonth)
					{
						strFormat = _T("d MMMM");
					}
					else
					{
						strFormat = _T("MMMM d");
					}

					if (day.GetDay () == 1 && day.GetMonth () == 1)
					{
						bNewYear = TRUE;
						strFormat += _T(" yyyy");
					}			
				}

				if (!strFormat.IsEmpty ())
				{
					strDate.GetBuffer (_MAX_PATH);

					SYSTEMTIME st;
					day.GetAsSystemTime (st);

					::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 
						strFormat, (LPTSTR)(LPCTSTR)strDate, _MAX_PATH);

					strDate.ReleaseBuffer ();

					CSize szSize (pDC->GetTextExtent (strDate));

					if (rectDayCaption.Width () - 4 < szSize.cx)
					{
						if (bDateBeforeMonth)
						{
							strFormat = _T("d MMM");
						}
						else
						{
							strFormat = _T("MMM d");
						}

						if (bNewYear)
						{
							strFormat += _T(" yy");
						}

						strDate.GetBuffer (_MAX_PATH);

						::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 
							strFormat, (LPTSTR)(LPCTSTR)strDate, _MAX_PATH);

						strDate.ReleaseBuffer ();
					}
				}
			}
			else
			{
				if ((iRow == 0 && iDay == 0) || day.GetDay () == 1)
				{
					if (bDateBeforeMonth)
					{
						strFormat = _T("d MMM");
					}
					else
					{
						strFormat = _T("MMM d");
					}

					if (day.GetDay () == 1 && day.GetMonth () == 1)
					{
						bNewYear = TRUE;
						strFormat += _T(" yy");
					}
				}

				if (!strFormat.IsEmpty ())
				{
					strDate.GetBuffer (_MAX_PATH);

					SYSTEMTIME st;
					day.GetAsSystemTime (st);

					::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 
						strFormat, (LPTSTR)(LPCTSTR)strDate, _MAX_PATH);

					strDate.ReleaseBuffer ();

					CSize szSize (pDC->GetTextExtent (strDate));

					if (rectDayCaption.Width () - 4 < szSize.cx)
					{
						strFormat = _T("d");
						BOOL bNeedFormat = TRUE;

						if (bNewYear)
						{
							if (bDateBeforeMonth)
							{
								strFormat += _T(" MMM");
							}
							else
							{
								strFormat = _T("MMM ") + strFormat;
							}

							bNeedFormat = FALSE;

							strDate.GetBuffer (_MAX_PATH);

							::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 
								strFormat, (LPTSTR)(LPCTSTR)strDate, _MAX_PATH);

							strDate.ReleaseBuffer ();

							szSize = pDC->GetTextExtent (strDate);

							if (rectDayCaption.Width () - 4 < szSize.cx)
							{
								strFormat = _T("d");
								bNeedFormat = TRUE;
							}
						}

						if (bNeedFormat)
						{
							strDate.GetBuffer (_MAX_PATH);

							::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 
								strFormat, (LPTSTR)(LPCTSTR)strDate, _MAX_PATH);

							strDate.ReleaseBuffer ();
						}
					}
				}
			}

			if (bToday)
			{
				rectDayCaption.bottom--;
			}

			visualManager->PreparePlannerCaptionBackItem (FALSE);
			COLORREF clrText = OnFillPlannerCaption (
				pDC, rectDayCaption, bToday, bSelected, FALSE);

			DrawCaptionText (pDC, rectDayCaption, strDate, clrText, bCompact ? DT_LEFT : DT_RIGHT,
				bToday && bSelected);

			day += COleDateTimeSpan (1, 0, 0, 0);
		}
	}

	if (hOldFont != NULL)
	{
		::SelectObject (pDC->GetSafeHdc (), hOldFont);
	}
}
BOOL CBCGPPlannerViewMonth::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
{
	if (m_pCapturedAppointment != NULL)
	{
		GetPlanner ()->SendMessage (WM_CANCELMODE, 0, 0);
		return TRUE;
	}

	BOOL isShiftPressed = (0x8000 & GetKeyState(VK_SHIFT)) != 0;

	BOOL bHandled = FALSE;

	if (nChar == VK_PRIOR || nChar == VK_NEXT) // Page Up, Page Down
	{
		OnVScroll (nChar == VK_PRIOR ? SB_PAGEUP : SB_PAGEDOWN, 0, NULL);

		SetSelection (m_Date, m_Date);

		bHandled = TRUE;
	}
	else if (nChar == VK_HOME || nChar == VK_END)
	{
		COleDateTime date
			(
				GetFirstWeekDay2 (m_Date, CBCGPPlannerManagerCtrl::GetFirstDayOfWeek () + 1)
			);

		if (nChar == VK_END)
		{
			date += COleDateTimeSpan (6, 0, 0, 0);
		}

		if (!isShiftPressed)
		{
			m_Date = date;
		}
		else
		{
			if (nChar == VK_HOME)
			{
				COleDateTime oldDate (m_Date);

				m_Date = date;
				date   = oldDate;
			}
			else
			{
				m_Date = m_Selection[1];
			}
		}

		SetSelection (m_Date, date);

		bHandled = TRUE;
	}
	else if (nChar == VK_UP || nChar == VK_DOWN || nChar == VK_LEFT || nChar == VK_RIGHT)
	{
		COleDateTime date (m_Selection [1]);

		COleDateTimeSpan span (1, 0, 0 ,0);

		if (nChar == VK_LEFT)
		{
			date -= span;
		}
		else if (nChar == VK_RIGHT)
		{
			date += span;
		}
		else
		{
			span = COleDateTimeSpan (7, 0, 0 ,0);

			if (nChar == VK_UP)
			{
				date -= span;
			}
			else if (nChar == VK_DOWN)
			{
				date += span;
			}
		}

		BOOL bScroll = FALSE;

		if (date < m_DateStart)
		{
			OnVScroll (SB_LINEUP, 0, NULL);
			bScroll = TRUE;
		}
		else if (date >= (m_DateStart + COleDateTimeSpan (GetViewDuration (), 0, 0, 0)))
		{
			OnVScroll (SB_LINEDOWN, 0, NULL);
			bScroll = TRUE;
		}

		if (!isShiftPressed || bScroll)
		{
			m_Date = date;
			SetSelection (m_Date, m_Date);
		}
		else
		{
			SetSelection (m_Selection [0], date);

			if (date <= m_Date)
			{
				m_Date = date;
			}
		}

		bHandled = TRUE;
	}

	return bHandled;
}
void CBCGPPlannerViewMulti::OnDrawAppointmentsDuration (CDC* pDC)
{
	if ((GetPlanner ()->GetDrawFlags () & BCGP_PLANNER_DRAW_VIEW_NO_DURATION) == 
			BCGP_PLANNER_DRAW_VIEW_NO_DURATION)
	{
		return;
	}

	XBCGPAppointmentArray& arQueryApps = GetQueryedAppointments ();
	XBCGPAppointmentArray& arDragApps  = GetDragedAppointments ();

	if (arQueryApps.GetSize () == 0 && arDragApps.GetSize () == 0)
	{
		return;
	}

	BOOL bDragDrop        = IsDragDrop ();
	DROPEFFECT dragEffect = GetDragEffect ();
	BOOL bDragMatch       = IsCaptureMatched ();

	COleDateTime dtS = GetDateStart ();
	COleDateTime dtE = GetDateEnd ();

	const int nMinuts = CBCGPPlannerView::GetTimeDeltaInMinuts (GetTimeDelta ());
	const int nCount = GetViewHours() * 60 / nMinuts;
	const int yOffset = GetViewHourOffset () * m_nRowHeight;

	for (int nApp = 0; nApp < 2; nApp++)
	{
		XBCGPAppointmentArray& arApps = nApp == 1 ? arDragApps : arQueryApps;

		if (nApp == 1)
		{
			bDragDrop = bDragDrop && arDragApps.GetSize ();
		}

		if (arApps.GetSize () == 0)
		{
			continue;
		}

		for (int i = 0; i < arApps.GetSize (); i++)
		{
			CBCGPAppointment* pApp = arApps [i];
			if (pApp == NULL || !(pApp->IsAllDay () || pApp->IsMultiDay ()) || 
				pApp->GetDurationColor () == CLR_DEFAULT)
			{
				continue;
			}

			BOOL bDraw = FALSE;

			if (bDragDrop && dragEffect != DROPEFFECT_NONE && 
				pApp->IsSelected () && nApp == 0)
			{
				if ((dragEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY || bDragMatch)
				{
					bDraw = TRUE;
				}
			}
			else
			{
				bDraw = TRUE;
			}

			if(!bDraw)
			{
				continue;
			}

			int nResourceIndex = FindResourceIndexByID (pApp->GetResourceID ());
			ASSERT(nResourceIndex != -1);
			XResource& resource = m_Resources[nResourceIndex];

			COleDateTime dtStart  = pApp->GetStart ();
			COleDateTime dtFinish = pApp->GetFinish ();

			dtStart.SetDate (dtStart.GetYear (), dtStart.GetMonth (), dtStart.GetDay ());
			dtFinish.SetDate (dtFinish.GetYear (), dtFinish.GetMonth (), dtFinish.GetDay ());

			BOOL bStart = FALSE;
			BOOL bEnd   = FALSE;

			if (dtStart < dtS)
			{
				dtStart = dtS;
				bStart  = TRUE;
			}

			if (dtE < dtFinish)
			{
				dtFinish = dtE;
				bEnd     = TRUE;
			}

			COleDateTimeSpan span (dtFinish - dtStart);

			int nStart = (dtStart - dtS).GetDays ();
			int nEnd   = min(nStart + span.GetDays () + 1, GetViewDuration ());

			CBrush br (pApp->GetDurationColor () == CLR_DEFAULT
				? globalData.clrWindow
				: pApp->GetDurationColor ());

			for(int i = nStart; i < nEnd; i++)
			{
				CRect rt (resource.m_Rects[i]);

				rt.right  = rt.left + 
					CBCGPPlannerViewMulti::BCGP_PLANNER_DURATION_BAR_WIDTH + 1;		
				rt.left  -= (i == 0) ? 1 : 0;
				rt.top   -= 1;
				rt.bottom = rt.top + nCount * m_nRowHeight;
				rt.DeflateRect (1, 0);
				
				if (!pApp->IsAllDay ())
				{
					rt.OffsetRect (0, -yOffset);

					if (i == (nEnd - 1) && !bEnd)
					{
						dtFinish = pApp->GetFinish ();
						const double dDelta = (dtFinish.GetHour () * 60 + dtFinish.GetMinute ()) / (double)nMinuts;

						rt.bottom = rt.top + CBCGPPlannerView::round(dDelta * m_nRowHeight);
					}

					if (i == nStart && !bStart)
					{
						dtStart  = pApp->GetStart ();
						const double dDelta = 
							(dtStart.GetHour () * 60 + dtStart.GetMinute ()) / (double)nMinuts;

						rt.top += CBCGPPlannerView::round(dDelta * m_nRowHeight);
					}

					rt.IntersectRect (rt, resource.m_Rects[i]);
				}

				pDC->FillRect (rt, &br);
			}
		}
	}
}
void CBCGPPlannerViewMulti::AdjustAppointments ()
{
	XBCGPAppointmentArray& arQueryApps = GetQueryedAppointments ();
	XBCGPAppointmentArray& arDragApps = GetDragedAppointments ();

	const int nDays = GetViewDuration ();

	if ((arQueryApps.GetSize () == 0 && arDragApps.GetSize () == 0) || 
		m_ViewRects.GetSize () != nDays)
	{
		ClearVisibleUpDownIcons ();
		return;
	}

	BOOL bDrawShadow = IsDrawAppsShadow ();

	BOOL bDragDrop        = IsDragDrop ();
	DROPEFFECT dragEffect = GetDragEffect ();
	BOOL bDragMatch       = IsCaptureMatched ();

	bDragDrop = !bDragDrop || 
		(bDragDrop && ((dragEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY && bDragMatch) || 
		!bDragMatch);
	bDragDrop = bDragDrop && arDragApps.GetSize ();

	const int nTimeDelta = CBCGPPlannerView::GetTimeDeltaInMinuts (GetTimeDelta ());
	const int yOffset = GetViewHourOffset () * m_nRowHeight;
	const int yHeaderOffset = m_nHeaderScrollOffset * (m_nRowHeight + s_HeaderAllDayPadding);

	COleDateTime date (m_DateStart);

	for (int nApp = 0; nApp < 2; nApp++)
	{
		if (!bDragDrop && nApp == 0)
		{
			continue;
		}

		XBCGPAppointmentArray& arApps = nApp == 0 ? arDragApps : arQueryApps;

		for (int i = 0; i < arApps.GetSize (); i++)
		{
			CBCGPAppointment* pApp = arApps[i];
			ASSERT_VALID (pApp);

			pApp->ResetDraw ();
			pApp->GetDSDraw ().SetConcatenate (FALSE);
		}
	}

	COleDateTimeSpan spanDay (1, 0, 0, 0);

	int nDay = 0;

	const BOOL bNoDuration = 
		(GetPlanner ()->GetDrawFlags () & BCGP_PLANNER_DRAW_VIEW_NO_DURATION) == 
		BCGP_PLANNER_DRAW_VIEW_NO_DURATION;

	for (int nRes = 0; nRes < m_Resources.GetSize (); nRes++)
	{
		XResource& resource = m_Resources[nRes];

		date = m_DateStart;

		for (nDay = 0; nDay < nDays; nDay ++)
		{
			XBCGPAppointmentArray arAllDays;

			for (int nApp = 0; nApp < 2; nApp++)
			{
				if (!bDragDrop && nApp == 1)
				{
					continue;
				}

				XBCGPAppointmentArray& arApps = nApp == 1 ? arDragApps : arQueryApps;

				XBCGPAppointmentArray arByDate;

				int i;

				CRect rectFill (resource.m_Rects[nDay]);
				rectFill.top -= yOffset;

				if (bNoDuration && nDay > 0)
				{
					rectFill.left++;
				}

				int nStartIndex = 0;
				for (i = 0; i < arApps.GetSize (); i++)
				{
					const CBCGPAppointment* pApp = arApps[i];
					if (pApp != NULL && pApp->GetResourceID () == resource.m_ResourceID)
					{
						nStartIndex = i;
						break;
					}
				}

				for (i = nStartIndex; i < arApps.GetSize (); i++)
				{
					CBCGPAppointment* pApp = arApps[i];
					ASSERT_VALID (pApp);

					if (pApp->GetResourceID () != resource.m_ResourceID)
					{
						break;
					}

					if (CBCGPPlannerView::IsAppointmentInDate (*pApp, date))
					{
						CRect rtApp (rectFill);

						// trimming top and bottom edge, starting from TimeDelta and Appointment interval
						rtApp.top = rectFill.top + m_nRowHeight * 
							long((pApp->GetStart ().GetHour () * 60 + 
								 pApp->GetStart ().GetMinute ()) / nTimeDelta) - 1;

						if (pApp->IsAllDay () || pApp->IsMultiDay ())
						{
							BOOL bAdd = TRUE;

							for (int i = 0; i < arAllDays.GetSize (); i++)
							{
								if (arAllDays[i] == pApp)
								{
									bAdd = FALSE;
									break;
								}
							}

							if (bAdd)
							{
								arAllDays.Add (pApp);
							}
						}
						else
						{
							rtApp.right -= 2 * BCGP_PLANNER_APPOINTMENT_SPACE;

							if (pApp->GetStart () != pApp->GetFinish ())
							{
								COleDateTime dtAF (pApp->GetFinish ());
								int minutes = dtAF.GetHour () * 60 + dtAF.GetMinute ();

								if (!IsOneDay (pApp->GetStart (), dtAF))
								{
									BOOL bStartDay   = IsOneDay (date, pApp->GetStart ());
									BOOL bFinishNULL = dtAF.GetHour () == 0 && 
													   dtAF.GetMinute () == 0;

									if (bStartDay)
									{
										minutes = 24 * 60;
									}

									if (bFinishNULL)
									{
										if (!bStartDay)
										{
											if (pApp->GetDSDraw ().GetCount () == 1)
											{
												pApp->GetDSDraw ()[0].m_date2 = date;
												continue;
											}
										}
									}
									else
									{
										if (!bStartDay)
										{
											rtApp.top = rectFill.top - 1;
										}
									}
								}

								rtApp.bottom = rectFill.top + m_nRowHeight * 
									(long)ceil(minutes / (double)nTimeDelta) - 1;
							}
							else
							{
								rtApp.bottom = rtApp.top + m_nRowHeight;
							}

							pApp->SetRectDraw (rtApp, date);
							arByDate.Add (pApp);
						}
					}
				}

				// resort appointments in the view, if count of collection is great than 1
				if (arByDate.GetSize () > 1)
				{
					XBCGPAppointmentArray* ar = new XBCGPAppointmentArray;

					// array, that contains columns
					CArray<XBCGPAppointmentArray*, XBCGPAppointmentArray*> arColumns;
					arColumns.Add (ar);

					// initialize first column
					ar->Copy (arByDate);

					while (ar != NULL)
					{
						CBCGPAppointment* pApp1 = ar->GetAt (0);

						XBCGPAppointmentArray* arNew = NULL;

						i = 1;

						// remove appointments, that have collisions in rects, from previous column 
						// to the next column
						while (i < ar->GetSize ())
						{
							CBCGPAppointment* pApp2 = ar->GetAt (i);

							CRect rtInter;
							if (rtInter.IntersectRect (pApp1->GetRectDraw (date), pApp2->GetRectDraw (date)))
							{
								if (arNew == NULL)
								{
									// add a new column
									arNew = new XBCGPAppointmentArray;
									arColumns.Add (arNew);
								}

								arNew->Add (pApp2);
								ar->RemoveAt (i);
							}
							else
							{
								pApp1 = pApp2;
								i++;
							}
						}

						ar = arNew;
					}

					int nCount = (int) arColumns.GetSize ();

					// reinitialize drawing rects, if found great than 1 columns
					if (nCount > 1)
					{
						int nWidth = rectFill.Width () / nCount;
						int nL = rectFill.left;

						// left border of appointments, based on column order
						for (i = 0; i < nCount; i++)
						{
							ar = arColumns[i];

							for (int j = 0; j < ar->GetSize (); j++)
							{
								CBCGPAppointment* pApp = ar->GetAt (j);
								ASSERT_VALID (pApp);

								CRect rtApp (pApp->GetRectDraw (date));
								rtApp.left = nL;

								pApp->SetRectDraw (rtApp, date);
							}

							nL += nWidth;
						}

						// correcting right border of appointments
						for (i = 0; i < nCount; i++)
						{
							ar = arColumns[i];

							for (int j = 0; j < ar->GetSize (); j++)
							{
								CBCGPAppointment* pApp = ar->GetAt (j);
								CRect rtApp (pApp->GetRectDraw (date));

								for (int k = i + 1; k < nCount; k++)
								{
									XBCGPAppointmentArray* arNext = arColumns[k];

									for (int m = 0; m < arNext->GetSize (); m++)
									{
										CBCGPAppointment* pAppNext = arNext->GetAt (m);
									
										CRect rtInter;
										if (rtInter.IntersectRect (rtApp, pAppNext->GetRectDraw (date)))
										{
											rtApp.right = rectFill.left + nWidth * k - 
												(bDrawShadow ? BCGP_PLANNER_APPOINTMENT_SPACE : 0);
											pApp->SetRectDraw (rtApp, date);
											break;
										}
									}
								}
							}
						}
					}

					// clean up columns array
					for (i = 0; i < nCount; i++)
					{
						delete arColumns[i];
					}

					arColumns.RemoveAll ();
				}
			}

			// adjust "all day" or "multi day" appointments
			if (arAllDays.GetSize () > 0)
			{
				const int c_Count = (int) arAllDays.GetSize ();

				CRect rectFill (0, 0, 0, 0);

				rectFill.top    = m_nHeaderHeight + 1 - yHeaderOffset;
				rectFill.bottom = rectFill.top + m_nRowHeight;

				int i = 0;

				for (i = 0; i < c_Count; i++)
				{
					CBCGPAppointment* pApp = arAllDays[i];

					rectFill.left  = resource.m_Rects [nDay].left;
					rectFill.right = resource.m_Rects [nDay].right;

					if (CBCGPPlannerView::IsAppointmentInDate (*pApp, date))
					{
						pApp->SetRectDraw (rectFill, date);
					}
				}

				for (i = 1; i < c_Count; i++)
				{
					CBCGPAppointment* pApp1 = arAllDays[i];

					CRect rtApp1;
					if (pApp1->GetDSDraw ().IsEmpty ())
					{
						rtApp1 = pApp1->GetRectDraw ();
					}
					else
					{
						rtApp1 = pApp1->GetDSDraw ().Get (date)->GetRect ();
					}

					for (int j = 0; j < i; j++)
					{
						CBCGPAppointment* pApp2 = arAllDays[j];

						CRect rtApp2;
						if (pApp2->GetDSDraw ().IsEmpty ())
						{
							rtApp2 = pApp2->GetRectDraw ();
						}
						else
						{
							rtApp2 = pApp2->GetDSDraw ().Get (date)->GetRect ();
						}

						CRect rtInter;
						if (rtInter.IntersectRect (rtApp1, rtApp2))
						{
							rtApp1.top    = rtApp2.top;
							rtApp1.bottom = rtApp2.bottom;
							rtApp1.OffsetRect (0, m_nRowHeight + 2);
							
							if (pApp1->GetDSDraw ().IsEmpty ())
							{
								pApp1->SetRectDraw (rtApp1);
							}
							else
							{
								pApp1->GetDSDraw ().Get (date)->SetRect (rtApp1);
							}

							j = 0;
						}
					}
				}
			}

			date += spanDay;
		}
	}	

	date = m_DateStart;

	for (nDay = 0; nDay < nDays; nDay ++)
	{
		CheckVisibleAppointments (date, m_rectApps, FALSE);

		date += spanDay;
	}

	CheckVisibleUpDownIcons(FALSE);

	m_bUpdateToolTipInfo = TRUE;
}
void CBCGPPlannerViewMulti::AdjustLayout (CDC* /*pDC*/, const CRect& rectClient)
{
	if (IsCurrentTimeVisible ())
	{
		StartTimer (FALSE);
	}
	else
	{
		StopTimer (FALSE);
	}

	m_nHeaderHeight       = 2;
	m_nHeaderAllDayHeight = 1;

	const int nMinuts = CBCGPPlannerView::GetTimeDeltaInMinuts (GetTimeDelta ());
	const int nCount = GetViewHours() * 60 / nMinuts;

	m_rectTimeBar = rectClient;
	m_rectTimeBar.right = m_rectTimeBar.left + (long)(m_nRowHeight * (nMinuts == 60 ? 2.5 : 3.0)) + 5;

	m_rectApps.left = m_rectTimeBar.right;

	{
		// finding allday or multiday events
		const int nDays = GetViewDuration ();

		CDWordArray arDays;
		arDays.SetSize (nDays);

		COleDateTime dtS = GetDateStart ();

		XBCGPAppointmentArray& arQueryApps = GetQueryedAppointments ();
		XBCGPAppointmentArray& arDragApps  = GetDragedAppointments ();

		BOOL bDragDrop        = IsDragDrop ();
		DROPEFFECT dragEffect = GetDragEffect ();
		BOOL bDragMatch       = IsCaptureMatched ();

		bDragDrop = !bDragDrop || 
			(bDragDrop && ((dragEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY && bDragMatch) || 
			!bDragMatch);
		bDragDrop = bDragDrop && arDragApps.GetSize ();

		DWORD maxCount = 0;

		for (int nRes = 0; nRes < m_Resources.GetSize (); nRes++)
		{
			UINT nResourceID = m_Resources[nRes].m_ResourceID;

			for (int nApp = 0; nApp < 2; nApp++)
			{
				if (!bDragDrop && nApp == 0)
				{
					continue;
				}

				XBCGPAppointmentArray& arApps = nApp == 0 ? arDragApps : arQueryApps;

				int nStartIndex = 0;
				int i = 0;
				for (i = 0; i < arApps.GetSize (); i++)
				{
					const CBCGPAppointment* pApp = arApps[i];
					if (pApp != NULL && pApp->GetResourceID () == nResourceID)
					{
						nStartIndex = i;
						break;
					}
				}

				for (i = nStartIndex; i < (int)arApps.GetSize (); i++)
				{
					const CBCGPAppointment* pApp = arApps[i];
					if (pApp == NULL)
					{
						continue;
					}

					ASSERT_VALID (pApp);

					if (pApp->GetResourceID () != nResourceID)
					{
						break;
					}

					if (pApp->IsAllDay () || pApp->IsMultiDay ())
					{
						if (nDays > 1)
						{
							COleDateTime dtStart  = pApp->GetStart ();
							COleDateTime dtFinish = pApp->GetFinish ();

							dtStart = COleDateTime (dtStart.GetYear (), dtStart.GetMonth (), dtStart.GetDay (),
								0, 0, 0);

							if (pApp->IsAllDay ())
							{
								dtFinish += COleDateTimeSpan (1, 0, 0, 0);
							}
							else if (pApp->GetFinish ().GetHour () != 0 ||
									 pApp->GetFinish ().GetMinute () != 0)
							{
								dtFinish = COleDateTime (dtFinish.GetYear (), dtFinish.GetMonth (), dtFinish.GetDay (),
									0, 0, 0);
								dtFinish += COleDateTimeSpan (1, 0, 0, 0);
							}

							if (dtStart < dtS)
							{
								dtStart = dtS;
							}

							COleDateTimeSpan span (dtFinish - dtStart);

							int nStart = (dtStart - dtS).GetDays ();
							int nEnd   = nStart + span.GetDays ();

							if (nEnd > (int) nDays)
							{
								nEnd = (int) nDays;
							}

							for (int j = nStart; j < nEnd; j++)
							{
								arDays[j] = arDays[j] + 1;
							}
						}
						else
						{
							arDays[0] = arDays[0] + 1;
						}
					}
				}
			}

			for (int i = 0; i < nDays; i++)
			{
				if (maxCount < arDays[i])
				{
					maxCount = arDays[i];
				}

				arDays[i] = 0;
			}
		}	

		if (maxCount > 0)
		{
			m_nHeaderAllDayHeight = maxCount;
		}
	}

	int nRow = rectClient.Height () / 
		(nCount + m_nHeaderHeight + m_nHeaderAllDayHeight);

	int nOldRowHeight = m_nRowHeight;

	if (nRow > m_nRowHeight)
	{
		m_nRowHeight = nRow;
	}

	const int nRowHeightPadding = m_nRowHeight + s_HeaderAllDayPadding;
	int nHeaderAllDayCount = m_nHeaderAllDayHeight;
	m_nHeaderHeight       *= m_nRowHeight;
	m_nHeaderAllDayHeight *= nRowHeightPadding;

	m_rectApps.top += m_nHeaderHeight;

	m_nHeaderScrollTotal = 0;
	m_nHeaderScrollPage  = 1;

	if (GetPlanner()->IsHeaderScrollingEnabled() && 
		nHeaderAllDayCount > 0 && m_nHeaderAllDayHeight > m_rectApps.Height () / 2)
	{
		m_nHeaderAllDayHeight = min(m_rectApps.Height () / (nRowHeightPadding * 2), nHeaderAllDayCount);
		if (m_nHeaderAllDayHeight == 0)
		{
			m_nHeaderAllDayHeight = 1;
		}

		if (m_nHeaderAllDayHeight != nHeaderAllDayCount)
		{
			m_nHeaderScrollTotal = nHeaderAllDayCount - 1;
			m_nHeaderScrollPage  = m_nHeaderAllDayHeight;
		}

		m_nHeaderAllDayHeight *= nRowHeightPadding;
	}

	nRow = (m_rectApps.Height () - m_nHeaderAllDayHeight) / nCount;

	if (nRow > nOldRowHeight)
	{
		m_nRowHeight = nRow;
	}

	int delta = m_rectApps.Height () - m_nHeaderAllDayHeight;

	if (delta < 0)
	{
		m_nHeaderAllDayHeight = m_rectApps.Height ();
	}
	else
	{
		int nc = (int)(delta / m_nRowHeight);

		if (nc >= nCount)
		{
			m_nHeaderAllDayHeight = m_rectApps.Height () - nCount * m_nRowHeight;
		}
		else
		{
			m_nHeaderAllDayHeight += delta - nc * m_nRowHeight;
		}
	}

	m_rectApps.top += m_nHeaderAllDayHeight;

	AdjustScrollSizes ();
	
	// correct selection
	COleDateTime sel1 (GetSelectionStart ());
	COleDateTime sel2 (GetSelectionEnd ());

	SetSelection (sel1, sel2, FALSE);
}
int CBCGPPlannerViewWorkWeek::GetWorkWeekInterval () const
{
	ASSERT_VALID(GetPlanner ());
	return GetPlanner ()->GetWorkWeekInterval ();
}
void CBCGPPlannerViewMulti::OnDrawClient (CDC* pDC, const CRect& rect)
{
	ASSERT_VALID (pDC);

	CRect rectFill (rect);

//	const int nWeekStart = CBCGPPlannerManagerCtrl::GetFirstDayOfWeek () + 1;
	const int yOffset = m_nScrollOffset * m_nRowHeight;

	int nFirstWorkingHour   = GetFirstWorkingHour ();
	int nFirstWorkingMinute = GetFirstWorkingMinute ();
	int nLastWorkingHour    = GetLastWorkingHour ();
	int nLastWorkingMinute  = GetLastWorkingMinute ();

	const int nDays = GetViewDuration ();
	const int nRes  = (int) m_Resources.GetSize ();

	rectFill.OffsetRect (0, -yOffset);

	const int nMinuts = CBCGPPlannerView::GetTimeDeltaInMinuts (GetTimeDelta ());
	const int nCount = 60 / nMinuts;

	CPen     penHour[2];
	CPen     penHalfHour[2];

	for (int i = 0; i < 2; i++)
	{
		penHour[i].CreatePen (PS_SOLID, 0,
			GetHourLineColor (i == 0 /* Working */, TRUE));

		penHalfHour[i].CreatePen (PS_SOLID, 0, 
			GetHourLineColor (i == 0 /* Working */, FALSE));
	}

	XBCGPPlannerWorkingParameters WorkingParameters(this);
	COLORREF DefaultWorkingColorFill = visualManager->GetPlannerWorkColor ();

	OnFillPlanner (pDC, rect, FALSE /* Non-working */);

	CBrush brHilite (visualManager->GetPlannerSelectionColor (this));

	CPen penBlack (PS_SOLID, 0, visualManager->GetPlannerSeparatorColor (this));
	CPen* pOldPen = pDC->SelectObject (&penBlack);

	const int iStart = GetViewHourOffset();
	const int iEnd   = min (iStart + rect.Height () / m_nRowHeight, nCount * 24);

	COleDateTime dtStart (GetDateStart ());

	BOOL bShowSelection = !((m_Selection[0].GetHour ()   == 0 &&
							 m_Selection[0].GetMinute () == 0 &&
							 m_Selection[0].GetSecond () == 0 &&
							 m_Selection[1].GetHour ()   == 23 &&
							 m_Selection[1].GetMinute () == 59 &&
							 m_Selection[1].GetSecond () == 59) ||
							(m_Selection[1].GetHour ()   == 0 &&
							 m_Selection[1].GetMinute () == 0 &&
							 m_Selection[1].GetSecond () == 0 &&
							 m_Selection[0].GetHour ()   == 23 &&
							 m_Selection[0].GetMinute () == 59 &&
							 m_Selection[0].GetSecond () == 59));

	BOOL bIsDrawDuration = 
		(GetPlanner ()->GetDrawFlags () & BCGP_PLANNER_DRAW_VIEW_NO_DURATION) == 0;
	const int nDurationWidth = bIsDrawDuration ? BCGP_PLANNER_DURATION_BAR_WIDTH + 1 : 0;

	visualManager->PreparePlannerBackItem (FALSE, FALSE);

	const UINT nResourceID = GetCurrentResourceID ();

	int nDay = 0;
	for (nDay = 0; nDay < nDays; nDay++)
	{
		int nWD = dtStart.GetDayOfWeek ();
		BOOL bWeekEnd = nWD == 1 || nWD == 7;

		for (int i = 0; i < nRes; i++)
		{
			XResource& res = m_Resources[i];

			int nFirstHour   = nFirstWorkingHour;
			int nFirstMinute = nFirstWorkingMinute;
			int nLastHour    = nLastWorkingHour;
			int nLastMinute  = nLastWorkingMinute;

			if (res.m_WorkStart < res.m_WorkEnd)
			{
				nFirstHour   = res.m_WorkStart.GetHour ();
				nFirstMinute = res.m_WorkStart.GetMinute ();
				nLastHour    = res.m_WorkEnd.GetHour ();
				nLastMinute  = res.m_WorkEnd.GetMinute ();
			}

			int iWorkStart = nFirstHour * nCount + (int)(nFirstMinute / nMinuts);
			int iWorkEnd   = nLastHour * nCount + (int)(nLastMinute / nMinuts);

			rectFill = res.m_Rects[nDay];

			rectFill.left   += nDurationWidth;
			rectFill.bottom = rectFill.top + m_nRowHeight - 1;

			BCGP_PLANNER_WORKING_STATUS AllPeriodWorkingStatus = 
				GetWorkingPeriodParameters (res.m_ResourceID, dtStart + COleDateTimeSpan (0, 0, iStart * nMinuts, 0), dtStart + COleDateTimeSpan (0, 0, (iEnd * nMinuts) - 1, 59), WorkingParameters); 
			BCGP_PLANNER_WORKING_STATUS SpecificPeriodWorkingStatus = AllPeriodWorkingStatus; 

			for (int iStep = iStart; iStep < iEnd; iStep++)
			{
				BOOL bIsWork = TRUE;
				if (AllPeriodWorkingStatus == BCGP_PLANNER_WORKING_STATUS_UNKNOWN)
				{ // We don't know for the day -> we should see for the period
					COleDateTime CurrentPeriodStart = dtStart + COleDateTimeSpan (0, 0, iStep * nMinuts, 0);
					COleDateTime CurrentPeriodEnd = CurrentPeriodStart + COleDateTimeSpan (0, 0, nMinuts - 1, 59);
					SpecificPeriodWorkingStatus = GetWorkingPeriodParameters (res.m_ResourceID, CurrentPeriodStart, CurrentPeriodEnd, WorkingParameters); 
				}

				switch (SpecificPeriodWorkingStatus)
				{
				case BCGP_PLANNER_WORKING_STATUS_ISNOTWORKING: // not a working period
					bIsWork = FALSE;
					break;
				case BCGP_PLANNER_WORKING_STATUS_ISWORKING: // forced to be a working period (we do not control working hours)
					bIsWork = TRUE;
					break;
				case BCGP_PLANNER_WORKING_STATUS_ISNORMALWORKINGDAY: // regular working day without control of week-end (so it may be a week-end day !)
					bIsWork = (iWorkStart <= iStep && iStep < iWorkEnd);
					break;
				case BCGP_PLANNER_WORKING_STATUS_ISNORMALWORKINGDAYINWEEK: // regular working day in a week (the week end is not a working day)
				default: // could not determine if period is working or not so we calculate as "standard"
					bIsWork = !bWeekEnd && (iWorkStart <= iStep && iStep < iWorkEnd);
				}

				if (!IsDateInSelection (dtStart + 
					COleDateTimeSpan (0, (iStep * nMinuts) / 60, (iStep * nMinuts) % 60, 0)) ||
					!bShowSelection || res.m_ResourceID != nResourceID)
				{
					if (bIsWork)
					{
						if (WorkingParameters.m_clrWorking != CLR_DEFAULT)
						{
							CBrush brush(WorkingParameters.m_clrWorking);
							pDC->FillRect (rectFill, &brush);
						}
						else
						{
							OnFillPlanner (pDC, rectFill, TRUE /* Working */);
						}
					}
					else
					{ // IF non working color is different from default non working color -> we should draw it with new color..
						if ((WorkingParameters.m_clrNonWorking != CLR_DEFAULT) && 
							(WorkingParameters.m_clrNonWorking != DefaultWorkingColorFill))
						{
							CBrush brush(WorkingParameters.m_clrNonWorking);
							pDC->FillRect (rectFill, &brush);
						}
					}
				}
				else
				{
					pDC->FillRect (rectFill, &brHilite);
				}

				int nPenIndex = bIsWork ? 0 : 1;

				pDC->SelectObject (((iStep + 1) % nCount == 0) ? 
					&penHour [nPenIndex] : &penHalfHour [nPenIndex]);

				pDC->MoveTo (rectFill.left, rectFill.bottom);
				pDC->LineTo (rectFill.right, rectFill.bottom);

				rectFill.OffsetRect (0, m_nRowHeight);
			}
		}	

		dtStart += COleDateTimeSpan (1, 0, 0, 0);
	}

	pDC->SelectObject (&penBlack);

	if (bIsDrawDuration)
	{
		for (nDay = 0; nDay < nDays; nDay++)
		{
			for (int i = 0; i < nRes; i++)
			{
				CRect rectDurBar (m_Resources[i].m_Rects[nDay]);
				rectDurBar.right = rectDurBar.left + BCGP_PLANNER_DURATION_BAR_WIDTH;

				// Draw duration bar (at left):
				pDC->FillRect (rectDurBar, &globalData.brWindow);

				if (nDay > 0 || i > 0)
				{
					pDC->MoveTo (rectDurBar.left, rectDurBar.top);
					pDC->LineTo (rectDurBar.left, rectDurBar.bottom);
				}

				pDC->MoveTo (rectDurBar.right, rectDurBar.top);
				pDC->LineTo (rectDurBar.right, rectDurBar.bottom);
			}	
		}
	}
	else
	{
		for (nDay = 0; nDay < nDays; nDay++)
		{
			for (int i = 0; i < nRes; i++)
			{
				CRect rectDurBar (m_Resources[i].m_Rects[nDay]);

				if (nDay > 0 || i > 0)
				{
					pDC->MoveTo (rectDurBar.left, rectDurBar.top);
					pDC->LineTo (rectDurBar.left, rectDurBar.bottom);
				}
			}
		}
	}

	pDC->SelectObject (pOldPen);
}