// RemoteTreeCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "ConsoleApp.h"
#include "RemoteTreeCtrl.h"

#include "MainFrm.h"
#include "LocalView.h"
#include "RemoteView.h"

#include "BandwidthDlg.h"
#include "VolumeInfoDlg.h"
#include ".\remotetreectrl.h"


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

CString NumericFormat(__int64 nNumeric);
CString BYTE2KMBYTE(__int64 nBytes, int nFlag, bool bShowDecimalPoint);
bool IsPathItself(CString sSrcPath, CString sDstPath);

/////////////////////////////////////////////////////////////////////////////
// CRemoteTreeCtrl

CRemoteTreeCtrl::CRemoteTreeCtrl()
{
}

CRemoteTreeCtrl::~CRemoteTreeCtrl()
{
}


BEGIN_MESSAGE_MAP(CRemoteTreeCtrl, CTreeCtrl)
	//{{AFX_MSG_MAP(CRemoteTreeCtrl)
	//}}AFX_MSG_MAP
	ON_WM_CREATE()
	ON_NOTIFY_REFLECT(NM_RCLICK, OnNMRclick)
	ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBegindrag)
//	ON_WM_CONTEXTMENU()
	ON_COMMAND(ID_TREE_CUT, OnTreeCut)
	ON_COMMAND(ID_TREE_COPY, OnTreeCopy)
	ON_COMMAND(ID_TREE_PASTE, OnTreePaste)
	ON_COMMAND(ID_TREE_DELETE, OnTreeDelete)
	ON_COMMAND(ID_TREE_RENAME, OnTreeRename)
	ON_COMMAND(ID_TREE_SETANONY, OnTreeSetAnony)
	ON_COMMAND(ID_TREE_UNSETANONY, OnTreeUnsetAnony)
	ON_COMMAND(ID_TREE_SETBANDWIDTH, OnTreeSetBandwidth)
	ON_COMMAND(ID_TREE_INFO, OnTreeInfo)
//	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnTvnEndlabeledit)
//	ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnTvnBeginlabeledit)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRemoteTreeCtrl message handlers
BOOL CRemoteTreeCtrl::PreTranslateMessage(MSG* pMsg)
{
	CMainFrame *pmf = (CMainFrame *)AfxGetMainWnd();

	switch (pMsg->message)
	{
	case WM_SETFOCUS:
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDOWN:
		pmf->SetFocus(this);
		break;
	case WM_KEYDOWN:
		CEdit *edit = GetEditControl();
		if (edit) {
			if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) {
				edit->SendMessage(WM_KEYDOWN, pMsg->wParam, pMsg->lParam);
				return TRUE;
			}
		}
		else if (pMsg->wParam == VK_F2) {
			HTREEITEM hti = GetSelectedItem();
			if (!hti)
				return TRUE;
			if (!GetParentItem(hti))
				return TRUE;
			EditLabel(hti);
			return TRUE;
		}
		else if (pMsg->wParam == VK_DELETE) {
			((CRemoteView*)GetParent())->DeleteTreeItem(GetSelectedItem());
			return TRUE;
		}
		else if (GetKeyState(VK_CONTROL) & 128) {
			if (pMsg->wParam == VK_C) {
				SetClipboard(GetSelectedItem(), CBS_COPY);
				return TRUE;
			}
			else if (pMsg->wParam == VK_X) {
				SetClipboard(GetSelectedItem(), CBS_CUT);
				return TRUE;
			}
			else if (pMsg->wParam == VK_V) {
				PasteClipboard(GetSelectedItem());
				return TRUE;
			}
			else if (pMsg->wParam == VK_D) {
				HTREEITEM hti = GetSelectedItem();
				if (!hti || hti == GetRootItem() || GetParentItem(hti) == GetRootItem())
					return TRUE;

				m_htiSelected = hti;
				OnTreeDelete();
				return TRUE;
			}
		}
	}

	return CTreeCtrl::PreTranslateMessage(pMsg);
}

int CRemoteTreeCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//	if (CTreeCtrl::OnCreate(lpCreateStruct) == -1)
//		return -1;

	m_dropTarget.Register(this);

	SHFILEINFO shfi;
	HIMAGELIST hil = (HIMAGELIST)SHGetFileInfo("", 0, &shfi, sizeof(shfi), SHGFI_ICON | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
	SetImageList(CImageList::FromHandle(hil), TVSIL_NORMAL);

	return 0;
}

void CRemoteTreeCtrl::OnNMRclick(NMHDR *pNMHDR, LRESULT *pResult)
{
	DWORD dwPos = GetMessagePos();

	CPoint pt(GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos));
	CPoint ptHit = pt;

	ScreenToClient(&ptHit);

	if (m_htiSelected = HitTest(ptHit))
		OnContextMenu(this, pt);

	*pResult = 0;
}

void CRemoteTreeCtrl::OnContextMenu(CWnd* pWnd, CPoint point)
{
	if (m_htiSelected == GetRootItem())
		return;

	CMainFrame* pmf = (CMainFrame*)AfxGetMainWnd();

	CMenu menu, *pmenu;

	menu.LoadMenu(IDR_POP_RTREE);
	pmenu = menu.GetSubMenu(0);
	ASSERT(pmenu != NULL);

	pmenu->SetMenuItemBitmaps(ID_TREE_CUT, MF_BYCOMMAND, &pmf->m_bmCut, &pmf->m_bmCut);
	pmenu->SetMenuItemBitmaps(ID_TREE_COPY, MF_BYCOMMAND, &pmf->m_bmCopy, &pmf->m_bmCopy);
	pmenu->SetMenuItemBitmaps(ID_TREE_PASTE, MF_BYCOMMAND, &pmf->m_bmPaste, &pmf->m_bmPaste);

	PRTREEITEM_STRUCT prti = (PRTREEITEM_STRUCT)GetItemData(m_htiSelected);
	if (prti->nClass == TNS_VOLUME) {
		pmenu->EnableMenuItem(ID_TREE_CUT,    MF_GRAYED);
		pmenu->EnableMenuItem(ID_TREE_COPY,   MF_GRAYED);
		pmenu->EnableMenuItem(ID_TREE_DELETE, MF_GRAYED);
		pmenu->EnableMenuItem(ID_TREE_RENAME, MF_GRAYED);

		pmenu->DeleteMenu(6, MF_BYPOSITION);
		pmenu->DeleteMenu(ID_TREE_SETANONY,     MF_BYCOMMAND);
		pmenu->DeleteMenu(ID_TREE_UNSETANONY,   MF_BYCOMMAND);
		pmenu->DeleteMenu(ID_TREE_SETBANDWIDTH, MF_BYCOMMAND);
	}
	else {
		pmenu->DeleteMenu(10, MF_BYPOSITION);
//		pmenu->DeleteMenu(ID_TREE_INFO, MF_BYCOMMAND);

		if (((PRTREEITEM_STRUCT)GetItemData(GetParentItem(m_htiSelected)))->nClass != TNS_FOLDER) {
			pmenu->DeleteMenu(!atoi(prti->saAttr[1]) ? ID_TREE_UNSETANONY : ID_TREE_SETANONY, MF_BYCOMMAND);
		}
		else {
			pmenu->DeleteMenu(6, MF_BYPOSITION);
			pmenu->DeleteMenu(ID_TREE_SETANONY,     MF_BYCOMMAND);
			pmenu->DeleteMenu(ID_TREE_UNSETANONY,   MF_BYCOMMAND);
			pmenu->DeleteMenu(ID_TREE_SETBANDWIDTH, MF_BYCOMMAND);
		}
	}

	COleDataObject odo;
	if (!(odo.AttachClipboard() && odo.IsDataAvailable(CF_HDROP))
		&& !(pmf->m_cbs != CBS_NONE && pmf->m_saDragSource.GetCount() > 0))
		pmenu->EnableMenuItem(ID_TREE_PASTE, MF_GRAYED);

	pmenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);
}

void CRemoteTreeCtrl::OnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

	HTREEITEM hti = pNMTreeView->itemNew.hItem;
	if (hti == GetRootItem() || GetParentItem(hti) == GetRootItem())
		return;

	CMainFrame *pmf = (CMainFrame *)AfxGetMainWnd();
	pmf->m_bDragFromRemote = TRUE;
	pmf->m_htiDragTarget   = GetVolumeItem(hti);
	pmf->m_saDragSource.RemoveAll();
	pmf->m_saDragSource.Add(GetPath(hti));

	pmf->m_pLocalView->StartDrag();

	COleDataSource ods;
	DROPEFFECT de = ods.DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE, NULL);

	pmf->m_pLocalView->EndDrag();

	pmf->m_bDragFromRemote = FALSE;

	*pResult = 0;
}

void CRemoteTreeCtrl::OnTreeCut()
{
	SetClipboard(m_htiSelected, CBS_CUT);
}

void CRemoteTreeCtrl::OnTreeCopy()
{
	SetClipboard(m_htiSelected, CBS_COPY);
}

void CRemoteTreeCtrl::OnTreePaste()
{
	PasteClipboard(m_htiSelected);
}

void CRemoteTreeCtrl::OnTreeDelete()
{
	CMainFrame *pmf = (CMainFrame *)AfxGetMainWnd();

	pmf->m_pRemoteView->DeleteTreeItem(m_htiSelected);
}

void CRemoteTreeCtrl::OnTreeRename()
{
	EditLabel(m_htiSelected);
}

void CRemoteTreeCtrl::OnTreeSetAnony()
{
	CMainFrame *pmf = (CMainFrame *)AfxGetMainWnd();

	HTREEITEM htiVolume = GetVolumeItem(m_htiSelected);
	HCOMMLIB  hcl       = (HCOMMLIB)pmf->m_mapHcl[htiVolume];

	if (!cl_set_anonyauth(hcl, GetItemText(htiVolume), TRUE, GetItemText(m_htiSelected))) {
		AfxMessageBox(cl_get_error_message(hcl), MB_ICONERROR);
		return;
	}

	((CRemoteView*)GetParent())->SetAnonyFolder(htiVolume, GetItemText(m_htiSelected), true, true);

}

void CRemoteTreeCtrl::OnTreeUnsetAnony()
{
	CMainFrame *pmf = (CMainFrame *)AfxGetMainWnd();

	HTREEITEM htiVolume = GetVolumeItem(m_htiSelected);
	HCOMMLIB  hcl       = (HCOMMLIB)pmf->m_mapHcl[htiVolume];

	if (!cl_set_anonyauth(hcl, GetItemText(htiVolume), FALSE, GetItemText(m_htiSelected))) {
		AfxMessageBox(cl_get_error_message(hcl), MB_ICONERROR);
		return;
	}

	((CRemoteView*)GetParent())->SetAnonyFolder(htiVolume, GetItemText(m_htiSelected), false, true);
}

void CRemoteTreeCtrl::OnTreeSetBandwidth()
{
	CBandwidthDlg dlg;

	dlg.m_sPath  = GetPath(m_htiSelected);
	dlg.m_nLevel = 0;

	if (dlg.DoModal() != IDOK)
		return;

	CMainFrame* pmf = (CMainFrame*)AfxGetMainWnd();

	HTREEITEM htiVolume = GetVolumeItem(m_htiSelected);
	HCOMMLIB  hcl       = (HCOMMLIB)pmf->m_mapHcl[htiVolume];

//	if (!cl_set_anonyauth(hcl, GetItemText(htiVolume), FALSE, GetItemText(m_htiSelected))) {
//		AfxMessageBox(cl_get_error_message(hcl), MB_ICONERROR);
//		return;
//	}
}

void CRemoteTreeCtrl::OnTreeInfo()
{
	PRTREEITEM_STRUCT	prtiTree;
	HTREEITEM			htiVolume; 
	PRTREEITEM_STRUCT	prtiVolume;
	CString				sVolumeId;
	RFOLDERINFO_STRUCT	folderinfo;
	CVolumeInfoDlg		dlg;
	__int64				nTotalBytes;
	__int64				nUsedBytes;  

	BeginWaitCursor();

	CMainFrame *pmf = (CMainFrame *)AfxGetMainWnd();

	prtiTree = (PRTREEITEM_STRUCT)GetItemData(m_htiSelected);
	
	if(prtiTree->nClass == TNS_VOLUME)
	{
		pmf->UpdateVolumeInfo(m_htiSelected);

		htiVolume  = GetVolumeItem(m_htiSelected);
		prtiVolume = (PRTREEITEM_STRUCT)GetItemData(htiVolume);
		sVolumeId  = GetItemText(htiVolume);
		nTotalBytes = _atoi64(prtiVolume->saAttr[2]);
		nUsedBytes  = _atoi64(prtiVolume->saAttr[3]);
		dlg.m_sType = "서비스";
		dlg.m_sTitle = sVolumeId;
	}
	else
	{
		folderinfo.nCountFile = 0;
		folderinfo.nCountFolder = 0;
		folderinfo.nSize = 0;

		pmf->GetFolderInfo(m_htiSelected,&folderinfo);
		nTotalBytes = folderinfo.nSize;
		nUsedBytes = folderinfo.nSize;
		dlg.m_sType = "폴더";
		dlg.m_sTitle = folderinfo.strName;
	}
	
	dlg.m_sTotalSpace  = NumericFormat(nTotalBytes) + "Bytes";
	dlg.m_sTotalSpaceT = BYTE2KMBYTE(nTotalBytes, 0, TRUE);

	int     nFlag = 0;
	CString sUnit = dlg.m_sTotalSpaceT.Right(2);
	if (sUnit == "KB")
		nFlag = 1;
	else if (sUnit == "MB")
		nFlag = 2;
	else if (sUnit == "GB")
		nFlag = 3;
	else if (sUnit == "TB")
		nFlag = 4;

	__int64 nFreeBytes = nTotalBytes - nUsedBytes;
	dlg.m_sUseSpace    = NumericFormat(nUsedBytes) + "Bytes";
	dlg.m_sUseSpaceT   = BYTE2KMBYTE(nUsedBytes, nFlag, TRUE);
	dlg.m_sFreeSpace   = NumericFormat(nFreeBytes) + "Bytes";
	dlg.m_sFreeSpaceT  = BYTE2KMBYTE(nFreeBytes, nFlag, TRUE);

	dlg.DoModal();

	((CRemoteView*)GetParent())->ShowStatusSpace();

/*
	__int64 nTotalBytes, nUsedBytes;

	BOOL bRet = pdwft->GetVolumeInfo(GetPath(m_htiSelected), &nUsedBytes);

	pmf->RecycleConnection(pdwft);

	EndWaitCursor();

	if (!bRet) {
		CString sMsg;
		sMsg.Format("서비스 정보를 가져올 수 없습니다.\n%s", pdwft->GetErrorMessage());
		AfxMessageBox(sMsg, MB_ICONERROR);
		return;
	}

	CVolumeInfoDlg dlg;

	HTREEITEM htiVolume, hti = m_htiSelected;
	while (hti != GetRootItem()) {
		htiVolume = hti;

		hti = GetParentItem(hti);
	}
	PT_TREENODE ptn = (PT_TREENODE)GetItemData(htiVolume);

	dlg.m_sTitle = GetItemText(htiVolume);

	int iPos, iPos2;

	iPos = ptn->sAttribute.Find('|') + 1;
	iPos = ptn->sAttribute.Find('|', iPos) + 1;
	iPos2 = ptn->sAttribute.Find('|', iPos);

	nTotalBytes = _atoi64(ptn->sAttribute.Mid(iPos, iPos2 - iPos));
	if (GetParentItem(m_htiSelected) == GetRootItem()) {
		UpdateVolumeInfo(htiVolume, nUsedBytes);

		dlg.m_sType = "서비스";
	}
	else {
		dlg.m_sType = "폴더";
		dlg.m_sTitle += GetPath(m_htiSelected);
	}

	__int64 nFreeBytes = nTotalBytes - nUsedBytes;

	dlg.m_sTotalSpace  = NumericFormat(nTotalBytes) + "Bytes";
	dlg.m_sTotalSpaceT = BYTE2KMBYTE(nTotalBytes, 0, TRUE);

	int nFlag = 0;
	if (dlg.m_sType == "서비스") {
		CString sUnit = dlg.m_sTotalSpaceT.Right(2);

		if (sUnit == "KB")
			nFlag = 1;
		else if (sUnit == "MB")
			nFlag = 2;
		else if (sUnit == "GB")
			nFlag = 3;
		else if (sUnit == "TB")
			nFlag = 4;
	}

	dlg.m_sUseSpace    = NumericFormat(nUsedBytes) + "Bytes";
	dlg.m_sUseSpaceT   = BYTE2KMBYTE(nUsedBytes, nFlag, TRUE);
	dlg.m_sFreeSpace   = NumericFormat(nFreeBytes) + "Bytes";
	dlg.m_sFreeSpaceT  = BYTE2KMBYTE(nFreeBytes, nFlag, TRUE);

	dlg.DoModal();

	((CRemoteView*)GetParent())->ShowStatusSpace();
*/
}

HTREEITEM CRemoteTreeCtrl::InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	HTREEITEM hti = CTreeCtrl::InsertItem(lpszItem, hParent, hInsertAfter);

	if (TVI_ROOT != hParent)
		Sort(hParent);

	return hti;
}

HTREEITEM CRemoteTreeCtrl::InsertItem(LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	HTREEITEM hti = CTreeCtrl::InsertItem(lpszItem, nImage, nSelectedImage, hParent, hInsertAfter);

	if (TVI_ROOT != hParent)
		Sort(hParent);

	return hti;
}

BOOL CRemoteTreeCtrl::SetItemText(HTREEITEM hItem, LPCTSTR lpszItem)
{
	PRTREEITEM_STRUCT prti = (PRTREEITEM_STRUCT)GetItemData(hItem);
	if (prti)
		prti->saAttr[1] = prti->saAttr[1].Left(prti->saAttr[1].ReverseFind('/') + 1) + lpszItem;

	return CTreeCtrl::SetItemText(hItem, lpszItem);
}

BOOL CRemoteTreeCtrl::DeleteItem(HTREEITEM hItem)
{
	if(ItemHasChildren(hItem))
		DeleteChildItem(hItem);
	
	PRTREEITEM_STRUCT prti = (PRTREEITEM_STRUCT)GetItemData(hItem);
	if (prti)
	{
 		for (int i = 0; i < prti->paObject.GetCount(); i++)
 		{
// 			CString strTemp;
// 			strTemp.Format(_T("DeleteItem : %s"),((PRLISTITEM_STRUCT)prti->paObject[i])->sName);
//  			OutputDebugString(strTemp);
 			delete (PRLISTITEM_STRUCT)prti->paObject[i];
 		}
		prti->paObject.RemoveAll();
		prti->saAttr.RemoveAll();
		delete prti;
	}

	return CTreeCtrl::DeleteItem(hItem);
}

BOOL CRemoteTreeCtrl::DeleteAllItems()
{
	SetRedraw(FALSE);

	HTREEITEM hti = GetRootItem();
	while (hti)
	{
		HTREEITEM htiRoot = hti;
		while (hti)
		{
			if (ItemHasChildren(hti))
			{
				hti = GetChildItem(hti);
				continue;
			}
			else if (htiRoot == hti)
				break;

			HTREEITEM htiParent = GetParentItem(hti);
			DeleteItem(hti);
			hti = htiParent;
		}

		hti = GetNextSiblingItem(htiRoot);
		DeleteItem(htiRoot);
	}

	SetRedraw(TRUE);

	return TRUE;//CTreeCtrl::DeleteAllItems();
}

void CRemoteTreeCtrl::DeleteChildItem(HTREEITEM hti)
{
	OutputDebugString(_T("DeleteChildItem"));
	
	if (!hti)
		hti = GetSelectedItem();

	if (!hti)
		return;

	HTREEITEM htiCurrent = hti;

	SetRedraw(FALSE);
	while (hti)
	{
		if (ItemHasChildren(hti))
		{
			hti = GetChildItem(hti);
			continue;
		}
		else if (htiCurrent == hti)
			break;

		HTREEITEM htiParent = GetParentItem(hti);
		DeleteItem(hti);
		hti = htiParent;
	}

	SetRedraw(TRUE);

	PRTREEITEM_STRUCT prti = (PRTREEITEM_STRUCT)GetItemData(hti);
	if (prti) {
		for (int i = 0; i < prti->paObject.GetCount(); i++)
			delete (PRLISTITEM_STRUCT)prti->paObject[i];

		prti->paObject.RemoveAll();
	}
}

CString CRemoteTreeCtrl::GetPath(HTREEITEM hti)
{
	if (!hti)
		hti = GetSelectedItem();

	CString sPath = "";

	while (((PRTREEITEM_STRUCT)GetItemData(hti))->nClass == TNS_FOLDER) {
		sPath = "/" + GetItemText(hti) + sPath;

		hti = GetParentItem(hti);
	}

	return sPath;
}

HTREEITEM CRemoteTreeCtrl::GetVolumeItem(HTREEITEM hti)
{
	PRTREEITEM_STRUCT prti = (PRTREEITEM_STRUCT)GetItemData(hti);
	ASSERT(prti);
	if (prti->nClass == TNS_ROOT)
		return NULL;

	while (hti) {
		prti = (PRTREEITEM_STRUCT)GetItemData(hti);
		if (prti->nClass == TNS_VOLUME)
			break;

		hti = GetParentItem(hti);
	}

	return hti;
}

CString CRemoteTreeCtrl::GetVolumeText(HTREEITEM hti)
{
	while (hti && GetParentItem(hti) != GetRootItem())
		hti = GetParentItem(hti);

	return GetItemText(hti);
}

HTREEITEM CRemoteTreeCtrl::GetItem(HTREEITEM hti, CString sPath)
{
	if (sPath.Left(1) == "/")
		sPath.Delete(0);
	if (sPath.Right(1) == "/")
		sPath.Delete(sPath.GetLength());

	int     iToken = 0;
	CString sToken = sPath.Tokenize("/", iToken);
	while (sToken != "")
	{
		HTREEITEM htiChild = GetChildItem(hti);
		while (htiChild) {
			if (GetItemText(htiChild) == sToken)
				break;

			htiChild = GetNextSiblingItem(htiChild);
		}

		if (!htiChild)
			return NULL;

		hti    = htiChild;
		sToken = sPath.Tokenize("/", iToken);
	}

	return hti;
}

bool CRemoteTreeCtrl::IsExistsChild(HTREEITEM hti, CString sName)
{
	PRTREEITEM_STRUCT prti = (PRTREEITEM_STRUCT)GetItemData(hti);
	if (!prti)
		return false;

	for (int i = 0; i < prti->paObject.GetCount(); i++) {
		if (((PRLISTITEM_STRUCT)prti->paObject[i])->sName == sName)
			return true;
	}

	return false;
}

void CRemoteTreeCtrl::SetClipboard(HTREEITEM hti, CLIPBOARD_STATE cbs)
{
	if (OpenClipboard()) {
		EmptyClipboard();
		CloseClipboard();
	}

	if (!hti || hti == GetRootItem() || GetParentItem(hti) == GetRootItem())
		return;

	CMainFrame *pmf = (CMainFrame *)AfxGetMainWnd();

	pmf->m_saDragSource.RemoveAll();

	pmf->m_cbs           = cbs;
	pmf->m_htiDragTarget = GetVolumeItem(hti);
	pmf->m_saDragSource.Add(GetPath(hti));
}

void CRemoteTreeCtrl::PasteClipboard(HTREEITEM htiTarget)
{
	if (!htiTarget || htiTarget == GetRootItem())
		return;

	COleDataObject odo;

	if (odo.AttachClipboard() && odo.IsDataAvailable(CF_HDROP)) {
		STGMEDIUM sm;
		FORMATETC fe = {CF_HDROP, (DVTARGETDEVICE FAR*)NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};

		if (!odo.GetData(CF_HDROP, &sm, &fe))
			return;

		HDROP hdrop = (HDROP)sm.hGlobal;

		int nDragCount = ::DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0);
		if (nDragCount == 0)
			return;

		CMainFrame* pmf = (CMainFrame*)AfxGetMainWnd();

		pmf->m_saDragSource.RemoveAll();

		char szFile[MAX_PATH];
		for (int i = 0; i < nDragCount; i++) {
			::DragQueryFile(hdrop, i, szFile, sizeof(szFile));

			CString sFile(szFile);
			if (sFile.Find('\\') < 0) {
				AfxMessageBox("시스템 파일은 업로드 할 수 없습니다.");
				pmf->m_saDragSource.RemoveAll();
				break;
			}

			pmf->m_saDragSource.Add(sFile);
		}

		if (pmf->m_saDragSource.GetCount() == 0)
			return;

		pmf->m_sDragTarget   = GetPath(htiTarget);
		pmf->m_htiDragTarget = GetVolumeItem(htiTarget);

		pmf->Upload(false);
	}
	else {
		CMainFrame* pmf = (CMainFrame*)AfxGetMainWnd();

		if (pmf->m_cbs == CBS_NONE)
			return;

		if (pmf->m_saDragSource.GetCount() == 0)
			return;

		if (GetVolumeItem(htiTarget) != pmf->m_htiDragTarget) {
			AfxMessageBox("서로 다른 서비스사이에는 파일을 복사 또는 이동 할 수 없습니다.");
			return;
		}

		pmf->m_sDragTarget = GetPath(htiTarget);
		for (int i = 0; i < pmf->m_saDragSource.GetCount(); i++) {
			if (IsPathItself(pmf->m_saDragSource[i], pmf->m_sDragTarget)) {
				AfxMessageBox("자기 자신의 하위 폴더로 복사 또는 이동 할 수 없습니다.");
				return;
			}
		}

		pmf->BeginWaitMessage();

		CStringArray saSucceed;
		if (pmf->m_cbs == CBS_COPY)
			pmf->CopyRemoteObject(pmf->m_htiDragTarget, pmf->m_saDragSource, pmf->m_sDragTarget, saSucceed );
		else
			pmf->MoveRemoteObject(pmf->m_htiDragTarget, pmf->m_saDragSource, pmf->m_sDragTarget, saSucceed );

		CRemoteView* pview = (CRemoteView*)GetParent();
		for (int i = 0; i < saSucceed.GetCount(); i++) {
			HTREEITEM hti = GetItem(pmf->m_htiDragTarget, saSucceed[i]);
			if (!hti)
				continue;

			CString sName = saSucceed[i].Mid(saSucceed[i].ReverseFind('/') + 1);
			if (!IsExistsChild(htiTarget, sName))
				pview->AppendObject(htiTarget, true, sName, 0, "");
			if (pmf->m_cbs == CBS_CUT)
				DeleteItem(hti);
		}

		pmf->EndWaitMessage();

		if (saSucceed.GetCount() == 0)
			return;

		pmf->m_pRemoteView->RefreshItem();
	}
}

void CRemoteTreeCtrl::Sort(HTREEITEM hti)
{
	SortChildren(hti);
}