// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
//
// CWnd support for MFC Control containment (Feature Pack controls)
//

#include "..\stdafx.h"
#include "afxpriv.h"
#include "afxole.h"
#include "..\src\mfc\oleimpl2.h"
#include "..\src\mfc\afximpl.h"
#include "afxctrlcontainer.h"
// OG TO REDUCE EXE SIZE
/*
#include "afxtagmanager.h"
#include "afxbutton.h"
#include "afxcolorbutton.h"
#include "afxeditbrowsectrl.h"
#include "afxfontcombobox.h"
#include "afxlinkctrl.h"
#include "afxmaskededit.h"
#include "afxmenubutton.h"
#include "afxpropertygridctrl.h"
#include "afxshelllistctrl.h"
#include "afxshelltreectrl.h"
#include "afxvslistbox.h"
*/

////////////////////////////////////////////////////////////////////////////

static void DoRegisterWindowClass(LPCTSTR lpszClassName, LPCTSTR lpszBaseClassName)
{
	ASSERT(lpszClassName != NULL);
	ASSERT(lpszBaseClassName != NULL);

	WNDCLASS wnd = {0};

	HINSTANCE hInst = AfxGetInstanceHandle();
	if (!AfxCtxGetClassInfo(hInst, lpszBaseClassName, &wnd))
	{
		wnd.style = CS_DBLCLKS;
		wnd.hInstance = hInst;
		wnd.lpfnWndProc = ::DefWindowProc;
	}

	wnd.lpszClassName = lpszClassName;
	AfxRegisterClass(&wnd);
}

void AfxRegisterMFCCtrlClasses()
{
	DoRegisterWindowClass(_T("MFCButton"), WC_BUTTON);
	DoRegisterWindowClass(_T("MFCColorButton"), WC_BUTTON);
	DoRegisterWindowClass(_T("MFCEditBrowse"), WC_EDIT);
	DoRegisterWindowClass(_T("MFCFontComboBox"), WC_COMBOBOX);
	DoRegisterWindowClass(_T("MFCLink"), WC_BUTTON);
	DoRegisterWindowClass(_T("MFCMaskedEdit"), WC_EDIT);
	DoRegisterWindowClass(_T("MFCMenuButton"), WC_BUTTON);
	DoRegisterWindowClass(_T("MFCPropertyGrid"), WC_STATIC);
	DoRegisterWindowClass(_T("MFCShellList"), WC_LISTVIEW);
	DoRegisterWindowClass(_T("MFCShellTree"), WC_TREEVIEW);
	DoRegisterWindowClass(_T("MFCVSListBox"), WC_STATIC);
}

////////////////////////////////////////////////////////////////////////////
// CMFCControlContainer

CMFCControlContainer::CMFCControlContainer(CWnd* pWnd) : m_pWnd(pWnd)
{
}

CMFCControlContainer::~CMFCControlContainer()
{
	FreeSubclassedControls();
	ClearControlData();
}

BOOL CMFCControlContainer::SubclassDlgControls()
{
	if (m_pWnd->GetSafeHwnd() != NULL)
	{
		// Subclass Feature Pack controls:
		CWnd* pWndChild = m_pWnd->GetWindow(GW_CHILD);
		while (pWndChild != NULL)
		{
			ASSERT_VALID(pWndChild);

			TCHAR lpszClassName [MAX_CLASS_NAME + 1];

			::GetClassName(pWndChild->GetSafeHwnd(), lpszClassName, MAX_CLASS_NAME);
			CWnd* pWndSubclassedCtrl = CreateDlgControl(lpszClassName);

			if (pWndSubclassedCtrl != NULL)
			{
				m_arSubclassedCtrls.Add((CObject*)pWndSubclassedCtrl);
				pWndSubclassedCtrl->SubclassWindow(pWndChild->GetSafeHwnd());
			}

			pWndChild = pWndChild->GetNextWindow();
		}

		return TRUE;
	}

	return FALSE;
}

void CMFCControlContainer::FreeSubclassedControls()
{
	// Free subclassed controls: 
	for (int i = 0; i < m_arSubclassedCtrls.GetCount(); i++)
	{
		if (m_arSubclassedCtrls [i] != NULL)
		{
			delete m_arSubclassedCtrls [i];
		}
	}
	m_arSubclassedCtrls.RemoveAll();
}

CWnd* CMFCControlContainer::CreateDlgControl(LPCTSTR lpszClassName)
{
	ASSERT(m_pWnd->GetSafeHwnd() != NULL);

	if (lpszClassName != NULL)
	{
		CString strClass = lpszClassName;
		CWnd* pWndSubclassedCtrl = NULL;
		/*
		if (strClass == _T("MFCButton"))
		{
			pWndSubclassedCtrl = new CMFCButton;
		}
		else if (strClass == _T("MFCColorButton"))
		{
			pWndSubclassedCtrl = new CMFCColorButton;
		}
		else if (strClass == _T("MFCEditBrowse"))
		{
			pWndSubclassedCtrl = new CMFCEditBrowseCtrl;
		}
		else if (strClass == _T("MFCFontComboBox"))
		{
			pWndSubclassedCtrl = new CMFCFontComboBox;
		}
		else if (strClass == _T("MFCLink"))
		{
			pWndSubclassedCtrl = new CMFCLinkCtrl;
		}
		else if (strClass == _T("MFCMaskedEdit"))
		{
			pWndSubclassedCtrl = new CMFCMaskedEdit;
		}
		else if (strClass == _T("MFCMenuButton"))
		{
			pWndSubclassedCtrl = new CMFCMenuButton;
		}
		else if (strClass == _T("MFCPropertyGrid"))
		{
			pWndSubclassedCtrl = new CMFCPropertyGridCtrl;
		}
		else if (strClass == _T("MFCShellList"))
		{
			pWndSubclassedCtrl = new CMFCShellListCtrl;
		}
		else if (strClass == _T("MFCShellTree"))
		{
			pWndSubclassedCtrl = new CMFCShellTreeCtrl;
		}
		else if (strClass == _T("MFCVSListBox"))
		{
			pWndSubclassedCtrl = new CVSListBox;
		}
		*/
		return pWndSubclassedCtrl;
	}

	return NULL;
}

BOOL CMFCControlContainer::IsSubclassedFeaturePackControl(HWND hWndCtrl)
{
	if (hWndCtrl == NULL)
	{
		return FALSE;
	}

	for (int i = 0; i < m_arSubclassedCtrls.GetCount(); i++)
	{
		CWnd* pWnd = (CWnd*)m_arSubclassedCtrls[i];
		if (pWnd->GetSafeHwnd() == hWndCtrl)
		{
			return TRUE;
		}
	}

	return FALSE;
}

void CMFCControlContainer::PreUnsubclassControl(CWnd* pControl)
{
	/*
	CMFCShellListCtrl* pListCtrl = DYNAMIC_DOWNCAST(CMFCShellListCtrl, pControl);
	if (pListCtrl != NULL && pListCtrl->GetHeaderCtrl().GetSafeHwnd() != NULL)
	{
		pListCtrl->GetHeaderCtrl().UnsubclassWindow();
	}
	*/
}

BOOL CMFCControlContainer::ReSubclassControl(HWND hWndCtrl, WORD nIDC, CWnd& control)
{
	if (hWndCtrl == NULL)
	{
		return FALSE;
	}

	int nIndex = -1;
	for (int i = 0; i < m_arSubclassedCtrls.GetCount(); i++)
	{
		CWnd* pWnd = (CWnd*)m_arSubclassedCtrls [i];
		if (pWnd->GetSafeHwnd() == hWndCtrl)
		{
			nIndex = i;
			break;
		}
	}

	if (nIndex != -1)
	{
		CWnd* pWnd = DYNAMIC_DOWNCAST(CWnd, m_arSubclassedCtrls [nIndex]);
		
		if (pWnd->GetSafeHwnd() != NULL)
		{
			ASSERT_VALID(pWnd);

			// get init state
			DWORD dwSize = 0;
			BYTE* pbInitData = NULL;
			GetControlData(nIDC, dwSize, pbInitData);

			// Free old subclassed control:
			m_arSubclassedCtrls [nIndex] = NULL;

			// unsubclass
			PreUnsubclassControl(pWnd);
			VERIFY(pWnd->UnsubclassWindow() == hWndCtrl);
			// destroy
			delete pWnd;

			// subclass
			if (!control.SubclassWindow(hWndCtrl))
			{
				ASSERT(FALSE);      // possibly trying to subclass twice?
				AfxThrowNotSupportedException();
			}

			// set init state
			if (dwSize > 0)
			{
				control.SendMessage(WM_MFC_INITCTRL, (WPARAM)dwSize, (LPARAM)pbInitData);
			}

			return TRUE;
		}
	}

	return FALSE;
}

void CMFCControlContainer::SetControlData(WORD nIDC, DWORD dwSize, BYTE* pbData)
{
	CByteArray* pArray = new CByteArray;
	pArray->SetSize(dwSize);

	BYTE* pbBuffer = pArray->GetData();
	if (memcpy_s(pbBuffer, dwSize, pbData, dwSize) != 0)
	{
		delete pArray;
		ASSERT(FALSE);
		return;
	}

	m_mapControlData.SetAt(nIDC, pArray);
}

BOOL CMFCControlContainer::GetControlData(WORD nIDC, DWORD& dwSize, BYTE*& pbData)
{
	CObject* pData = NULL;
	if (m_mapControlData.Lookup(nIDC, pData) && pData != NULL)
	{
		CByteArray* pArray = (CByteArray*)pData;
		dwSize = (DWORD)pArray->GetSize();
		pbData = pArray->GetData();
		return TRUE;
	}

	return FALSE;
}

void CMFCControlContainer::ClearControlData()
{
	WORD nIDC;
	CObject* pData = NULL;
	POSITION pos = m_mapControlData.GetStartPosition();
	while (pos != NULL)
	{
		m_mapControlData.GetNextAssoc(pos, nIDC, pData); 
		CByteArray* pArray = (CByteArray*)pData; 
		delete pArray;
	}

	m_mapControlData.RemoveAll();
}

////////////////////////////////////////////////////////////////////////////
// Accessing dialog DLGINIT helpers

int __stdcall CMFCControlContainer::UTF8ToString(LPCSTR lpSrc, CString& strDst, int nLength)
{
	LPTSTR lpDst = NULL;
	int count = ::MultiByteToWideChar(CP_UTF8, 0, lpSrc, nLength, NULL, 0);
	if (count <= 0)
	{
		return 0;
	}

	LPWSTR lpWide = new WCHAR[count + 1];
	memset(lpWide, 0, (count + 1) * sizeof(WCHAR));

	::MultiByteToWideChar(CP_UTF8, 0, lpSrc, nLength, lpWide, count);

#ifdef _UNICODE
	lpDst = lpWide;
#else
	count = ::WideCharToMultiByte(::GetACP(), 0, lpWide, -1, NULL, 0, NULL, 0);

	if (count > 0)
	{
		lpDst = new char[count + 1];
		memset(lpDst, 0, count + 1);

		::WideCharToMultiByte(::GetACP(), 0, lpWide, -1, lpDst, count, NULL, 0);
	}

	delete [] lpWide;
#endif

	strDst = lpDst;
	delete[] lpDst;
	return count;
}

BOOL __stdcall CMFCControlContainer::ReadBoolProp(CTagManager& tagManager, LPCTSTR lpszTag, BOOL& bMember)
{
	if (lpszTag == NULL)
	{
		return FALSE;
	}

	CString str;
//	tagManager.ExcludeTag(lpszTag, str);

	if (str.IsEmpty())
	{
		return FALSE;
	}

	bMember = (str.CompareNoCase(PS_True) == 0);
	return TRUE;
}
