/*
Original code by : Mihai Filimon
Modifications by S. Sridhar 
1. Added a edit control where the user can type in the path
2. If the path typed in the edit ctrl does not exist then the 
   user will be propmted as to whether he/she wants the path 
   to be created
3. Setting the flag bShowFilesInDir to TRUE will result in all 
   the files in the current folder to be displayed in the dialog
4. If u don't want to display all the files then u can use the 
   file filter to display the file types u want to display
5. Calling API SetTitle with the desired title will set the Title 
   of the dialog. This API has to be invoked before DoModal is called
6. User can pass the Initial Folder to be displayed in the constructor 
   of CSelectFolder

Usage Examples
--------------

CaplSelectFolderDialog oSelectFolderDialog(FALSE, NULL,
						OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
						NULL, NULL);

CaplSelectFolderDialog oSelectFolderDialog(FALSE, "c:\\my documents",
						OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
						NULL, NULL);

CaplSelectFolderDialog oSelectFolderDialog(TRUE, "c:\\my documents",
						OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
						NULL, NULL);

CaplSelectFolderDialog oSelectFolderDialog(TRUE, "c:\\my documents",
						OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
	"Microsoft Word Documents (*.doc)|*.doc|Microsoft Excel Worksheets (*.xls)|*.xls|", NULL);

CaplSelectFolderDialog oSelectFolderDialog(TRUE, "c:\\my documents",
						OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
	"HTML Files (*.html, *.htm)|*.html;*.htm||", NULL);
*/

#include "stdafx.h"
#include "apl_gui.h"
#include <IO.H>
/*
#include <DLGS.H>
#include <WINUSER.H>
*/
#include <imagehlp.h>
#pragma comment(lib, "imagehlp")

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

#define IDLB_FOLDER_DIALOG_FILES		101
#define IDEB_FOLDER_DIALOG_SEL_FOLDER	102

/////////////////////////////////////////////////////////////////////////////
// CaplSelectFolderDialog

static BOOL IsDirectory(const CString& lpszName)
{
	DWORD dwRet;
	dwRet = ::GetFileAttributes(lpszName);
	return (dwRet != 0xFFFFFFFF) && (dwRet & FILE_ATTRIBUTE_DIRECTORY);
}


IMPLEMENT_DYNAMIC(CaplSelectFolderDialog, CFileDialog)

WNDPROC CaplSelectFolderDialog::m_wndProc = NULL;


CaplSelectFolderDialog::CaplSelectFolderDialog(
						BOOL bShowFilesInDir /*= FALSE*/, 
						LPCTSTR lpcstrInitialDir /*= NULL*/, 
						DWORD dwFlags /*= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT*/,
						LPCTSTR lpszFilter /*= NULL*/, 
						CWnd* pParentWnd /*= NULL*/)
					: CFileDialog(TRUE, NULL, 
					(bShowFilesInDir)? ((lpszFilter)? NULL : _T("*.*")) : _T("*.....*"), 
									dwFlags, lpszFilter, pParentWnd,  0, FALSE)
{
	if(lpcstrInitialDir)
		m_ofn.lpstrInitialDir = lpcstrInitialDir;
	
	m_bShowFilesInDir = bShowFilesInDir;

	m_pEdit = NULL;

	m_cstrTitle =  APL_T("Выбор папки");
}

CaplSelectFolderDialog::~CaplSelectFolderDialog()
{
	if(m_pEdit)
		delete m_pEdit;
}

BEGIN_MESSAGE_MAP(CaplSelectFolderDialog, CFileDialog)
	//{{AFX_MSG_MAP(CaplSelectFolderDialog)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CaplSelectFolderDialog::DoDataExchange( CDataExchange* pDX )
{
	CFileDialog::DoDataExchange(pDX);

// 	DDX_Control(pDX, IDOK, m_ok_btn);	
// 	DDX_Control(pDX, IDCANCEL, m_cancel_btn);
}

// Function name	: WindowProcNew
// Description	    : Call this function when user navigate into CFileDialog.
// Return type		: LRESULT
// Argument         : HWND hwnd
// Argument         : UINT message
// Argument         : WPARAM wParam
// Argument         : LPARAM lParam
LRESULT CALLBACK WindowProcNew(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam)
{
	if(message ==  WM_COMMAND)
	{
		if (HIWORD(wParam) == BN_CLICKED)
		{
			if (LOWORD(wParam) == IDOK)
			{
				if (CFileDialog* pDlg = (CFileDialog*)CWnd::FromHandle(hwnd))
				{
					CString cstrPath;
					((CaplSelectFolderDialog*)pDlg->GetDlgItem(
						IDEB_FOLDER_DIALOG_SEL_FOLDER))->GetWindowText(cstrPath);
					
					//If there is nothing entered in the IDEB_FOLDER_DIALOG_SEL_FOLDER
					//Then use the current sel folder
					if(cstrPath.GetLength() == 0)
						cstrPath = ((CaplSelectFolderDialog*)pDlg->GetDlgItem(0))->GetFolderPath();

					//If the user has entered something like "c:\\windows\\\\system"
					//this is invalid but _access returns valid if this string is passed to
					//it. So before giving it to _access validate it.
					int i;
					for (i = 1; i < cstrPath.GetLength() - 1; i++)
					{
						if (cstrPath[i] == _T('\\') && cstrPath[i+1] == _T('\\'))
						{
							AfxMessageBox( APL_T("Некорректная папка"), MB_OK | MB_ICONHAND);
							return NULL;
						}
					}

					if (cstrPath.IsEmpty())
					{
						AfxMessageBox( APL_T("Некорректная папка"), MB_OK | MB_ICONHAND);
						return NULL;
					}
					
					//If user has entered a trailing backslash remove it
					//e.g. "c:\\windows\\system\\" --> "c:\\windows\\system"
					if (cstrPath[i] == _T('\\'))
						cstrPath = cstrPath.Left (cstrPath.GetLength() - 1);

					//If path does not exist
					if(__access(cstrPath, 00) != 0)
					{
						if(AfxMessageBox(cstrPath + _T("\n") + _T("\n") +
							 APL_T("Данный путь не существует. Вы хотите его создать?"),
							MB_YESNO | MB_ICONQUESTION) == IDYES)
						{
#ifdef UNICODE
							SHCreateDirectoryEx(hwnd, cstrPath + _T("\\"), NULL);
#else
							MakeSureDirectoryPathExists(cstrPath + _T("\\"));
#endif
							if(__access(cstrPath, 00) != 0)
							{
								AfxMessageBox((CString) APL_T("Не удалось создать папку:") + _T("\n") + cstrPath);
								return NULL;
							}
						}
					}

					((CaplSelectFolderDialog*)pDlg->GetDlgItem(0))->SetSelectedPath(cstrPath + _T("\\"));

					pDlg->EndDialog(IDOK);

					return NULL;
				}
			}
		}
	}

	return CallWindowProc(CaplSelectFolderDialog::m_wndProc, hwnd, message, wParam, lParam);
}

// Function name	: CaplSelectFolderDialog::OnInitDone
// Description	    : For update the wiew of CFileDialog
// Return type		: void 
void CaplSelectFolderDialog::OnInitDone()
{
	int nRealCtrlID = 0;

#if _MSC_VER >= 1400
	nRealCtrlID = cmb13;
#else
	nRealCtrlID = edt1;
#endif

	HideControl(nRealCtrlID);

	CWnd* pFD = GetParent();
	CRect rectCancelPB; pFD->GetDlgItem(IDCANCEL)->GetWindowRect(rectCancelPB);
	pFD->ScreenToClient(rectCancelPB);
	CRect rectOKPB; pFD->GetDlgItem(IDOK)->GetWindowRect(rectOKPB);
	pFD->ScreenToClient(rectOKPB);
	pFD->GetDlgItem(IDOK)->SetWindowPos(0,rectCancelPB.left - rectOKPB.Width() - 4, rectCancelPB.top, 0,0, SWP_NOZORDER | SWP_NOSIZE);
	CRect rectList2LC; pFD->GetDlgItem(lst1)->GetWindowRect(rectList2LC);
	pFD->ScreenToClient(rectList2LC);
	
	pFD->GetDlgItem(lst1)->SetWindowPos(0,0,0,rectList2LC.Width(), abs(rectList2LC.top - (rectCancelPB.top - 45)) + 25, SWP_NOMOVE | SWP_NOZORDER);
	
	SetControlText(IDOK,  APL_T("Выбрать"));
	pFD->SetWindowText(m_cstrTitle);
	m_wndProc = (WNDPROC)SetWindowLong(pFD->m_hWnd, GWL_WNDPROC, (long)WindowProcNew);

	CRect rectstc3ST; 
	pFD->GetDlgItem(stc3)->GetWindowRect(rectstc3ST);
	pFD->ScreenToClient(rectstc3ST);
	pFD->GetDlgItem(stc3)->SetWindowText( APL_T("Текущая папка:"));
#if _MSC_VER >= 1400
	pFD->GetDlgItem(stc3)->SetWindowPos(0, rectstc3ST.left, rectstc3ST.top + 6, rectstc3ST.Width() + 20, rectstc3ST.Height(), SWP_NOZORDER);
#else
	pFD->GetDlgItem(stc3)->SetWindowPos(0, rectstc3ST.left, rectstc3ST.top + 14, rectstc3ST.Width() + 20, rectstc3ST.Height(), SWP_NOZORDER);
#endif

	CRect rectCurrFolderEB;
	pFD->GetDlgItem(nRealCtrlID)->GetWindowRect(rectCurrFolderEB);
	pFD->ScreenToClient(rectCurrFolderEB);
	rectCurrFolderEB.left = rectstc3ST.left;
	rectCurrFolderEB.right -= 90;
#if _MSC_VER >= 1400
	rectCurrFolderEB.top += 27;
	rectCurrFolderEB.bottom += 27;
#else
	rectCurrFolderEB.top += 30;
	rectCurrFolderEB.bottom += 30;
#endif

	m_pEdit = new CEdit();
	m_pEdit->Create(WS_TABSTOP | WS_VISIBLE | WS_CHILD |ES_AUTOHSCROLL, 
					rectCurrFolderEB, pFD, IDEB_FOLDER_DIALOG_SEL_FOLDER);
	m_pEdit->SetWindowText(m_ofn.lpstrInitialDir);
	m_pEdit->SetFont(pFD->GetDlgItem(nRealCtrlID)->GetFont());
	
	//Draw the thick sunkun edge
	m_pEdit->ModifyStyleEx(0, WS_EX_CLIENTEDGE, SWP_DRAWFRAME);
	
	//Set the Tab order after the Folders Listbox
	m_pEdit->SetWindowPos(pFD->GetDlgItem(lst1), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

	if(!m_bShowFilesInDir || (m_ofn.lpstrFilter == NULL) || (_strlen(m_ofn.lpstrFilter) == 0))
	{
		//File Types Static text and Combo box
		HideControl(stc2);
		HideControl(cmb1);
	}
	
	if(m_bShowFilesInDir && (m_ofn.lpstrFilter != NULL) && (_strlen(m_ofn.lpstrFilter) != 0))
	{
		//Increase the height of the dialog
		CRect rectDialog;
		pFD->GetWindowRect(rectDialog);
		rectDialog.bottom += 35;
		pFD->SetWindowPos(0, 0, 0, rectDialog.Width(), rectDialog.Height(), SWP_NOZORDER | SWP_NOMOVE);

		CRect rectST;
		pFD->GetDlgItem(stc2)->GetWindowRect(rectST);
		pFD->ScreenToClient(rectST);
		rectST.top += 25;
		rectST.bottom += 25;
		pFD->GetDlgItem(stc2)->SetWindowPos(0, rectST.left, rectST.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);

		CRect rectComboDL;
		pFD->GetDlgItem(cmb1)->GetWindowRect(rectComboDL);
		pFD->ScreenToClient(rectComboDL);
		rectComboDL.left = rectST.left;
		rectComboDL.top = rectST.top + rectST.Height();
		rectComboDL.bottom = rectST.bottom + rectST.Height();
		pFD->GetDlgItem(cmb1)->SetWindowPos(0, rectComboDL.left, rectComboDL.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);

		pFD->GetDlgItem(IDCANCEL)->GetWindowRect(rectCancelPB);
		pFD->ScreenToClient(rectCancelPB);
		rectCancelPB.top = rectST.bottom - 2;
		rectCancelPB.bottom = rectCancelPB.top + rectCancelPB.Height();
		pFD->GetDlgItem(IDCANCEL)->SetWindowPos(0, rectCancelPB.left, rectCancelPB.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);

		pFD->GetDlgItem(IDOK)->GetWindowRect(rectOKPB);
		pFD->ScreenToClient(rectOKPB);
		pFD->GetDlgItem(IDOK)->SetWindowPos(0,rectCancelPB.left - rectOKPB.Width() - 4, rectCancelPB.top, 0,0, SWP_NOZORDER | SWP_NOSIZE);

		rectCurrFolderEB.right = rectCancelPB.right;
		m_pEdit->SetWindowPos(pFD->GetDlgItem(lst1), 0, 0, rectCurrFolderEB.Width(), rectCurrFolderEB.Height(), SWP_NOMOVE | SWP_NOZORDER);
	}

	pFD->CenterWindow();
}

void CaplSelectFolderDialog::OnFolderChange()
{
	CWnd *pWnd=GetParent();
	if(pWnd)
	{
		if(::IsWindow(pWnd->m_hWnd))
		{
			m_pEdit->SetWindowText(GetFolderPath());
		}
	}
}

/*
void CaplSelectFolderDialog::OnFileNameChange()
{
	TCHAR path[MAX_PATH]; 

	GetCurrentDirectory ( MAX_PATH, path ); 
	m_cstrPath = CString (path);

	CWnd* pParent = GetParent ( )->GetDlgItem ( lst2 ); 

	// get the list control 
	CListCtrl *pList = ( CListCtrl * ) pParent->GetDlgItem ( 1 );

	// currently selected item 
	int pos = pList->GetNextItem ( -1, LVIS_SELECTED | LVIS_FOCUSED ); 

	if ( pos != -1 ) 
	{ 
		// create the full path... 
		CString selection = pList->GetItemText( pos, 0 ); 
		CString testStr = CString (path) + _T ( "\\" ) + selection; 
		if (::IsDirectory(testStr))
			m_cstrPath = testStr;
		GetParent()->GetDlgItem(IDOK)->EnableWindow(TRUE);
	}
	else
		GetParent()->GetDlgItem(IDOK)->EnableWindow(FALSE);

	GetParent()->GetDlgItem(edt1)->SetWindowText(m_cstrPath);
}
*/

void CaplSelectFolderDialog::SetSelectedPath(LPCTSTR lpcstrPath)
{
	m_cstrPath = lpcstrPath;
}

CString CaplSelectFolderDialog::GetSelectedPath() const
{
	return m_cstrPath;
}

void CaplSelectFolderDialog::SetTitle(CString cstrTitle)
{
	m_cstrTitle = cstrTitle;
}

