void CBCGPPlannerViewMonth::OnDrawWeekBar (CDC* pDC, const CRect& rectBar)
{
	if (rectBar.IsRectEmpty ())
	{
		return;
	}

	ASSERT_VALID (pDC);

	visualManager->PreparePlannerCaptionBackItem (FALSE);
	visualManager->OnFillPlannerWeekBar (pDC, this, rectBar);

	COLORREF clrLine = visualManager->GetPlannerSeparatorColor (this);

	const int nRows = GetViewDuration () / 7;

	const BOOL bDateBeforeMonth = CBCGPPlannerView::IsDateBeforeMonth ();

	CStringArray saFormat;
	{
		CString strMonthFmt (_T("MMM"));
		CString strSep (_T(" "));

		HFONT hOldFont = (HFONT)::SelectObject (pDC->GetSafeHdc (), GetFont ());

		CSize szText (pDC->GetTextExtent (_T("AAA 00 - AAA 00")));

		CRect rect (m_WeekRects[0]);
		if (rect.Height() < (szText.cx * 1.5))
		{
			strMonthFmt = _T("M");
			strSep      = CBCGPPlannerView::GetDateSeparator ();
		}

		if (hOldFont != NULL)
		{
			::SelectObject (pDC->GetSafeHdc (), hOldFont);
		}

		CString strFormat;
		if (bDateBeforeMonth)
		{
			strFormat = _T("d") + strSep + strMonthFmt;
			saFormat.Add (_T("d"));
			saFormat.Add (strFormat);
			saFormat.Add (strFormat);
		}
		else
		{
			strFormat = strMonthFmt + strSep + _T("d");
			saFormat.Add (strFormat);
			saFormat.Add (_T("d"));
			saFormat.Add (strFormat);
		}
	}

	COLORREF clrTextOld = pDC->GetTextColor ();
	HFONT hOldFont = (HFONT)::SelectObject (pDC->GetSafeHdc (), GetFontVert ());

	COleDateTime day1 (GetDateStart ());
	COleDateTime day2 (day1);
	day2 += COleDateTimeSpan (6, 0, 0, 0);

	COleDateTimeSpan span (7, 0, 0, 0);

	for (int iRow = 0; iRow < nRows; iRow++)
	{
		CRect rect (m_WeekRects[iRow]);

		if (rect.top < rect.bottom)
		{
			COLORREF clrText = 
				visualManager->OnFillPlannerCaption (pDC, this, rect, FALSE, FALSE, TRUE, FALSE);

			pDC->SetTextColor (clrText);

			pDC->Draw3dRect (rect, clrLine, clrLine);

			rect.DeflateRect (1, 1);

			SYSTEMTIME st1;
			day1.GetAsSystemTime (st1);
			SYSTEMTIME st2;
			day2.GetAsSystemTime (st2);

			CString strDate1;
			CString strDate2;

			if (day1.GetMonth () == day2.GetMonth ())
			{
				strDate1.GetBuffer (_MAX_PATH);
				::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st1, 
					saFormat[0], (LPTSTR)(LPCTSTR)strDate1, _MAX_PATH);
				strDate1.ReleaseBuffer ();

				strDate2.GetBuffer (_MAX_PATH);
				::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st2, 
					saFormat[1], (LPTSTR)(LPCTSTR)strDate2, _MAX_PATH);
				strDate2.ReleaseBuffer ();
			}
			else
			{
				strDate1.GetBuffer (_MAX_PATH);
				::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st1, 
					saFormat[2], (LPTSTR)(LPCTSTR)strDate1, _MAX_PATH);
				strDate1.ReleaseBuffer ();

				strDate2.GetBuffer (_MAX_PATH);
				::GetDateFormat (LOCALE_USER_DEFAULT, 0, &st2, 
					saFormat[2], (LPTSTR)(LPCTSTR)strDate2, _MAX_PATH);
				strDate2.ReleaseBuffer ();
			}

			CString strText = strDate1 + _T(" - ") + strDate2;

			CSize szText (pDC->GetTextExtent (strText));

			CRect rectText (rect);
			rectText.left = rectText.left + (rect.Width () - szText.cy + 1) / 2;

			rectText.top = rectText.bottom;
			if (szText.cx < rect.Height ())
			{
				rectText.top -= (rect.Height () - szText.cx + 1) / 2;
			}
			rectText.bottom = rect.top;

			pDC->DrawText (strText, rectText, DT_SINGLELINE);
		}

		day1 += span;
		day2 += span;
	}

	pDC->SetTextColor (clrTextOld);
	if (hOldFont != NULL)
	{
		::SelectObject (pDC->GetSafeHdc (), hOldFont);
	}
}
예제 #2
0
bool EvaluateCondition(const FeedFilterCondition& condition,
                       const FeedItem& item) {
  bool is_numeric = false;
  std::wstring element;
  std::wstring value = ReplaceVariables(condition.value, item.episode_data);
  auto anime = AnimeDatabase.FindItem(item.episode_data.anime_id);

  switch (condition.element) {
    case kFeedFilterElement_File_Title:
      element = item.title;
      break;
    case kFeedFilterElement_File_Category:
      element = item.category;
      break;
    case kFeedFilterElement_File_Description:
      element = item.description;
      break;
    case kFeedFilterElement_File_Link:
      element = item.link;
      break;
    case kFeedFilterElement_Meta_Id:
      if (anime)
        element = ToWstr(anime->GetId());
      is_numeric = true;
      break;
    case kFeedFilterElement_Episode_Title:
      element = item.episode_data.title;
      break;
    case kFeedFilterElement_Meta_DateStart:
      if (anime)
        element = anime->GetDateStart();
      break;
    case kFeedFilterElement_Meta_DateEnd:
      if (anime)
        element = anime->GetDateEnd();
      break;
    case kFeedFilterElement_Meta_Episodes:
      if (anime)
        element = ToWstr(anime->GetEpisodeCount());
      is_numeric = true;
      break;
    case kFeedFilterElement_Meta_Status:
      if (anime)
        element = ToWstr(anime->GetAiringStatus());
      is_numeric = true;
      break;
    case kFeedFilterElement_Meta_Type:
      if (anime)
        element = ToWstr(anime->GetType());
      is_numeric = true;
      break;
    case kFeedFilterElement_User_Status:
      if (anime)
        element = ToWstr(anime->GetMyStatus());
      is_numeric = true;
      break;
    case kFeedFilterElement_Episode_Number:
      element = ToWstr(anime::GetEpisodeHigh(item.episode_data.number));
      is_numeric = true;
      break;
    case kFeedFilterElement_Episode_Version:
      element = item.episode_data.version;
      if (element.empty())
        element = L"1";
      is_numeric = true;
      break;
    case kFeedFilterElement_Local_EpisodeAvailable:
      if (anime)
        element = ToWstr(anime->IsEpisodeAvailable(
            anime::GetEpisodeHigh(item.episode_data.number)));
      is_numeric = true;
      break;
    case kFeedFilterElement_Episode_Group:
      element = item.episode_data.group;
      break;
    case kFeedFilterElement_Episode_VideoResolution:
      element = item.episode_data.resolution;
      break;
    case kFeedFilterElement_Episode_VideoType:
      element = item.episode_data.video_type;
      break;
  }

  switch (condition.op) {
    case kFeedFilterOperator_Equals:
      if (is_numeric) {
        if (IsEqual(value, L"True"))
          return ToInt(element) == TRUE;
        return ToInt(element) == ToInt(value);
      } else {
        if (condition.element == kFeedFilterElement_Episode_VideoResolution) {
          return anime::TranslateResolution(element) == anime::TranslateResolution(condition.value);
        } else {
          return IsEqual(element, value);
        }
      }
    case kFeedFilterOperator_NotEquals:
      if (is_numeric) {
        if (IsEqual(value, L"True"))
          return ToInt(element) == TRUE;
        return ToInt(element) != ToInt(value);
      } else {
        if (condition.element == kFeedFilterElement_Episode_VideoResolution) {
          return anime::TranslateResolution(element) != anime::TranslateResolution(condition.value);
        } else {
          return !IsEqual(element, value);
        }
      }
    case kFeedFilterOperator_IsGreaterThan:
      if (is_numeric) {
        return ToInt(element) > ToInt(value);
      } else {
        if (condition.element == kFeedFilterElement_Episode_VideoResolution) {
          return anime::TranslateResolution(element) > anime::TranslateResolution(condition.value);
        } else {
          return CompareStrings(element, condition.value) > 0;
        }
      }
    case kFeedFilterOperator_IsGreaterThanOrEqualTo:
      if (is_numeric) {
        return ToInt(element) >= ToInt(value);
      } else {
        if (condition.element == kFeedFilterElement_Episode_VideoResolution) {
          return anime::TranslateResolution(element) >= anime::TranslateResolution(condition.value);
        } else {
          return CompareStrings(element, condition.value) >= 0;
        }
      }
    case kFeedFilterOperator_IsLessThan:
      if (is_numeric) {
        return ToInt(element) < ToInt(value);
      } else {
        if (condition.element == kFeedFilterElement_Episode_VideoResolution) {
          return anime::TranslateResolution(element) < anime::TranslateResolution(condition.value);
        } else {
          return CompareStrings(element, condition.value) < 0;
        }
      }
    case kFeedFilterOperator_IsLessThanOrEqualTo:
      if (is_numeric) {
        return ToInt(element) <= ToInt(value);
      } else {
        if (condition.element == kFeedFilterElement_Episode_VideoResolution) {
          return anime::TranslateResolution(element) <= anime::TranslateResolution(condition.value);
        } else {
          return CompareStrings(element, condition.value) <= 0;
        }
      }
    case kFeedFilterOperator_BeginsWith:
      return StartsWith(element, value);
    case kFeedFilterOperator_EndsWith:
      return EndsWith(element, value);
    case kFeedFilterOperator_Contains:
      return InStr(element, value, 0, true) > -1;
    case kFeedFilterOperator_NotContains:
      return InStr(element, value, 0, true) == -1;
  }

  return false;
}
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);
	}
}
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::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);
}
void CBCGPPlannerViewMulti::OnDrawHeaderAllDay (CDC* pDC, const CRect& rectHeader)
{
	ASSERT_VALID (pDC);

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

	visualManager->OnFillPlannerHeaderAllDay (pDC, this, rectHeader);

	int nDay = 0;

	COleDateTime date (GetDateStart ());
	COleDateTimeSpan span (1, 0, 0, 0);

	CRect rt (rectHeader);
	rt.bottom--;

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

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

		for (nDay = 1; nDay < nDays; nDay++)
		{
			pDC->MoveTo (m_ViewRects [nDay].left, rectHeader.top);
			pDC->LineTo (m_ViewRects [nDay].left, rectHeader.bottom - 1);
		}

		for (int i = 1; i < nRes; i++)
		{
			for (nDay = 0; nDay < nDays; nDay++)
			{
				CRect& rectRes = m_Resources[i].m_Rects[nDay];
				pDC->MoveTo (rectRes.left, rectHeader.top);
				pDC->LineTo (rectRes.left, rectHeader.bottom - 1);
			}
		}

		pDC->SelectObject (pOldPen);
	}

	UINT nResourceID = GetCurrentResourceID ();

	for (nDay = 0; nDay < nDays; nDay++)
	{
		for (int i = 0; i < nRes; i++)
		{
			rt.left  = m_Resources [i].m_Rects [nDay].left;
			rt.right = m_Resources [i].m_Rects [nDay].right;

			visualManager->OnDrawPlannerHeaderAllDayItem (pDC, this, rt, 
				FALSE, 
				m_SelectionAllDay[nDay] && m_Resources [i].m_ResourceID == nResourceID);
		}

		if (date == dayCurrent)
		{
			rt.left  = m_ViewRects [nDay].left;
			rt.right = m_ViewRects [nDay].right;

			visualManager->OnDrawPlannerHeaderAllDayItem (pDC, this, rt, TRUE, FALSE);
		}

		date += span;
	}
}
COleDateTime CBCGPRecurrenceRuleMonthly::GetNextEventDay (const COleDateTime& dtPrev) const
{
	if (dtPrev < GetDateStart ())
	{
		return COleDateTime ();
	}

	COleDateTime dt (dtPrev);

	DWORD dwSpan = m_Type == BCGP_REC_RULE_MONTHLY_TYPE_DAY ? m_dwDaySpan : m_dwDayTypeSpan;

	{
		int m = dt.GetMonth ();
		int y = dt.GetYear ();
		int nDays = 0;

		dt = COleDateTime (y, m, 1, 0, 0, 0);

		for (DWORD i = 0; i < dwSpan; i++)
		{
			m++;

			if (m == 13)
			{
				m = 1;
				y++;
			}

			nDays = CBCGPCalendar::GetMaxMonthDay (m, y);
			dt += COleDateTimeSpan (nDays, 0, 0, 0);
		}

		int d = GetPossibleDay (m, y);

		dt = COleDateTime (y, m, nDays < d ? nDays : d, 0, 0, 0);
	}

	BCGP_RECURRENCE_RULE_LIMIT limitType = GetLimitType ();

	if (limitType == BCGP_RECURRENCE_RULE_LIMIT_COUNT)
	{
		if (m_Type == BCGP_REC_RULE_MONTHLY_TYPE_DAY)
		{
			int m = ((dt.GetYear () - GetDateStart ().GetYear ()) * 12 +
				(dt.GetMonth () - GetDateStart ().GetMonth () + dwSpan)) / dwSpan;
			
			if ((int)GetLimitCount () < m)
			{
				dt = COleDateTime ();
			}
		}
	}
	else if (limitType == BCGP_RECURRENCE_RULE_LIMIT_DATE)
	{
		if (GetLimitDate () < dt)
		{
			dt = COleDateTime ();
		}
	}

	return dt;
}
COleDateTime CBCGPRecurrenceRuleDaily::GetNextEventDay (const COleDateTime& dtPrev) const
{
	if (dtPrev < GetDateStart ())
	{
		return COleDateTime ();
	}

	COleDateTime dt (dtPrev);
	
	if (m_Type == BCGP_REC_RULE_DAILY_TYPE_WEEKDAYS)
	{
		dt += COleDateTimeSpan (1, 0, 0, 0);

		int nWD = dt.GetDayOfWeek ();

		if (nWD == 1)
		{
			dt += COleDateTimeSpan (1, 0, 0, 0);
		}
		else if (nWD == 7)
		{
			dt += COleDateTimeSpan (2, 0, 0, 0);
		}
	}
	else
	{
		dt += COleDateTimeSpan (m_dwSpan, 0, 0, 0);
	}

	BCGP_RECURRENCE_RULE_LIMIT limitType = GetLimitType ();

	if (limitType == BCGP_RECURRENCE_RULE_LIMIT_COUNT)
	{
		if (m_Type == BCGP_REC_RULE_DAILY_TYPE_WEEKDAYS)
		{
			COleDateTime dtF (
				CBCGPPlannerView::GetFirstWeekDay (GetDateStart (), 
					2));

			int nDaysCount = (dt - GetDateStart ()).GetDays () + 1;
			int nWeekCount = (dt - dtF).GetDays () / 7;

			if ((nDaysCount - nWeekCount * 2) > (int)GetLimitCount ())
			{
				dt = COleDateTime ();
			}
		}
		else
		{
			if ((GetDateStart () + 
				 COleDateTimeSpan (m_dwSpan * GetLimitCount (), 0, 0, 0)) <= dt)
			{
				dt = COleDateTime ();
			}
		}
	}
	else if (limitType == BCGP_RECURRENCE_RULE_LIMIT_DATE)
	{
		if (GetLimitDate () < dt)
		{
			dt = COleDateTime ();
		}
	}

	return dt;
}
COleDateTime CBCGPRecurrenceRuleWeekly::GetNextEventDay (const COleDateTime& dtPrev) const
{
	if (dtPrev < GetDateStart ())
	{
		return COleDateTime ();
	}

	COleDateTime dt (dtPrev);

	int nWD  = dt.GetDayOfWeek ();
	BCGP_REC_RULE_WEEKLY typeWD = DayOfWeekToType (nWD);
	nWD--;

	int nWDL = TypeToDayOfWeek (m_LastDay) - 1;

	if (nWD == 0)
	{
		nWD = 7;
	}

	if (nWDL == 0)
	{
		nWDL = 7;
	}

	if (nWD == nWDL)
	{
		COleDateTime dtFirst (CBCGPPlannerView::GetFirstWeekDay (dtPrev, 
						2));//CBCGPPlannerManagerCtrl::GetFirstDayOfWeek () + 1));

		int nWDF = TypeToDayOfWeek (m_FirstDay) - 1;
		if (nWDF == 0)
		{
			nWDF = 7;
		}

		dt = dtFirst + COleDateTimeSpan (m_dwSpan * 7 + nWDF - 1, 0, 0, 0);
	}
	else
	{
		int nWDN = TypeToDayOfWeek (GetNextDay (typeWD)) - 1;

		if (nWDN == 0)
		{
			nWDN = 7;
		}

		int delta = nWDN - nWD;
		if (delta < 0)
		{
			delta += 7;
		}

		dt += COleDateTimeSpan (delta, 0, 0, 0);
	}


	BCGP_RECURRENCE_RULE_LIMIT limitType = GetLimitType ();

	if (limitType == BCGP_RECURRENCE_RULE_LIMIT_COUNT)
	{
		int nCount = GetLimitCount () % m_nCount;

		int delta  = GetLimitCount () / m_nCount;
		delta = delta * 7 * m_dwSpan;

		if (nCount > 0)
		{
			int i = 0;
			int c = 0;
			for (DWORD dwD = BCGP_REC_RULE_WEEKLY_FIRST; dwD <= BCGP_REC_RULE_WEEKLY_LAST; dwD = dwD << 1)
			{
				c++;

				if ((m_dwDays & dwD) != 0)
				{
					i++;

					if (i == nCount)
					{
						break;
					}
				}	
			}

			delta += c;
		}

		if (delta <= (dt - CBCGPPlannerView::GetFirstWeekDay (GetDateStart (), 
						2)))
		{
			dt = COleDateTime ();
		}
	}
	else if (limitType == BCGP_RECURRENCE_RULE_LIMIT_DATE)
	{
		if (dt > GetLimitDate ())
		{
			dt = COleDateTime ();
		}
	}

	return dt;
}
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);
}