// RLDropTarget.cpp : 구현 파일입니다.
//

#include "stdafx.h"
#include "ConsoleApp.h"
#include "RLDropTarget.h"
#include "MainFrm.h"
#include "RemoteView.h"
#include "RemoteTreeCtrl.h"
#include "RemoteListCtrl.h"


bool IsPathItself(CString sSrcPath, CString sDstPath);

// CRLDropTarget

IMPLEMENT_DYNAMIC(CRLDropTarget, COleDropTarget)
CRLDropTarget::CRLDropTarget()
{
}

CRLDropTarget::~CRLDropTarget()
{
}


BEGIN_MESSAGE_MAP(CRLDropTarget, COleDropTarget)
END_MESSAGE_MAP()


// CRLDropTarget 메시지 처리기입니다.
DROPEFFECT CRLDropTarget::OnDragEnter(CWnd* pwnd, COleDataObject* podo, DWORD dwKeyState, CPoint point)
{
	m_hwndFocused = GetFocus();

	((CRemoteView*)pwnd->GetParent())->m_bUpdating = TRUE;

	m_iPrevItem = -1;

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

	if (!pmf->m_bDragFromRemote) {
		if (!podo->IsDataAvailable(CF_HDROP))
			return DROPEFFECT_NONE;

		pmf->m_saDragSource.RemoveAll();
		if (!GetDragFileInfo(podo))
			return DROPEFFECT_NONE;
	}

	m_dePrev = DROPEFFECT_NONE;

	return OnDragOver(pwnd, podo, dwKeyState, point);
}

DROPEFFECT CRLDropTarget::OnDragOver(CWnd* pwnd, COleDataObject* podo, DWORD dwKeyState, CPoint point)
{
	DROPEFFECT de = DROPEFFECT_NONE;

	if (((CMainFrame*)AfxGetMainWnd())->m_saDragSource.GetCount() == 0)
		return de;

	CRemoteListCtrl* plist = (CRemoteListCtrl*)pwnd;

	plist->SetFocus();

	if (m_iPrevItem >= 0)
		plist->SetItemState(m_iPrevItem, m_dwPrevItemState, LVIS_SELECTED);

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

	int iItem = plist->HitTest(point);
	if (iItem < 0) {
		m_iPrevItem = -1;

		CRemoteTreeCtrl* ptree = ((CRemoteView*)pwnd->GetParent())->GetTreeCtrl();

		HTREEITEM htiSelected = ptree->GetSelectedItem();

		if (!pmf->m_bDragFromRemote) {
			if (htiSelected != ptree->GetRootItem())
				de = DROPEFFECT_COPY;
		}
		else {
			CString sSourcePath = pmf->m_saDragSource.GetAt(0);
			CString sTargetPath = ptree->GetPath(htiSelected);

			sSourcePath = sSourcePath.Left(sSourcePath.ReverseFind('/'));

			if (ptree->GetVolumeItem(htiSelected) == pmf->m_htiDragTarget
				&& sSourcePath != sTargetPath.Left(sSourcePath.GetLength()))
				de = dwKeyState & MK_CONTROL ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
		}
	}
	else {
		m_dwPrevItemState = plist->GetItemState(iItem, LVIS_SELECTED);
		plist->SetItemState(iItem, LVIS_SELECTED, LVIS_SELECTED);

		PRLISTITEM_STRUCT prli = (PRLISTITEM_STRUCT)plist->GetItemData(iItem);

		m_iPrevItem = iItem;

		if (prli->bFolder) {
			if (!pmf->m_bDragFromRemote)
				de = DROPEFFECT_COPY;
			else {
				CRemoteTreeCtrl* ptree = ((CRemoteView*)pwnd->GetParent())->GetTreeCtrl();

				HTREEITEM htiSelected = ptree->GetSelectedItem();

				if (htiSelected == ptree->GetRootItem()) {
					CString sPath = ((CRemoteListCtrl*)pwnd)->GetItemText(iItem, 0);
					HTREEITEM hti = ptree->GetChildItem(ptree->GetRootItem());
					while (hti) {
						if (sPath == ptree->GetItemText(hti)) {
							if (ptree->GetVolumeItem(hti) == pmf->m_htiDragTarget)
								de = dwKeyState & MK_CONTROL ? DROPEFFECT_COPY : DROPEFFECT_MOVE;

							break;
						}

						hti = ptree->GetNextSiblingItem(hti);
					}
				}
				else {
					CString sTargetPath = ptree->GetPath(htiSelected) + "/" + plist->GetItemText(iItem, 0);

					BOOL bAvail = TRUE;
					if (ptree->GetVolumeItem(htiSelected) != pmf->m_htiDragTarget)
						bAvail = FALSE;
					else {
						for (int i = 0; i < pmf->m_saDragSource.GetCount(); i++) {
							if (IsPathItself(pmf->m_saDragSource[i], sTargetPath)) {
								bAvail = FALSE;
								break;
							}
						}
					}

					if (bAvail)
						de = dwKeyState & MK_CONTROL ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
				}
			}
		}
	}

	m_dePrev = de;

	return de;
}

void CRLDropTarget::OnDragLeave(CWnd* pwnd)
{
	((CRemoteView*)pwnd->GetParent())->m_bUpdating = FALSE;

	if (m_iPrevItem >= 0) {
		CRemoteListCtrl* plist = (CRemoteListCtrl*)pwnd;

		plist->SetItemState(m_iPrevItem, m_dwPrevItemState, LVIS_SELECTED);
	}

	if (m_hwndFocused)
		CWnd::FromHandle(m_hwndFocused)->SetFocus();
}

BOOL CRLDropTarget::OnDrop(CWnd* pwnd, COleDataObject* podo, DROPEFFECT de, CPoint point)
{
	CString sPath = m_iPrevItem >= 0 ? "/" + ((CRemoteListCtrl*)pwnd)->GetItemText(m_iPrevItem, 0) : "";

	if (m_dePrev != DROPEFFECT_NONE) {
		CMainFrame*      pmf   = (CMainFrame*)AfxGetMainWnd();
		CRemoteTreeCtrl* ptree = ((CRemoteView*)pwnd->GetParent())->GetTreeCtrl();

		HTREEITEM hti = NULL;

		if (!pmf->m_bDragFromRemote) {
			// 리스트에 표시된 아이템이 볼륨이면...
			if (ptree->GetSelectedItem() == ptree->GetRootItem()) {
				hti = ptree->GetChildItem(ptree->GetRootItem());
				while (hti) 	{
					if (sPath.Mid(1) == ptree->GetItemText(hti)) {
						sPath = "";
						break;
					}

					hti = ptree->GetNextSiblingItem(hti);
				}
			}
			else {
				hti = ptree->GetSelectedItem();
			}

			pmf->m_sDragTarget   = ptree->GetPath(hti) + sPath;
			pmf->m_htiDragTarget = ptree->GetVolumeItem(hti);

			pmf->Upload(false);
		}
		else {
			HTREEITEM htiTarget = ptree->GetSelectedItem();
			if (htiTarget == ptree->GetRootItem())
				sPath = "";

			pmf->m_sDragTarget = ptree->GetPath(htiTarget) + sPath;

			pmf->BeginWaitMessage();

			CStringArray saSucceed;
			if (de == DROPEFFECT_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*)ptree->GetParent();
			for (int i = 0; i < saSucceed.GetCount(); i++) {
				HTREEITEM hti = ptree->GetItem(pmf->m_htiDragTarget, saSucceed[i]);
				if (!hti)
					continue;

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

			pmf->EndWaitMessage();

			if (saSucceed.GetCount() > 0)
				pmf->m_pRemoteView->RefreshItem();
		}
	}

	OnDragLeave(pwnd);

	return TRUE;
}

BOOL CRLDropTarget::GetDragFileInfo(COleDataObject* podo)
{
	STGMEDIUM sm;
	FORMATETC fe = {CF_HDROP, (DVTARGETDEVICE FAR*)NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};

	if (!podo->GetData(CF_HDROP, &sm, &fe))
		return FALSE;

	HDROP hdrop = (HDROP)sm.hGlobal;

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

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

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

		CString sFile(szFile);
		if (sFile.Find('\\') < 0) {
			pmf->m_saDragSource.RemoveAll();
			break;
		}

		pmf->m_saDragSource.Add(sFile);
	}

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

	return TRUE;
}
