#include "stdafx.h"
#include "PathDialog.h"

#include <io.h>
#include <errno.h>

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

#define IDC_FOLDERTREE 0x3741
#define IDC_TITLE      0x3742
#define IDC_STATUSTEXT 0x3743

//#define IDC_NEW_EDIT_PATH	0x3744
#define IDC_NEW_EDIT_PATH 0xFFFF


// Class CDlgWnd
BEGIN_MESSAGE_MAP(CPathDialogSub, CWnd)
	ON_BN_CLICKED(IDOK, OnOK)
	ON_EN_CHANGE(IDC_NEW_EDIT_PATH, OnChangeEditPath)
END_MESSAGE_MAP()

void CPathDialogSub::OnOK()
{
	::GetWindowText(::GetDlgItem(m_hWnd, IDC_NEW_EDIT_PATH), m_pdlg->m_szPathName, MAX_PATH);

	if (CPathDialog::MakeSurePathExists(m_pdlg->m_szPathName) == 0) {
		m_pdlg->m_bSuccess = TRUE;

		::EndDialog(m_pdlg->m_hWnd, IDOK);
	}
	else {
		::SetFocus(::GetDlgItem(m_hWnd, IDC_NEW_EDIT_PATH));
	}
}

void CPathDialogSub::OnChangeEditPath()
{
	::GetWindowText(::GetDlgItem(m_hWnd, IDC_NEW_EDIT_PATH), m_pdlg->m_szPathName, MAX_PATH);

	SendMessage(BFFM_ENABLEOK, 0, _tcslen(m_pdlg->m_szPathName) > 0);
}

/////////////////////////////////////////////////////////////////////////////
// CPathDialog dialog
CPathDialog::CPathDialog(LPCTSTR pszCaption, LPCTSTR pszTitle, LPCTSTR pszInitialPath, CWnd* pParent)
{
	m_dlg.m_pdlg = this;

	m_hWnd = NULL;

    // Get the true parent of the dialog
    m_pwndParent = CWnd::GetSafeOwner(pParent);

	m_pszCaption     = pszCaption;
	m_pszInitialPath = pszInitialPath;

	memset(&m_bi, 0, sizeof(m_bi));
	m_bi.hwndOwner      = !m_pwndParent ? NULL : m_pwndParent->GetSafeHwnd();
	m_bi.pszDisplayName = 0;
	m_bi.pidlRoot       = 0;
//	m_bi.ulFlags        = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
	m_bi.ulFlags        = BIF_NEWDIALOGSTYLE;
	m_bi.lpfn           = BrowseCallbackProc;
	m_bi.lpszTitle      = pszTitle;
//	m_bi.lParam         = (LPARAM)pszInitialPath;
}


/////////////////////////////////////////////////////////////////////////////
// CPathDialog message handlers

CString CPathDialog::GetPathName()
{
	return m_szPathName;
}

int CALLBACK CPathDialog::BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam, LPARAM pData) 
{
	CPathDialog* pdlg = (CPathDialog*)pData;

	switch (uMsg) {
	case BFFM_INITIALIZED: 
		{
			pdlg->m_hWnd = hwnd;

			if (pdlg->m_pszCaption != NULL)
				::SetWindowText(hwnd, pdlg->m_pszCaption);

			VERIFY(pdlg->m_dlg.SubclassWindow(hwnd));

			::ShowWindow(::GetDlgItem(hwnd, IDC_STATUSTEXT), SW_HIDE);

			RECT rc;
			::GetWindowRect(::GetDlgItem(hwnd, IDC_FOLDERTREE), &rc);

			rc.bottom = rc.top    - 2;
			rc.top    = rc.bottom - 23;
			rc.left   = rc.left   + 2;
			::ScreenToClient(hwnd, (LPPOINT)&rc);
			::ScreenToClient(hwnd, ((LPPOINT)&rc) + 1);

			HWND hwndEdit = ::CreateWindowEx(WS_EX_CLIENTEDGE, _T("EDIT"), _T(""),
				WS_VISIBLE | WS_CHILD | WS_TABSTOP,
				rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
				hwnd, NULL, NULL, NULL);
			::SetWindowLong(hwndEdit, GWL_ID, IDC_NEW_EDIT_PATH);
			::ShowWindow(hwndEdit, SW_SHOW);

			HFONT hfont = (HFONT)::SendMessage(hwnd, WM_GETFONT, 0, 0);
			::SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));

			LPCTSTR lpszPath = pdlg->m_pszInitialPath;

			TCHAR szPath[MAX_PATH];
			if (lpszPath == NULL) {
				::GetCurrentDirectory(MAX_PATH, szPath);
				lpszPath = szPath;
			}

			if (GetFileAttributes(lpszPath) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND) {
				SHGetSpecialFolderPath(hwnd, szPath, CSIDL_PERSONAL, 0);
				lpszPath = szPath; 
			}
			else
				::SendMessage(hwnd,BFFM_SETSELECTION, TRUE, (LPARAM)lpszPath);

			::SetWindowText(::GetDlgItem(hwnd, IDC_NEW_EDIT_PATH), lpszPath);
		}

		break;
	case BFFM_SELCHANGED:
		{
			char szSelection[MAX_PATH];
//			if (!::SHGetPathFromIDList((LPITEMIDLIST)lParam, szSelection) || szSelection[1]!=':') {
			if (!::SHGetPathFromIDList((LPITEMIDLIST)lParam, szSelection)) {
				szSelection[0] = NULL;
				::SendMessage(hwnd, BFFM_ENABLEOK, 0, FALSE);
			}
			else {
				::SendMessage(hwnd, BFFM_ENABLEOK, 0, TRUE);
			}

//			::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szSelection);
			::SetWindowText(::GetDlgItem(hwnd, IDC_NEW_EDIT_PATH), szSelection);

			break;
		}
	default:
		break;
	}

	return 0;
}

int CPathDialog::DoModal() 
{
	TCHAR szDiaplayName[MAX_PATH];

    m_bi.lpfn           = BrowseCallbackProc;
    m_bi.lParam         = (LPARAM)this;
	m_bi.pszDisplayName = szDiaplayName;

	LPITEMIDLIST pidl;
	LPMALLOC     pmalloc;

	int nRet = -1;
	if (SUCCEEDED(SHGetMalloc(&pmalloc))) {
		m_bSuccess = FALSE;

		pidl = SHBrowseForFolder(&m_bi);
		if (pidl)
			pmalloc->Free(pidl);

		if (m_bSuccess)
			nRet = IDOK;

		pmalloc->Release();
	}

	return nRet;
}

BOOL CPathDialog::IsValidFileName(LPCTSTR pszFileName)
{
	if (pszFileName == NULL)
		return FALSE;

	int nLen = (int)_tcslen(pszFileName);
	if (nLen <= 0)
		return FALSE;

	//check first char
	switch (pszFileName[0]) {
	case _T('.'):
	case _T(' '):
	case _T('\t'):
		return FALSE;
	}

	//check last char
	switch (pszFileName[nLen-1]) {
	case _T('.'):
	case _T(' '):
	case _T('\t'):
		return FALSE;
	}

	//check all
	int i = 0;
	while (pszFileName[i] != 0) {
		switch (pszFileName[i]) {
		case _T('\\'):
		case _T('/'):
		case _T(':'):
		case _T('*'):
		case _T('?'):
		case _T('\"'):
		case _T('<'):
		case _T('>'):
		case _T('|'):
			return FALSE;
		}

		i++;
	}

	return TRUE;
}

const TCHAR c_FolderDoesNotPermission[] = _T(
	"폴더 : \n"
	"%s\n\n"
	"에 접근할 수 없습니다. 다른 위치를 선택하십시오."
);
const TCHAR c_FolderDoesNotExist[] = _T(
	"폴더 : \n"
	"%s\n\n"
	"가 존재하시 않습니다. 폴더를 생성하시겠습니까?"
);
const TCHAR c_szErrInvalidPath[] = _T(
	"폴더 : \n"
	"%s\n\n"
	"가 잘못되었습니다. 다시 입력하십시오."
);
const TCHAR c_szErrCreatePath[] = _T(
	"폴더 : \n"
	"%s\n\n"
	"를 만들 수 없습니다. 폴더이름을 확인하십시오."
);

//return -1: user break;
//return  0: no error
//return  1: lpPath is invalid
//return  2: can not create lpPath
int CPathDialog::MakeSurePathExists(LPCTSTR pszPath)
{
	int nRet;

	CString sMessage;

	try
	{
		//validate path
		nRet = Touch(pszPath, TRUE);
		if (nRet != 0)
			throw nRet;

		if (_access(pszPath, 06) == 0) {
			if (pszPath[0] == '\\' && pszPath[1] == '\\') {
				char szFile[MAX_PATH];
				if (GetTempFileName(pszPath, "she", 0, szFile) == 0) {
					sMessage.Format(c_FolderDoesNotPermission, pszPath);
					AfxMessageBox(sMessage, MB_ICONWARNING);
					return -1;
				}
				DeleteFile(szFile);
			}

			return 0;
		}

		if (errno == ENOENT) {
			sMessage.Format(c_FolderDoesNotExist, pszPath);
			if (AfxMessageBox(sMessage, MB_YESNO | MB_ICONQUESTION) != IDYES)
				return -1;

			//create path
			nRet = Touch(pszPath, FALSE);
			if (nRet != 0)
				throw nRet;
		}
		else if (errno == EACCES) {
			char szFile[MAX_PATH];
			if (!GetTempFileName(pszPath, "she", 0, szFile)) {
				sMessage.Format(c_FolderDoesNotPermission, pszPath);
				AfxMessageBox(sMessage, MB_ICONWARNING);
				return -1;
			}
			DeleteFile(szFile);
		}

		return 0;
	}
	catch (int nErrCode)
	{
		switch (nErrCode) {
		case 1:
			sMessage.Format(c_szErrInvalidPath, pszPath);
			break;
		case 2:
		default:
			sMessage.Format(c_szErrCreatePath, pszPath);
			break;
		}

		AfxMessageBox(sMessage, MB_OK | MB_ICONEXCLAMATION);
	}

	return nRet;
}

//return 0: no error
//return 1: lpPath is invalid
//return 2: lpPath can not be created(bValidate == FALSE)
int CPathDialog::Touch(LPCTSTR pszPath, BOOL bValidate)
{
	if (pszPath == NULL)
		return 1;

	TCHAR szPath[MAX_PATH];
	_tcscpy(szPath, pszPath);

	int nLen = (int)_tcslen(szPath);

	//path must be "x:\..."
/*
	if ((nLen < 3)
		|| ((szPath[0] < _T('A') || _T('Z') < szPath[0])
		&& (szPath[0] < _T('a') || _T('z') < szPath[0])
		|| (szPath[1] != _T(':')) || (szPath[2] != _T('\\'))))
*/

	if (nLen == 3) {
		if (!bValidate) {
			if (_access(szPath, 0)!=0) {
				return 2;
			}
		}

		return 0;
	}

	int i = 3;

	BOOL bLastOne = TRUE;
	LPTSTR lpCurrentName;
	while (szPath[i] != 0) {
		lpCurrentName = &szPath[i];
		while( (szPath[i]!=0) && (szPath[i]!=_T('\\')) )
		{
			i++;
		}

		bLastOne =(szPath[i]==0);
		szPath[i] = 0;

		if( !IsValidFileName(lpCurrentName) )
		{
			return 1;
		}

		if(!bValidate)
		{
			CreateDirectory(szPath, NULL);
			if(_taccess(szPath, 0)!=0)
			{
				return 2;
			}
		}

		if(bLastOne)
		{
			break; //it's done
		}
		else
		{
			szPath[i] = _T('\\');
		}

		i++;
	}

	return (bLastOne?0:1);
}

//return 0: ok
//return 1: error
int CPathDialog::ConcatPath(LPTSTR lpRoot, LPCTSTR lpMorePath)
{
	if (lpRoot==NULL)
		return 1;

	int nLen = (int)_tcslen(lpRoot);

	if (nLen<3)
		return 1;

	if (lpMorePath == NULL)
		return 0;

	if (nLen == 3) {
		_tcscat(lpRoot, lpMorePath);
		return 0;
	}

	_tcscat(lpRoot, _T("\\"));
	_tcscat(lpRoot, lpMorePath);

	return 0;
}
