// XTPDatePickerDaysCollection.cpp: implementation of the CXTPDatePickerDaysCollection class.
//
// This file is a part of the XTREME CALENDAR MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"


#include "XTPCalendarDefines.h"

#include "XTPDatePickerDaysCollection.h"
#include "XTPDatePickerControl.h"

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

/////////////////////////////////////////////////////////////////////////////
// CXTPDatePickerDaysCollection

CXTPDatePickerDaysCollection::CXTPDatePickerDaysCollection(CXTPDatePickerControl* pControl)
	: m_pControl(pControl)
{
}

CXTPDatePickerDaysCollection::~CXTPDatePickerDaysCollection()
{
}

void CXTPDatePickerDaysCollection::_InsertBlock(int nIndexInsert, long nDateBegin, long nDateEnd)
{
	SELECTED_BLOCK block;
	block.nDateBegin = nDateBegin;
	block.nDateEnd = nDateEnd;
	m_arrSelectedBlocks.InsertAt(nIndexInsert, block);
}

void CXTPDatePickerDaysCollection::AddBlock(long nBegin, long nEnd)
{
	int i = 0;
	int nCount = (int)m_arrSelectedBlocks.GetSize();

	if (nCount > 0)
	{
		long& nDateEnd = m_arrSelectedBlocks[nCount - 1].nDateEnd;

		if (nDateEnd == nBegin)
		{
			nDateEnd = nEnd + 1;
			m_pControl->_RedrawControl(FALSE);
			return;
		}

		if (nDateEnd < nBegin)
		{
			i = nCount;
		}
	}

	for (; i < nCount; i++)
	{
		long& nDateBegin = m_arrSelectedBlocks[i].nDateBegin;
		long& nDateEnd = m_arrSelectedBlocks[i].nDateEnd;

		if ((nDateBegin <= nBegin) && (nDateEnd > nEnd))
		{
			return;
		}

		if (nDateEnd == nBegin)
		{
			nDateEnd = nEnd + 1;
			if (i + 1 < nCount && m_arrSelectedBlocks[i + 1].nDateBegin == nDateEnd)
			{
				nDateEnd = m_arrSelectedBlocks[i + 1].nDateEnd;
				m_arrSelectedBlocks.RemoveAt(i + 1);
			}

			m_pControl->_RedrawControl(FALSE);
			return;
		}
		if (nDateBegin == nEnd + 1)
		{
			nDateBegin = nBegin;
			m_pControl->_RedrawControl(FALSE);
			return;
		}

		if (nDateBegin > nEnd)
			break;
	}

	_InsertBlock(i, nBegin, nEnd + 1);
	m_pControl->_RedrawControl(FALSE);
}

void CXTPDatePickerDaysCollection::Clear()
{
	m_arrSelectedBlocks.RemoveAll();
}

void CXTPDatePickerDaysCollection::Add(const COleDateTime& dtDay)
{
	AddBlock((long)dtDay, (long)dtDay);
}

void CXTPDatePickerDaysCollection::Remove(const COleDateTime& dtDay)
{
	long nDate = (long)dtDay;

	for (int i = 0; i < (int)m_arrSelectedBlocks.GetSize(); i++)
	{
		long nDateBegin = m_arrSelectedBlocks[i].nDateBegin;
		long nDateEnd = m_arrSelectedBlocks[i].nDateEnd;

		if ((nDateBegin <= nDate) && (nDateEnd > nDate))
		{
			if (nDateBegin != nDate)
			{
				_InsertBlock(i, nDateBegin, nDate);
				i++;
			}

			if (nDateEnd - 1 != nDate)
			{
				_InsertBlock(i + 1, nDate + 1, nDateEnd);
			}

			m_arrSelectedBlocks.RemoveAt(i);
			return;
		}
	}
}


void CXTPDatePickerDaysCollection::Select(const COleDateTime& dtDay)
{
	long nDate = (long)dtDay;

	if (m_arrSelectedBlocks.GetSize() == 1 && m_arrSelectedBlocks[0].nDateBegin ==
		m_arrSelectedBlocks[0].nDateEnd - 1 && m_arrSelectedBlocks[0].nDateBegin == nDate)
	{

	}
	else
	{
		Clear();
		Add(dtDay);
	}
}

void CXTPDatePickerDaysCollection::SelectRange(const COleDateTime& dtDayBegin, const COleDateTime& dtDayEnd)
{
	COleDateTime dtDayBeginCopy;
	dtDayBeginCopy.SetDate(dtDayBegin.GetYear(), dtDayBegin.GetMonth(), dtDayBegin.GetDay());
	COleDateTime dtDayEndCopy;
	dtDayEndCopy.SetDate(dtDayEnd.GetYear(), dtDayEnd.GetMonth(), dtDayEnd.GetDay());

	//From MSDN: The COleDateTime class handles dates from 1 January 100 - 31 December 9999.
	if (dtDayBeginCopy.GetYear() < 100)
		dtDayBeginCopy.SetDate(100, dtDayBeginCopy.GetMonth(), dtDayBeginCopy.GetDay());

	if (dtDayEndCopy.GetYear() < 100)
		dtDayEndCopy.SetDate(100, dtDayEndCopy.GetMonth(), dtDayEndCopy.GetDay());

	if (dtDayBeginCopy.GetYear() >= 10000)
		dtDayBeginCopy.SetDate(9999, dtDayBeginCopy.GetMonth(), dtDayBeginCopy.GetDay());

	if (dtDayEndCopy.GetYear() >= 10000)
		dtDayEndCopy.SetDate(9999, dtDayEndCopy.GetMonth(), dtDayEndCopy.GetDay());

	long nBeginDate = (long)dtDayBeginCopy;
	long nEndDate = (long)dtDayEndCopy;

	if (nBeginDate > nEndDate)
	{
		long nBlockBegin = nBeginDate;
		nBeginDate = nEndDate;
		nEndDate = nBlockBegin;
	}

	if (m_arrSelectedBlocks.GetSize() == 1 && m_arrSelectedBlocks[0].nDateBegin == nBeginDate &&
		m_arrSelectedBlocks[0].nDateEnd == nEndDate + 1)
	{
		return;
	}

	Clear();

	_InsertBlock(0, nBeginDate, nEndDate + 1);
}

BOOL CXTPDatePickerDaysCollection::Contains(const COleDateTime& dtDay) const
{
	long nDay = (long)dtDay;

	int nCount = (int)m_arrSelectedBlocks.GetSize();
	if (nCount == 0)
		return FALSE;

	if (m_arrSelectedBlocks[0].nDateBegin > nDay)
		return FALSE;

	if (m_arrSelectedBlocks[nCount - 1].nDateEnd <= nDay)
		return FALSE;

	for (int i = 0; i < nCount; i++)
	{
		if ((m_arrSelectedBlocks[i].nDateBegin <= nDay) &&
			(m_arrSelectedBlocks[i].nDateEnd > nDay))
		{
			return TRUE;
		}
	}
	return FALSE;
}

BOOL CXTPDatePickerDaysCollection::GetMinMaxRange(COleDateTime& refMinRange, COleDateTime& refMaxRange) const
{
	int nSelCount = (int)m_arrSelectedBlocks.GetSize();
	if (nSelCount == 0)
		return FALSE;

	refMinRange = (DATE)(double)m_arrSelectedBlocks[0].nDateBegin;
	refMaxRange = (DATE)(double)m_arrSelectedBlocks[nSelCount - 1].nDateEnd - 1;

	return TRUE;
}

int CXTPDatePickerDaysCollection::GetSelectedDaysCount() const
{
	int nCount = 0;
	for (int i = 0; i < (int)m_arrSelectedBlocks.GetSize(); i++)
	{
		nCount += m_arrSelectedBlocks[i].nDateEnd - m_arrSelectedBlocks[i].nDateBegin;
	}
	return nCount;
}