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

#include "stdafx.h"
#include <direct.h> 
#include "ConsoleTransfer.h"
#include "TransferDlg.h"

#include "Options.h"
#include "FileExistsDlg.h"
#include "EnterSomethingDlg.h"

#include "TransLogger.h"

#include "ne_socket.h"
#include "ne_uri.h"
#include "ne_request.h"
#include "ne_xml.h"
#include "ne_string.h"

#define RETRY_CNT	5

typedef struct COMMLIB_HANDLE {
	ne_session*  pnsess;
	ne_uri       nuri;
	string       sUserId;
	string       sPassword;
	string       sDavAuth;
	DWORD        dwError;
	string       sError;

	// 업/다운 관련
	HANDLE       hThread;
	HANDLE       hWaitEvent;
	UINT32       uJob;
	string       sJobParam;
	cl_callback  proc;
	void*        pParam;
	HANDLE       hTranFile;
	__int64		 nExFileSize;
	__int64      iTranPos;
	__int64      nFileSize;
	DWORD        dwOldTick;
	int          nTranStop;
	string       sRedirect;
	string		 sDomain2;

//	set<PCLSERVICE_STRUCT>  setServiceList;
//	set<PCLPATHINFO_STRUCT> setPathInfoList;
//	set<PCLFILE_STRUCT>     setFileList;
} COMMLIB_STRUCT, *PCOMMLIB_STRUCT;

CString GetErrorMessage(DWORD dwError);
CString BYTE2KMBYTE(__int64 nBytes, int nFlag, BOOL bShowDecimalPoint);
CString BYTE2KMBIT(__int64 nBytes, int nFlag, BOOL bShowDecimalPoint);
CString NumericFormat(__int64 nNumeric);
bool CreateDirectory(CString sDirectory);
bool DeleteDirectory(CString sDirectory);

// CTransferDlg 대화 상자입니다.

PCOMMLIB_STRUCT  m_pcl;

IMPLEMENT_DYNAMIC(CTransferDlg, CDialog)
CTransferDlg::CTransferDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTransferDlg::IDD, pParent)
	, m_szTargetPath(_T(""))
{
	m_hcl = NULL;

	m_bPaused = false;
	m_bResume = false;
	m_bStop   = false;
	m_pause_disabled = false;

	m_pthread = NULL;
	
	m_bUpdating = false;
	m_bUpdateMode = false;

	m_nTotalCount       = 0;
	m_nTotalSize        = 0;
	m_nTotalTransferred = 0;
	m_iTransfer         = 0;
	m_nElapsed          = 0;

	m_nGapTransfer = 0.5;

	m_nSelectedCount = 0;
	m_nSelectedSize  = 0;

	m_sSkippedFolder = "";

	m_retry_file = new TRANFILE_STRUCT;
	m_retry_tfinfo =new RETRY_TFINFO;
	m_retry_tfinfo->retryFile = m_retry_file;
	m_retry_tfinfo->doRetry = false;
	m_retry_tfinfo->retryCnt = 0;

	m_nFailedFileCount = 0;
}

CTransferDlg::~CTransferDlg()
{
	for (int i = 0; i < m_paTranFile.GetCount(); i++)
		delete (PTRANFILE_STRUCT)m_paTranFile[i];

	delete m_retry_tfinfo->retryFile;
	delete m_retry_tfinfo;

}

void CTransferDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_WB_ADVERT, m_wbAdvert);
	DDX_Control(pDX, IDC_TAB, m_tab);
	DDX_Control(pDX, IDC_BTN_DELFILE, m_btnDelFile);
	DDX_Control(pDX, IDC_LIST, m_list);
	DDX_Control(pDX, IDC_STC_STATUS, m_stcStatus);
	DDX_Control(pDX, IDC_GRP_NOW, m_grpNow);
	DDX_Control(pDX, IDC_STC_SPEED_TITLE, m_stcSpeedTitle);
	DDX_Control(pDX, IDC_STC_SPEED, m_stcSpeed);
	DDX_Control(pDX, IDC_STC_SAVEFILE_TITLE, m_stcSaveFileTitle);
	DDX_Control(pDX, IDC_STC_SAVEFILE, m_stcSaveFile);
	DDX_Control(pDX, IDC_PRS_NOW, m_prsNow);
	DDX_Control(pDX, IDC_GRP_TOTAL, m_grpTotal);
	DDX_Control(pDX, IDC_STC_ETIME_TITLE, m_stcETimeTitle);
	DDX_Control(pDX, IDC_STC_ETIME, m_stcETime);
	DDX_Control(pDX, IDC_STC_LTIME_TITLE, m_stcLTimeTitle);
	DDX_Control(pDX, IDC_STC_LTIME, m_stcLTime);
	DDX_Control(pDX, IDC_STC_FILE_COUNT_TITLE, m_stcFileCountTitle);
	DDX_Control(pDX, IDC_STC_FILE_COUNT, m_stcFileCount);
	DDX_Control(pDX, IDC_PRS_TOTAL, m_prsTotal);
	DDX_Control(pDX, ID_START, m_btnStart);
	DDX_Control(pDX, ID_PAUSE, m_btnPause);
	DDX_Control(pDX, ID_CLOSE, m_btnClose);
}


BEGIN_MESSAGE_MAP(CTransferDlg, CDialog)
	ON_WM_CLOSE()
	ON_WM_TIMER()
	ON_WM_SETCURSOR()

	ON_BN_CLICKED(IDC_BTN_DELFILE, OnBtnDelfile)
	ON_BN_CLICKED(ID_START, OnBtnStart)
	ON_BN_CLICKED(ID_PAUSE, OnBtnPause)
	ON_BN_CLICKED(ID_CLOSE, OnBtnClose)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, OnListItemChanged)
	ON_NOTIFY(LVN_KEYDOWN,     IDC_LIST, OnListKeydown)

	ON_MESSAGE(WMU_TRANSFER_IS_READY,  OnTransferIsReady)
	ON_MESSAGE(WMU_TRANSFER,           OnTransfer)
	ON_MESSAGE(WMU_TRANSFER_COMPLETED, OnTransferCompleted)
	ON_MESSAGE(WMU_TRANSFER_ERROR,     OnTransferError)
END_MESSAGE_MAP()


// CTransferDlg 메시지 처리기입니다.

BOOL CTransferDlg::OnInitDialog()
{
	typedef std::pair<CString,int> pairTranFile;

	CDialog::OnInitDialog();

	HICON hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	SetIcon(hIcon, TRUE);
	SetIcon(hIcon, FALSE);

	// X버튼 삭제
    ModifyStyle(NULL, WS_SYSMENU | WS_MINIMIZEBOX);
	CMenu *menu = GetSystemMenu(FALSE);
	RemoveMenu(menu->m_hMenu, 6, MF_BYPOSITION);

	BeginWaitCursor();

	for (int i = IDC_BTN_DELFILE; i <= IDC_PRS_TOTAL; i++)
		GetDlgItem(i)->SetParent(&m_tab);

	m_tab.SetWindowPos(&CWnd::wndBottom, 4, 4, 469, 321, NULL);
	m_tab.SetItemSize(CSize(130, 17));

	m_prsNow.SetRange(0, 100);
	m_prsNow.SetStep(1);
	m_prsNow.SetShowText(TRUE);
	m_prsNow.SetText(" ");

	m_prsTotal.SetRange(0, 100);
	m_prsTotal.SetStep(1);
	m_prsTotal.SetShowText(TRUE);
	m_prsTotal.SetText(" ");

	m_list.InsertColumn(0, "이름", LVCFMT_LEFT,   237);
	m_list.InsertColumn(1, "크기", LVCFMT_RIGHT,  80);
	m_list.InsertColumn(2, "종류", LVCFMT_CENTER, 60);
	m_list.InsertColumn(3, "상태", LVCFMT_CENTER, 60);

	m_list.SetExtendedStyle(LVS_EX_INFOTIP | LVS_EX_FULLROWSELECT);

	SHFILEINFO shfi;
	HIMAGELIST hil = (HIMAGELIST)SHGetFileInfo("C:\\", 0, &shfi, sizeof(shfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
	m_list.SetImageList(CImageList::FromHandle(hil), LVSIL_SMALL);

	if (m_tp.nAction == TPA_UPLOAD) {
		m_tab.InsertItem(0, "올리기 윈도우");
		m_sTitle = "파일 업로드";
	}
	else {
		m_tab.InsertItem(0, "내리기 윈도우");
		m_sTitle = "파일 다운로드";
	}
	SetWindowText(m_sTitle);

	for (int i = 0; i < m_tp.nFileListSize; ) {
		m_mapTranFile.insert(pairTranFile(&m_pszFileList[i], 0));
		i += ((int)strlen(&m_pszFileList[i]) + 1);
	}

	OutputDebugString(m_tp.szPassword);
	OutputDebugString(m_tp.szUserId);

#ifdef _OLD
	m_hcl = cl_init(m_tp.szHost, m_tp.szUserId, m_tp.szPassword, m_tp.szProxyHost, m_tp.nProxyPort);
#else
	m_hcl = cl_init(m_tp.szHost, "" , m_tp.szUserId, m_tp.szPassword, m_tp.szProxyHost, m_tp.nProxyPort);
#endif

	if (!m_hcl) {
		AfxMessageBox(GetErrorMessage(GetLastError()), MB_ICONERROR);
		return FALSE;
	}

	m_wbAdvert.ShowWindow(SW_HIDE);
	DocumentCompleteWBAdvert(NULL, NULL);

	CenterWindow();
	ShowWindow(SW_SHOW);

	m_btnDelFile.EnableWindow(FALSE);
	m_btnStart.EnableWindow(FALSE);
	m_btnPause.EnableWindow(FALSE);
	m_btnClose.SetWindowText("취소");
	m_pthread = AfxBeginThread(LoadTransferFile, this);

	cl_set_write_log_dir(m_tp.bLogDir);
	cl_set_write_log_upload(m_tp.bLogUpload);

	cl_create_log_file();

	EndWaitCursor();

	return TRUE;  // return TRUE unless you set the focus to a control
	// 예외: OCX 속성 페이지는 FALSE를 반환해야 합니다.
}

void CTransferDlg::OnClose()
{
	// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
	if (m_pthread) {
		m_bStop  = true;
		m_nTimer = (UINT)SetTimer(TIMER_ID_CLOSE, 100, 0);
		return;
	}

	if (m_hcl)
	{
		cl_free(m_hcl);
		m_hcl = NULL;
	}

	cl_destroy_log_file();

	if(!m_dlgResult.GetSafeHwnd())
		m_dlgResult.Create(IDD_RESULT_DLG, this);

	if(m_dlgResult.IsAlreadyShow())
		CDialog::OnClose();
	else
	{
		m_dlgResult.SetResult(m_nTotalCount, m_nFailedFileCount, m_strFailedFiles);
		m_dlgResult.ShowWindow(SW_SHOW);
		m_dlgResult.UpdateData(FALSE);
	}		
}

BOOL CTransferDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	SetCursor(LoadCursor(NULL, m_pthread ? IDC_APPSTARTING : IDC_ARROW));

	return TRUE;
//	return CDialog::OnSetCursor(pWnd, nHitTest, message);
}

void CTransferDlg::OnTimer(UINT nIDEvent)
{
	// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
	KillTimer(m_nTimer);
	m_nTimer = 0;

	if (nIDEvent == TIMER_ID_CLOSE) {
		PostMessage(WM_CLOSE);
	}
	if (nIDEvent == TIMER_ID_UPDATESTATUS) {
		ShowStatus(TRUE);
	}
	else if (nIDEvent == TIMER_ID_TRANSFER) {
		PostMessage(WMU_TRANSFER, CLWRITEPOLICY_NONE);
	}

	CDialog::OnTimer(nIDEvent);
}

void CTransferDlg::OnBtnDelfile()
{
	m_bUpdating = true;

	CDWordArray daSelected;
	int         i, nLastItem = -1;

	BOOL bFoundTransferred = FALSE;

	POSITION pos = m_list.GetFirstSelectedItemPosition();
	while (pos) {
		int iItem = m_list.GetNextSelectedItem(pos);

		if (iItem <= nLastItem)
			continue;

		if ((iItem > 0 && iItem <= m_iTransfer)
			|| (iItem == 0 && ((PTRANFILE_STRUCT)m_paTranFile[iItem])->nState != TFS_READY)) {
			bFoundTransferred = TRUE;
			continue;
		}

		PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[iItem];

		daSelected.Add(iItem);
		if (ptf->bFolder) {
			CString sPath = ptf->sSrcPath;
			sPath += "\\";

			int nLength = sPath.GetLength();

			for (i = iItem + 1; i < m_paTranFile.GetCount(); i++) {
				CString sSrcPath = ((PTRANFILE_STRUCT)m_paTranFile[i])->sSrcPath;
				if (sPath != sSrcPath.Left(nLength))
					break;

				daSelected.Add(i);
			}

			nLastItem = i - 1;
		}
	}

	if (bFoundTransferred)
		AfxMessageBox("전송중이거나 전송완료된 폴더 또는 파일은 삭제할 수 없습니다.", MB_ICONINFORMATION);

	for (int i = (int)daSelected.GetCount() - 1; i >= 0; i--) {
		PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[daSelected[i]];

		if (strncmp(ptf->sText, "   ", 3) != 0)
			m_mapTranFile.erase(ptf->sSrcPath);

		for (std::map<CString,int>::iterator iter = m_mapTranFile.begin(); iter != m_mapTranFile.end(); iter++) {
			if (iter->second >= (int)daSelected[i])
				iter->second--;
		}

		delete ptf;

		m_list.DeleteItem(daSelected[i]);
		m_paTranFile.RemoveAt(daSelected[i]);
	}

	m_bUpdating = FALSE;

	ShowStatus();

	if (m_nTotalCount > 0 && ((PTRANFILE_STRUCT)m_paTranFile[0])->nState != TFS_READY) {
		ShowFileCount();
		ShowTotalProgress();
	}
	else {
		AfxMessageBox("전송 할 파일이 없습니다.");
		PostMessage(WM_CLOSE);
	}
}

void CTransferDlg::OnBtnStart()
{
	m_btnStart.EnableWindow(FALSE);
	m_btnPause.EnableWindow(TRUE);
	m_btnPause.SetFocus();
	Pause(false);

	InitTransferEnv();

	ShowStatus();

	PostMessage(WMU_TRANSFER, CLWRITEPOLICY_NONE);
}

void CTransferDlg::OnBtnPause()
{
	if(!m_pause_disabled)
	{
		if (m_bPaused) {
			Pause(false);

			InitTransferEnv();

			ShowStatus();

			m_nBaseFileSize = m_nTransferredSize;
			PostMessage(WMU_TRANSFER, CLWRITEPOLICY_APPEND);
		}
		else {
			m_btnPause.EnableWindow(FALSE);
			m_bPaused = TRUE;

			WriteDebugLog("" , "" ,"cl_stop_transfer(m_hcl)#0");

			cl_stop_transfer(m_hcl);

		}

	}
}

void CTransferDlg::OnBtnClose()
{
	if (TPA_UPLOAD == m_tp.nAction)
	{
		/////////////////////////////////////////////////////
		///전송창 닫을때, 이 전송트랙젠셕이 끝났음을 알린다.

		CConsoleTransferApp* pwp = (CConsoleTransferApp*) AfxGetApp();
		pwp->NoticeLastFileTransComplete();

		////////////////////////////////////////////////////
	}

	PostMessage(WM_CLOSE);
}

void CTransferDlg::OnListItemChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
	if (m_pthread)
		return;

	if (m_tp.nAction != TPA_UPLOAD || m_bUpdating)
		return;

	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

	if (!(pNMLV->uChanged & LVIS_DROPHILITED))
		return;

	if (pNMLV->uNewState & LVIS_SELECTED && !(pNMLV->uOldState & LVIS_SELECTED)) {
		m_nSelectedCount++;

		PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[pNMLV->iItem];
		if (!ptf->bFolder)
			m_nSelectedSize += ptf->nSize;
	}
	else if (!(pNMLV->uNewState & LVIS_SELECTED) && pNMLV->uOldState & LVIS_SELECTED) {
		m_nSelectedCount--;

		PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[pNMLV->iItem];
		if (!ptf->bFolder)
			m_nSelectedSize -= ptf->nSize;
	}

	if (m_nTimer != 0)
		KillTimer(m_nTimer);

	m_nTimer = (UINT)SetTimer(TIMER_ID_UPDATESTATUS, 10, 0);

	*pResult = 0;
}

void CTransferDlg::OnListKeydown(NMHDR *pNMHDR, LRESULT *pResult)
{
	if (m_pthread)
		return;

	LPNMLVKEYDOWN pLVKeyDow = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);

	if (GetKeyState(VK_CONTROL) & 128 && pLVKeyDow->wVKey == VK_A) {
		m_bUpdating = true;
		for (int i = 0; i < m_list.GetItemCount(); i++)
			m_list.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
		m_bUpdating = false;
		ShowStatus(true, false, true);
	}

	*pResult = 0;
}

LRESULT CTransferDlg::OnTransferIsReady(WPARAM wParam, LPARAM)
{
	if (m_bStop)
		return S_FALSE;

	m_btnStart.EnableWindow(TRUE);
	m_btnPause.EnableWindow(TRUE);
	m_btnClose.SetWindowText("닫기");

	LoadWritePolicy();

	ShowStatus();

	if (m_list.GetItemCount() == 0) {
		AfxMessageBox("전송할 파일이 없습니다.");
		PostMessage(WM_CLOSE);
		return S_FALSE;
	}

#ifndef _DEBUG
	OnBtnStart();
#endif

	return S_OK;
}

LRESULT CTransferDlg::OnTransfer(WPARAM wParam, LPARAM)
{
	int recvFailCnt=0;
	m_pause_disabled = false;

	if (m_bPaused) {
		Pause();
		return S_OK;
	}

	DWORD dwTick = GetTickCount();
	PTRANFILE_STRUCT ptf;

	if (false == m_retry_tfinfo->doRetry)
	{
		m_retry_tfinfo->retryCnt = 0;
		
		ptf = NULL;

		for (int i = m_iTransfer; i < m_paTranFile.GetCount(); i++) {
			ptf = (PTRANFILE_STRUCT)m_paTranFile[m_iTransfer];

			if (ptf->nState == TFS_TRANSFERRING)
				return S_FALSE;

			if (ptf->nState >= TFS_COMPLETE && ptf->nState <= TFS_STOP)
				continue;

			m_iTransfer = i;
			
			m_retry_tfinfo->retryFile->bFolder = ptf->bFolder;
			m_retry_tfinfo->retryFile->nSize = ptf->nSize;
			m_retry_tfinfo->retryFile->nState = ptf->nState;
			m_retry_tfinfo->retryFile->nTransferredSize = ptf->nTransferredSize;
			m_retry_tfinfo->retryFile->sLastModified = ptf->sLastModified;
			m_retry_tfinfo->retryFile->sSrcPath = ptf->sSrcPath;
			m_retry_tfinfo->retryFile->sDstPath = ptf->sDstPath; // 이거 왜 지우셨더랬나용!! -pizon : sorry...ㅠㅠ
			m_retry_tfinfo->retryFile->sText = ptf->sText;
				
			//memcpy( m_retry_tfinfo->retryFile , ptf , sizeof(TRANFILE_STRUCT));

			break;
		}
	}
	else
	{
		(m_retry_tfinfo->retryCnt)++;

		ptf = m_retry_tfinfo->retryFile;
	}

	// add by rokmc777...
	// m_iTransfer가 m_nTotalCount보다 커질경우에도 계속 돈다(특히 강제로 네트웍을 끊을때).. 원인찾기전에 임시로...
	if(!ptf)
	{
		PostMessage(WM_CLOSE);
		return S_FALSE;
	}

	m_bUpdating = true;

	if (m_iTransfer > 0)
		m_list.SetItemState(m_iTransfer - 1, 0, LVIS_SELECTED | LVIS_FOCUSED);

	m_list.SetItemState(m_iTransfer, LVIS_SELECTED, LVIS_SELECTED);
	m_list.SetItemText(m_iTransfer, 3, "전송중");
	m_list.EnsureVisible(m_iTransfer, TRUE);

	m_bUpdating = false;

	if (m_sSkippedFolder != "") 
	{
		CString m_sSrcPath = ptf->sSrcPath;

		if (m_sSkippedFolder == m_sSrcPath.Left(m_sSkippedFolder.GetLength())) {
			if (!ptf->bFolder)
				m_nTotalTransferred += ptf->nSize;

			ptf->nState = TFS_SKIPED;
			m_list.SetItemText(m_iTransfer, 3, "건너뜀");

			m_iTransfer++;

			//if (m_iTransfer < m_nTotalCount) {
			if (m_iTransfer <= m_nTotalCount) {
				m_bResume = false;
				m_nTimer = (UINT)SetTimer(TIMER_ID_TRANSFER, 100, 0);
			}
			else {
				PostMessage(WM_CLOSE);
			}

			ShowProgressStatus(m_nTotalTransferred);
			return S_OK;
		}
		else
			m_sSkippedFolder = "";
	}

	if (m_bPaused) {
		Pause();
		return S_OK;
	}

	ptf->nState = TFS_TRANSFERRING;

	CString sFileName, sDstPath;
	if (m_tp.nAction == TPA_UPLOAD) 
	{
		sFileName = ptf->sSrcPath;

		m_szTargetPath = m_tp.szDstPath + ptf->sDstPath;
		m_szTargetPath.Replace("//", "/");

		if( (m_nWriteAction == FILEEXISTS_UPDATE || m_bUpdateMode) && (!ptf->bFolder) /*파일일때만 수행 add by pizon*/ )
		{
			sDstPath = m_tp.szDstPath + GetHashedPath(ptf->sDstPath);
			sDstPath.Replace("//", "/");

			m_szHashedTargetPath = sDstPath;
		}
		else
			sDstPath = m_szTargetPath;
	}
	else {
		sFileName = m_tp.szDstPath + ptf->sDstPath;
		sFileName.Replace("\\\\", "\\");
	}

	m_stcSaveFile.SetWindowText(sFileName);
	ShowFileCount();

	int nWritePolicy = (int)wParam;

	BOOL bRet = FALSE;

	m_nCurrentFileSize = ptf->nSize;
	if (nWritePolicy != CLWRITEPOLICY_APPEND) {
		m_nBaseFileSize    = 0;
		m_nTransferredSize = 0;
	}

	m_dwOldTick = GetTickCount();
	if (m_tp.nAction == TPA_UPLOAD) {
		if (ptf->bFolder) 
		{
			PCLFILE_STRUCT pclfl = cl_get_file_list(m_hcl, sDstPath, 0, NULL);
			if (!pclfl)
			{
				WriteDebugLog("" , sDstPath ,"bRet = cl_make_directory(m_hcl, sDstPath);#1");
				bRet = cl_make_directory(m_hcl, sDstPath);
				if (bRet)
					PostMessage(WMU_TRANSFER_COMPLETED);
				else
				{
					AddFailedFile(sDstPath, true);
					m_sError = cl_get_error_message(m_hcl);
				}
			}
			else
			{
				bRet = TRUE;
// 폴더에 대해서 writepolicy 를 건너띔으로 설정하면 폴더밑에 파일들에도 같이 정책이 적용되기에
// 폴더에 대해서는 writepolicy 를 묻지않고 completed 시킨다(즉 overwrite)
//				if (nWritePolicy != CLWRITEPOLICY_OVERWRITE) {
//					m_dwError = CLERRNO_EXISTSFILE;
//					PostMessage(WMU_TRANSFER_ERROR);
//				}
//				else

				PostMessage(WMU_TRANSFER_COMPLETED);
			}
			cl_free_file_list(m_hcl, pclfl);

			m_nGapTransfer = (GetTickCount() - dwTick + 100) * 0.001;
			ShowProgressStatus(m_nTotalTransferred);
		}
		else 
		{
			if(m_nWriteAction == FILEEXISTS_UPDATE)
				nWritePolicy = CLWRITEPOLICY_OVERWRITE;
			
			WriteDebugLog(sFileName , sDstPath ,"bRet = cl_upload(m_hcl, sFileName, sDstPath, nWritePolicy, m_tp.nFreeBytes, TransferCallbackProc, this );#2");		

			bRet = cl_upload(m_hcl, sFileName, sDstPath, nWritePolicy, m_tp.nFreeBytes, TransferCallbackProc, this );
		}
	}
	else {
		if (ptf->bFolder) {
			CFileStatus64 fs;
			if (!GetStatus64(sFileName, fs) && GetLastError() == ERROR_FILE_NOT_FOUND) {
				bRet = CreateDirectory(sFileName);
				if (bRet)
					PostMessage(WMU_TRANSFER_COMPLETED);
				else
					m_sError = GetErrorMessage(m_dwError);
			}
			else {
				if (nWritePolicy != CLWRITEPOLICY_OVERWRITE) {
					bRet = TRUE;
					m_dwError = CLERRNO_EXISTSFILE;
					PostMessage(WMU_TRANSFER_ERROR);
				}
				else {
					if (fs.m_attribute & CFile::directory) {
						bRet = TRUE;
						PostMessage(WMU_TRANSFER_COMPLETED);
					}
					else {
						bRet = DeleteFile(sFileName);
						if (bRet) {
							((PTRANFILE_STRUCT)m_paTranFile[m_iTransfer])->nState = TFS_READY;
							PostMessage(WMU_TRANSFER);
						}
						else
							m_sError = GetErrorMessage(m_dwError);
					}
				}
			}

			m_nGapTransfer = (GetTickCount() - dwTick + 100) * 0.001;
			ShowProgressStatus(m_nTotalTransferred);
		}
		else {
			bRet = cl_download(m_hcl, ptf->sSrcPath, sFileName, nWritePolicy, m_tp.nFreeBytes, TransferCallbackProc, this);
			if (!bRet)
				m_sError = cl_get_error_message(m_hcl);
		}
	}

	if (!bRet) {

		m_sError = "에러가 발생했습니다.\n에러내용 : " + m_sError + "\n계속 하시겠습니까?";

		if (m_tp.nAction != TPA_UPLOAD)	{
			if (AfxMessageBox(m_sError, MB_YESNO | MB_ICONERROR) != IDYES) {
				PostMessage(WM_CLOSE);
				return S_FALSE;
			}
		}

		ptf->nState = TFS_ERROR;
		m_list.SetItemText(m_iTransfer, 3, "오류");

		m_iTransfer++;
		m_nTimer = (UINT)SetTimer(TIMER_ID_TRANSFER, 100, 0);
	}

	return S_OK;
}

LRESULT CTransferDlg::OnTransferCompleted(WPARAM wParam, LPARAM)
{
	if (m_bPaused) {
		Pause();
		return S_OK;
	}

	HTREEITEM htiVolume = (HTREEITEM) m_tp.pParam;
	CMapPtrToPtr mapHcl;

	HCOMMLIB  hcl       = (HCOMMLIB)mapHcl[htiVolume];
	PCOMMLIB_STRUCT m_pcl = (PCOMMLIB_STRUCT)hcl;

	PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[m_iTransfer];
	if (!ptf->bFolder) {
		m_nSpeedTransferred += (ptf->nSize - m_nBaseFileSize);

		m_nTotalTransferred += ptf->nSize;
		m_tp.nFreeBytes     -= (ptf->nSize - m_nBaseFileSize);
	}

	ptf->nState = TFS_COMPLETE;
	m_retry_tfinfo->doRetry = false;

	if( (!ptf->bFolder /*파일일때만 수행 add by pizon*/ ) 
	  && (ptf->nState == TFS_COMPLETE )
	  && (m_nWriteAction == FILEEXISTS_UPDATE || m_bUpdateMode) )
	{
		m_bUpdateMode = false;

#if 0 /* delete 안하고 , cl_move OVERWRITE  add by pizon */

		WriteDebugLog("" , m_szTargetPath ,"if(!cl_delete(m_hcl, m_szTargetPath))#3");		

		if(!cl_delete(m_hcl, m_szTargetPath))
		{
			if(cl_get_error_number(m_hcl) != CLERRNO_NOEXISTSFILE)
			{
				//AfxMessageBox(cl_get_error_message(hcl), MB_ICONERROR);
				return E_FAIL;
			}
		}

#endif
		FileOptLogsRequest(ptf);

		WriteDebugLog(m_szHashedTargetPath , m_szTargetPath ,"if(!cl_move(m_hcl, m_szHashedTargetPath, m_szTargetPath, true))#4");		

		if(!cl_move(m_hcl, m_szHashedTargetPath, m_szTargetPath, true))
		{
			//AfxMessageBox(cl_get_error_message(m_hcl), MB_ICONERROR);
			return E_FAIL;
		}
	}
	
	// 파일 분산 배포 요청/////////////////////////////////////////////
	if (!ptf->bFolder && TFS_COMPLETE == ptf->nState && TPA_UPLOAD == m_tp.nAction) 
//	if (TFS_COMPLETE == ptf->nState) 
	{
		// 말그대로 일시정시버튼의 일시정지.
		this->m_pause_disabled = true;

		CConsoleTransferApp* pwp = (CConsoleTransferApp*) AfxGetApp();

		pwp->NoticeTransComplete(m_szTargetPath);

	}
	//////////////////////////////////////////////////////////////////
	else
	{
		// 폴더일때나 다운로드일때 걍 완료(배포요청안함)
		this->TransCompleteWithDistribute();
	}

	return S_OK;
}
void CTransferDlg::TransCompleteWithDistribute()
{
	m_list.SetItemText(m_iTransfer, 3, "완료");

	m_iTransfer++;

	m_nBaseFileSize    = m_nTransferredSize;
	//	m_nBaseFileSize    = 0;
	m_nTransferredSize = 0;

	//if (m_iTransfer < m_nTotalCount) {
	if (m_iTransfer <= m_nTotalCount) {
		m_bResume = FALSE;
		m_nTimer = (UINT)SetTimer(TIMER_ID_TRANSFER, 100, 0);
	}
	else {

		if (TPA_UPLOAD == m_tp.nAction)
		{
			/////////////////////////////////////////////////////
			///전송창 닫을때, 이 전송트랙젠셕이 끝났음을 알린다.

			CConsoleTransferApp* pwp = (CConsoleTransferApp*) AfxGetApp();
			pwp->NoticeLastFileTransComplete();

			////////////////////////////////////////////////////
		}


		PostMessage(WM_CLOSE);
	}
}

LRESULT CTransferDlg::OnTransferError(WPARAM, LPARAM)
{
	UINT nMessage = WMU_TRANSFER_ERROR;

	PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[m_iTransfer];
	if (m_dwError == CLERRNO_EXISTSFILE) {
		TRANFILE_STRUCT tfOld;

		if (m_tp.nAction == TPA_UPLOAD) {
			CString sDstPath = m_tp.szDstPath + ptf->sDstPath;
			sDstPath.Replace("//", "/");
			PCLFILE_STRUCT pclfl = cl_get_file_list(m_hcl, sDstPath, 0, NULL);
			if (!pclfl) {
				m_sError = cl_get_error_message(m_hcl);
				cl_free_file_list(m_hcl, pclfl);
				goto MARK_ERROR;
			}

			tfOld.sDstPath      = pclfl->path;
			tfOld.sLastModified = pclfl->lastModified;
			tfOld.nSize = pclfl->attr & CLFILEATTR_FOLDER ? -1 : pclfl->size;

			cl_free_file_list(m_hcl, pclfl);
		}
		else {
			CFileStatus64 fs;

			CString sDstPath = m_tp.szDstPath + ptf->sDstPath;
			sDstPath.Replace("\\\\", "\\");
			if (!GetStatus64(sDstPath, fs)) {
				m_sError = GetErrorMessage(GetLastError());
				goto MARK_ERROR;
			}

			CString sLastModified = fs.m_mtime.Format("%Y-%m-%d %p %I:%M:%S");
			if (sLastModified.Replace("AM", "오전") == 0)
				sLastModified.Replace("PM", "오후");

			tfOld.sDstPath      = sDstPath;
			tfOld.sLastModified = sLastModified;
			tfOld.nSize = fs.m_attribute & CFile::directory ? -1 : fs.m_size;
		}

		CTimeSpan ts = CTime::GetCurrentTime() - m_tmStart;
		m_nElapsed += ts.GetTotalSeconds();

        int nAction = GetAction(tfOld.sDstPath, tfOld.sLastModified, tfOld.nSize,
			ptf->sSrcPath, ptf->sLastModified, ptf->nSize);

		if(nAction == FILEEXISTS_UPDATE)
			m_bUpdateMode = true;
		else
			m_bUpdateMode = false;

		m_nSpeedTransferred = 0;
		m_nSpeedTick        = GetTickCount();

		CEnterSomethingDlg dlg(IDS_INPUTDLGTITLE_RENAME, IDS_INPUTDLGTEXT_RENAME, FALSE, this);

		switch (nAction) {
		case FILEEXISTS_OVERWRITE:
			m_nWriteAction = CLWRITEPOLICY_OVERWRITE;
			ptf->nState    = TFS_READY;

			// OVERWRITE 의 경우에는 이전파일 삭제로그를 남김
			this->FileOptLogsRequest(ptf);
			
			break;
		case FILEEXISTS_UPDATE:
			ptf->nState    = TFS_READY;
			break;
		case FILEEXISTS_RESUME:
			m_nWriteAction        = CLWRITEPOLICY_APPEND;
			m_nBaseFileSize       = tfOld.nSize;
			ptf->nTransferredSize = tfOld.nSize;
			ptf->nState           = TFS_READY;
			break;
		case FILEEXISTS_RENAME:
			m_nWriteAction = CLWRITEPOLICY_NONE;
			dlg.m_String   = ptf->sDstPath;
			dlg.m_String   = dlg.m_String.Mid(dlg.m_String.ReverseFind(m_tp.nAction == TPA_UPLOAD ? '/' : '\\') + 1);
			if (dlg.DoModal() != IDOK) {
				m_nSpeedTransferred = 0;
				m_nSpeedTick        = GetTickCount();

				goto SKIP_CURRENTFILE;
			}
			else {
				m_nSpeedTransferred = 0;
				m_nSpeedTick        = GetTickCount();

				CString sSeparator = m_tp.nAction == TPA_UPLOAD ? "/" : "\\";
				CString sSrcPath   = ptf->sDstPath + sSeparator;
				CString sDstPath   = ptf->sDstPath;

				sDstPath = sDstPath.Left(sDstPath.ReverseFind(sSeparator[0]) + 1) + dlg.m_String;
				if (ptf->bFolder) {
					int nLength = sSrcPath.GetLength();
					for (int i = m_iTransfer + 1; i < m_paTranFile.GetCount(); i++) {
						PTRANFILE_STRUCT ptfSub = (PTRANFILE_STRUCT)m_paTranFile[i];

						CString sSubDstPath = ptfSub->sDstPath;
						if (sSrcPath != sSubDstPath.Left(nLength))
							break;

						sSubDstPath.Replace(sSrcPath, sDstPath + sSeparator);
						ptfSub->sDstPath = sSubDstPath;
					}
				}
				ptf->sDstPath = sDstPath;
				ptf->nState   = TFS_READY;
			}
			break;
		default:
SKIP_CURRENTFILE:
			if (!ptf->bFolder)
				m_nTotalTransferred += ptf->nSize;
			
			ptf->nState = TFS_SKIPED;
			m_list.SetItemText(m_iTransfer, 3, "건너뜀");
			if (ptf->bFolder) {
				m_sSkippedFolder  = ptf->sSrcPath;
				m_sSkippedFolder += "\\";
			}
			nMessage  = WMU_TRANSFER_COMPLETED;
			m_tmStart = CTime::GetCurrentTime();
			goto TRANSFER_NEXTFILE;
			break;
		}

		m_tmStart = CTime::GetCurrentTime();

		PostMessage(WMU_TRANSFER, m_nWriteAction);
		return S_OK;
	}

MARK_ERROR:

	m_sError = "에러가 발생했습니다.\n에러내용 : " + m_sError + "\n계속 하시겠습니까?";

//	if ((6==this->m_dwError||1==this->m_dwError) && (TPA_UPLOAD == this->m_tp.nAction) )
	if ( (TPA_UPLOAD == this->m_tp.nAction) )
	{
		if ((this->m_retry_tfinfo->retryCnt < RETRY_CNT))
		{
			this->m_retry_tfinfo->doRetry = true;
			this->PostMessage(WMU_TRANSFER, CLWRITEPOLICY_OVERWRITE);
			return S_OK;
		}
		else
		{
			this->SendMailWhenUploadFail(this->m_retry_tfinfo->retryFile->sSrcPath);
			this->WriteWhenUploadFail(this->m_retry_tfinfo->retryFile->sSrcPath , this->m_retry_tfinfo->retryFile->sDstPath);
			AddFailedFile(m_retry_tfinfo->retryFile->sSrcPath, false);
			this->PostMessage(WMU_TRANSFER_COMPLETED);
			return S_OK;
		}
	}
	else
	{
		if (AfxMessageBox(m_sError, MB_YESNO | MB_ICONERROR) != IDYES) {
			PostMessage(WM_CLOSE);
			return S_FALSE;
		}
	}

	m_nSpeedTransferred = 0;
	m_nSpeedTick        = GetTickCount();

	ptf->nState = TFS_ERROR;
	m_list.SetItemText(m_iTransfer, 3, "오류");

TRANSFER_NEXTFILE:
	m_iTransfer++;

	//if (m_iTransfer < m_nTotalCount) {
	if (m_iTransfer <= m_nTotalCount) {
		m_bResume = FALSE;
		m_nTimer = (UINT)SetTimer(TIMER_ID_TRANSFER, 100, 0);
	}
	else {
		PostMessage(WM_CLOSE);
	}

	return S_OK;
}

void CTransferDlg::TransferCallbackProc(LPVOID pParam, __int64 nTransferred)
{
	CTransferDlg* pdlg = (CTransferDlg*)pParam;

	if (nTransferred == 0) {
		pdlg->PostMessage(WMU_TRANSFER_COMPLETED);
		return;
	}
	else if (nTransferred == -1) {

		pdlg->m_dwError = cl_get_error_number(pdlg->m_hcl);
		pdlg->m_sError  = cl_get_error_message(pdlg->m_hcl);

#if 0
		if ((6==pdlg->m_dwError||1==pdlg->m_dwError) && (TPA_UPLOAD == pdlg->m_tp.nAction) )
		{
			if ((pdlg->m_retry_tfinfo->retryCnt < RETRY_CNT))
			{
				pdlg->m_retry_tfinfo->doRetry = true;
				pdlg->PostMessage(WMU_TRANSFER, CLWRITEPOLICY_OVERWRITE);
				return;
			}
			else
			{
				pdlg->SendMailWhenUploadFail(pdlg->m_retry_tfinfo->retryFile->sSrcPath);
				pdlg->WriteWhenUploadFail(pdlg->m_retry_tfinfo->retryFile->sSrcPath);
				AddFailedFile(m_retry_tfinfo->retryFile->sSrcPath, false);
				pdlg->PostMessage(WMU_TRANSFER_COMPLETED);
				return;
			}
		}
#endif

		pdlg->PostMessage(WMU_TRANSFER_ERROR);
		return;
	}

	// 전송속도 구하기
	DWORD dwTick    = GetTickCount();
	DWORD dwGapTick = dwTick - pdlg->m_nSpeedTick;
	dwGapTick++;

	double nGapSecond      = (double)(dwGapTick) / 1000;
	INT64  nGapTransferred = pdlg->m_nSpeedTransferred + (nTransferred - pdlg->m_nBaseFileSize);
	if (nGapTransferred <= 0)
		return;

	pdlg->m_nTransferSpeed = nGapTransferred / nGapSecond;

	pdlg->m_nTransferredSize = nTransferred;

	// 화면 출력하기
//	pdlg->m_stcSpeed.SetWindowText(BYTE2KMBYTE((__int64)pdlg->m_nTransferSpeed, 0, TRUE) + "/s");
	pdlg->m_stcSpeed.SetWindowText(BYTE2KMBIT((__int64)pdlg->m_nTransferSpeed * 8, 0, TRUE) + "bits/s");

	CString sProgress, sTransferred, sTotalSize;
	int     nPercent;

	nPercent     = int((nTransferred * 100) / (pdlg->m_nCurrentFileSize == 0 ? 1 : pdlg->m_nCurrentFileSize));
	sTransferred = NumericFormat(nTransferred);
	sTotalSize   = NumericFormat(pdlg->m_nCurrentFileSize);
	
	if (sTransferred == sTotalSize) pdlg->m_pause_disabled = true;
	else pdlg->m_pause_disabled = false;

	sProgress.Format("%d%% (%s / %s)", nPercent, sTransferred, sTotalSize);
	pdlg->m_prsNow.SetPos(nPercent, sProgress);

	pdlg->ShowProgressStatus(pdlg->m_nTotalTransferred + nTransferred);

/* 순간 속도
	// 전송속도 구하기
	DWORD dwTickCount = GetTickCount();
	DWORD dwGapTick   = dwTickCount - pdlg->m_dwOldTick;
	dwGapTick++;

	double nGapSecond      = (double)(dwGapTick) / 1000;
	INT64  nGapTransferred = nTransferred - pdlg->m_nTransferredSize;
	if (nGapTransferred <= 0)
		return;

	pdlg->m_nTransferSpeed = nGapTransferred / nGapSecond;

	pdlg->m_dwOldTick        = dwTickCount;
	pdlg->m_nTransferredSize = nTransferred;

	// 화면 출력하기
	pdlg->m_stcSpeed.SetWindowText(BYTE2KMBYTE((__int64)pdlg->m_nTransferSpeed, 0, TRUE) + "/s");

	CString sProgress, sTransferred, sTotalSize;
	int     nPercent;

	nPercent     = int((nTransferred * 100) / (pdlg->m_nCurrentFileSize == 0 ? 1 : pdlg->m_nCurrentFileSize));
	sTransferred = NumericFormat(nTransferred);
	sTotalSize   = NumericFormat(pdlg->m_nCurrentFileSize);
	sProgress.Format("%d%% (%s / %s)", nPercent, sTransferred, sTotalSize);
	pdlg->m_prsNow.SetPos(nPercent, sProgress);

	pdlg->ShowProgressStatus(pdlg->m_nTotalTransferred + nTransferred);
*/
}

void CTransferDlg::ShowProgressStatus(UINT64 nTransferred)
{
	// 경과시간
	CTime tmCurrent(CTime::GetCurrentTime());
	CTimeSpan ts = (tmCurrent - m_tmStart) + m_nElapsed;

	m_stcETime.SetWindowText(ts.Format("%H:%M:%S"));

	// 남은시간
	CString sRemainTime = "??:??:??";
	if (m_nTransferSpeed > 0.0) {
		int nRemainSec = (int)((double)(m_nTotalSize - nTransferred) / m_nTransferSpeed);
		nRemainSec += (int)((m_nTotalCount - m_iTransfer) * m_nGapTransfer) + 1;
		sRemainTime.Format("%02d:%02d:%02d", nRemainSec / 60 / 60, nRemainSec / 60 % 60, nRemainSec % 60);
	}
	else if (m_nTotalSize == 0) {
		int nRemainSec = (int)((m_nTotalCount - m_iTransfer) * m_nGapTransfer) + 1;
		sRemainTime.Format("%02d:%02d:%02d", nRemainSec / 60 / 60, nRemainSec / 60 % 60, nRemainSec % 60);
	}

	m_stcLTime.SetWindowText(sRemainTime);
	RedrawControl2();

	ShowTotalProgress();

	CString sTitle;
	int     nPercent = int((nTransferred * 100) / (m_nTotalSize == 0 ? 1 : m_nTotalSize));

	sTitle.Format("(%d%%) %s", nPercent, m_sTitle);
	SetWindowText(sTitle);
}

void CTransferDlg::ShowFileCount()
{
	if (m_nTotalCount == 0)
		return;

	m_stcFileCount.SetWindowText(NumericFormat(m_iTransfer + 1) + "/" + NumericFormat(m_nTotalCount));

	RedrawControl1();
}

void CTransferDlg::ShowTotalProgress()
{
	CString sProgress, sTransferred, sTotalSize;
	int     nPercent;

	if (m_nTotalCount == 0)
		return;

	UINT64 nTransferred = m_nTotalTransferred + m_nTransferredSize;

	nPercent     = int((nTransferred * 100) / (m_nTotalSize == 0 ? 1 : m_nTotalSize));
	sTransferred = NumericFormat(nTransferred);
	sTotalSize   = NumericFormat(m_nTotalSize);
	sProgress.Format("%d%% (%s / %s)", nPercent, sTransferred, sTotalSize);
	m_prsTotal.SetPos(nPercent, sProgress);
}

void CTransferDlg::Pause(bool bPause)
{
	if (!m_pause_disabled)
	{
		m_btnPause.EnableWindow(TRUE);

		m_bPaused = bPause;

		if (bPause && m_paTranFile.GetCount() > 0 && ((PTRANFILE_STRUCT)m_paTranFile[0])->nState != TFS_READY) {
			PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[m_iTransfer];
			ptf->nState = TFS_PAUSE;
			if (m_iTransfer > 0)
				m_list.SetItemState(m_iTransfer - 1, 0, LVIS_SELECTED | LVIS_FOCUSED);
			m_list.SetItemState(m_iTransfer, LVIS_SELECTED, LVIS_SELECTED);
			m_list.SetItemText(m_iTransfer, 3, "일시정지");
			m_list.EnsureVisible(m_iTransfer, TRUE);

			m_nSelectedCount = 1;
			if (!ptf->bFolder)
				m_nSelectedSize = ptf->nSize;

			ShowStatus(TRUE);

			CTimeSpan ts = CTime::GetCurrentTime() - m_tmStart;
			m_nElapsed += ts.GetTotalSeconds();
		}

		m_btnDelFile.EnableWindow(bPause);

		m_btnPause.SetWindowText(bPause ? "재시작(&R)" : "일시정지(&C)");
		m_btnClose.EnableWindow(bPause);

	}

}

void CTransferDlg::Resume()
{
	m_btnPause.EnableWindow(TRUE);

	InitTransferEnv();

	PostMessage(WMU_TRANSFER, CLWRITEPOLICY_NONE);
}

void CTransferDlg::InitTransferEnv()
{
	m_bResume = false;

	m_nSpeedTransferred = 0;
	m_nSpeedTick        = GetTickCount();

	m_stcLTime.SetWindowText("");
	m_stcSpeed.SetWindowText("");
	RedrawControl2();

	SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

	m_tmStart   = CTime::GetCurrentTime();
	m_dwOldTick = GetTickCount();
}

int CTransferDlg::GetAction(CString sOldObj, CString sOldMTime, UINT64 nOldSize, CString sNewObj, CString sNewMTime, UINT64 nNewSize)
{
	int nAction = m_nWriteAction;

//	LoadWritePolicy();

	if (!m_bWriteApplyAll) {
		CFileExistsDlg dlg(this);

		dlg.m_bDownload = (m_tp.nAction == TPA_UPLOAD ? FALSE : TRUE);

		char cSeparator = sOldObj.Find('/') >= 0 ? '/' : '\\';
		dlg.m_sFile1 = sOldObj;
		dlg.m_sTime1 = sOldMTime;
		dlg.m_sSize1 = nOldSize == (UINT64)-1 ? "" : NumericFormat(nOldSize) + "Bytes";

		cSeparator = sNewObj.Find('/') >= 0 ? '/' : '\\';
		dlg.m_sFile2 = sNewObj;
		dlg.m_sTime2 = sNewMTime;
		dlg.m_sSize2 = nNewSize == (UINT64)-1 ? "" : NumericFormat(nNewSize) + "Bytes";

		if (dlg.DoModal() == IDOK) 
		{
			switch(dlg.m_nSelectedAction)
			{
				case 0 : nAction = FILEEXISTS_OVERWRITE;	break;
				case 1 : nAction = FILEEXISTS_RENAME;		break;
				case 2 : nAction = FILEEXISTS_RESUME;		break;
				case 3 : nAction = FILEEXISTS_SKIP;			break;
				case 4 : nAction = FILEEXISTS_UPDATE;		break;
			}

			//nAction = dlg.m_nSelectedAction + 1;

			if (dlg.m_bAlways) 
			{
				m_bWriteApplyAll = TRUE;
				m_nWriteAction   = nAction;
			}
		}
		else {
			nAction = FILEEXISTS_SKIP;
		}
	}

	return nAction;
}


#define UP_MSG "업로드할 파일 목록을 읽는 중... "
#define DN_MSG "다운로드할 파일 목록을 읽는 중... "

UINT CTransferDlg::LoadTransferFile(LPVOID pParam)
{
	CTransferDlg* pdlg = (CTransferDlg*)pParam;

	pdlg->BeginWaitCursor();

	CStringArray saDelete;

	pdlg->m_list.DeleteAllItems();
	pdlg->m_paTranFile.RemoveAll();
	if (pdlg->m_tp.nAction == TPA_UPLOAD) {
		typedef std::pair<CString,int> pairTranFile;

		pdlg->m_stcStatus.SetWindowText(UP_MSG);

		for (map<CString,int>::iterator iter = pdlg->m_mapTranFile.begin(); iter != pdlg->m_mapTranFile.end(); iter++) {
			if (pdlg->m_bStop)
				break;

			if (iter->first.GetLength() == 3 && iter->first[1] == ':' && iter->first[2] == '\\') {
				CFileStatus64 fs;

				CFileFind finder;

				BOOL bFound = finder.FindFile(iter->first + "*");
				while (bFound) {
					if (pdlg->m_bStop)
						break;

					bFound = finder.FindNextFile();

					CString sFile = finder.GetFilePath();
					if (finder.IsDots() || finder.IsSystem() || !sFile.Right(4).Compare(".lnk"))
						continue;

					int iPos = pdlg->m_list.GetItemCount();

					if (finder.IsDirectory())
						pdlg->AppendLocalFile(sFile, 0);
					else {
						if (!GetStatus64(sFile, fs))
							continue;

						CString sTime = fs.m_mtime.Format("%Y-%m-%d %p %I:%M:%S");
						if (sTime.Replace("AM", "오전") == 0)
							sTime.Replace("PM", "오후");

						pdlg->AppendFile(sFile, fs.m_attribute & CFile::directory ? -1 : fs.m_size, sTime, 0);
					}

					pdlg->m_mapTranFile.insert(pairTranFile(sFile, iPos));
				}
				finder.Close();

				saDelete.Add(iter->first);
			}
			else {
				int iPos = pdlg->m_list.GetItemCount();
				if (pdlg->AppendLocalFile(iter->first, 0))
					iter->second = iPos;
			}
		}
	}
	else {
		pdlg->m_stcStatus.SetWindowText(DN_MSG);

		for (map<CString,int>::iterator iter = pdlg->m_mapTranFile.begin(); iter != pdlg->m_mapTranFile.end(); iter++) {
			if (pdlg->m_bStop)
				break;

			int iPos = pdlg->m_list.GetItemCount();
			if (pdlg->AppendRemoteFile(iter->first))
				iter->second = iPos;
		}
	}

	for (int i = 0; i < saDelete.GetCount(); i++)
		pdlg->m_mapTranFile.erase(saDelete[i]);

	if (!pdlg->m_bStop)
		pdlg->PostMessage(WMU_TRANSFER_IS_READY);

	pdlg->EndWaitCursor();

	pdlg->m_pthread = NULL;

	return 0;
}

bool CTransferDlg::AppendRemoteFile(CString sPath)
{
	UINT nFileCount;
	PCLFILE_STRUCT pclfl = cl_get_file_list(m_hcl, sPath, 2, &nFileCount);
	if (!pclfl)
		return false;

	if (sPath[0] != '/')
		sPath = "/" + sPath;
	int nRootCount = sPath.Replace('/', '\\');

	for (UINT i = (sPath == "\\" ? 1 : 0); i < nFileCount; i++) {
		if (m_bStop)
			return 0;

		CString sSubPath = pclfl[i].path;
		int nDepth = sSubPath.Replace('/', '\\') - nRootCount;
		AppendFile(pclfl[i].path, pclfl[i].attr & CLFILEATTR_FOLDER ? -1 : pclfl[i].size, pclfl[i].lastModified, nDepth);

		if (pclfl[i].attr & CLFILEATTR_FOLDER) {
			CString sName = pclfl[i].path;
			m_stcStatus.SetWindowText(DN_MSG + sName.Mid(sName.ReverseFind('/') + 1));
		}
	}

	cl_free_file_list(m_hcl, pclfl);

	return true;
}

bool CTransferDlg::AppendLocalFile(CString sPath, int nDepth)
{
	CFileStatus64 fs;
	if (!GetStatus64(sPath, fs))
		return false;

	m_stcStatus.SetWindowText(UP_MSG + sPath.Mid(sPath.ReverseFind('\\') + 1));

	CString sTime = fs.m_mtime.Format("%Y-%m-%d %p %I:%M:%S");
	if (sTime.Replace("AM", "오전") == 0)
		sTime.Replace("PM", "오후");

	BOOL bFolder = fs.m_attribute & CFile::directory;

	AppendFile(sPath, bFolder ? -1 : fs.m_size, sTime, nDepth);

	if (bFolder) {
		if (sPath.Right(1) != "\\")
			sPath += "\\";

		nDepth++;

		CFileFind finder;

		BOOL bFound = finder.FindFile(sPath + "*");
		while (bFound) {
			if (m_bStop)
				return false;

			bFound = finder.FindNextFile();

			CString sFile = finder.GetFilePath();

			if (finder.IsDots() || !sFile.Right(4).Compare(".lnk"))
				continue;

			if (finder.IsDirectory())
				AppendLocalFile(sFile, nDepth);
			else {
				if (!GetStatus64(sFile, fs))
					continue;

				sTime = fs.m_mtime.Format("%Y-%m-%d %p %I:%M:%S");
				if (sTime.Replace("AM", "오전") == 0)
					sTime.Replace("PM", "오후");

				AppendFile(sFile, fs.m_attribute & CFile::directory ? -1 : fs.m_size, sTime, nDepth);
			}
		}
		finder.Close();
	}

	return true;
}

void CTransferDlg::AppendFile(CString sPath, UINT64 nSize, CString sLastModified, int nDepth, int iPos)
{
	int  i, nReplace;
	char cSeparator1;
	char cSeparator2;

	if (m_tp.nAction == TPA_UPLOAD) {
		cSeparator1 = '\\';
		cSeparator2 = '/';
	}
	else {
		cSeparator1 = '/';
		cSeparator2 = '\\';
	}

	CString sText = sPath;

	nReplace = sText.Replace(cSeparator1, cSeparator2) - nDepth;
	for (i = 0; i < nReplace; i++)
		sText = sText.Mid(sText.Find(cSeparator2) + 1);

	PTRANFILE_STRUCT ptf = new TRANFILE_STRUCT;
	for (i = 0; i < nDepth; i++)
		ptf->sText += "   ";

	ptf->bFolder       = (nSize == (UINT64)-1);
	ptf->sText        += sText.Mid(sText.ReverseFind(cSeparator2) + 1);
	ptf->sSrcPath      = sPath;
	ptf->sDstPath      = sText;
	ptf->sLastModified = sLastModified;
	ptf->nSize         = nSize;
	ptf->nState        = TFS_READY;

	m_paTranFile.Add(ptf);

	if (iPos < 0)
        iPos = (int)m_paTranFile.GetCount() - 1;

	SHFILEINFO shfi;
	if (!SHGetFileInfo(ptf->sText.Mid(ptf->sText.ReverseFind('.')), ptf->bFolder ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME)) {
		shfi.iIcon         = -1;
		shfi.szTypeName[0] = NULL;
	}

	m_list.InsertItem(iPos, ptf->sText, shfi.iIcon);
	m_list.SetItemText(iPos, 1, ptf->bFolder ? "" : BYTE2KMBYTE(ptf->nSize, 1, FALSE));
	m_list.SetItemText(iPos, 2, shfi.szTypeName);
	m_list.SetItemText(iPos, 3, "대기중");
}

void CTransferDlg::ShowStatus(bool bSelected, bool bUpdate, bool bAllSelected)
{
	if (!bSelected) {
		if (bUpdate) {
			m_nTotalCount = (int)m_paTranFile.GetCount();
			m_nTotalSize  = 0;

			m_bUpdating = true;
			for (int i = 0; i < m_nTotalCount; i++) {
				m_list.SetItemState(i, 0, LVIS_SELECTED);

				PTRANFILE_STRUCT ptf = (PTRANFILE_STRUCT)m_paTranFile[i];
				if (!ptf->bFolder)
					m_nTotalSize += ptf->nSize;
			}
			m_bUpdating = false;
		}

		m_nSelectedCount = 0;
		m_nSelectedSize  = 0;

SHOW_TOTALOBJECTSTATUS:
		m_stcStatus.SetWindowText("전체 파일 수 " + NumericFormat(m_nTotalCount) + "건, 전체 파일 용량 " + BYTE2KMBYTE(m_nTotalSize, 0, TRUE));
	}
	else {
		if (bAllSelected) {
			m_nSelectedCount = m_nTotalCount;
			m_nSelectedSize  = m_nTotalSize;
		}

		if (m_nSelectedCount == 0)
			goto SHOW_TOTALOBJECTSTATUS;

		m_stcStatus.SetWindowText("선택된 파일 수 " + NumericFormat(m_nSelectedCount) + "건, 선택된 파일 용량 " + BYTE2KMBYTE(m_nSelectedSize, 0, TRUE));
	}
}

void CTransferDlg::LoadWritePolicy()
{
	
//	int nWritePolicy = COptions::GetOptionVal(OPTION_WRITEPOLICY);
	int nWritePolicy = m_tp.nWritePolicy;

	if (nWritePolicy == 0) {
		m_bWriteApplyAll = FALSE;
		m_nWriteAction   = FILEEXISTS_OVERWRITE;
	}
	else {
		m_bWriteApplyAll = TRUE;
		m_nWriteAction   = nWritePolicy;
	}
}

void CTransferDlg::RedrawControl1()
{
/*
	static bool bInited = false;
	static RECT rc1, rc2;

	if (!bInited) {
		m_stcSaveFile.GetWindowRect(&rc1);
		m_tab.ScreenToClient(&rc1);
		m_stcFileCount.GetWindowRect(&rc2);
		m_tab.ScreenToClient(&rc2);

		bInited = true;
	}

	m_tab.InvalidateRect(&rc1, FALSE);
	m_tab.InvalidateRect(&rc2, FALSE);
*/
	m_stcSaveFile.ShowWindow(SW_HIDE);
	m_stcSaveFile.ShowWindow(SW_SHOW);
	m_stcFileCount.ShowWindow(SW_HIDE);
	m_stcFileCount.ShowWindow(SW_SHOW);
}

void CTransferDlg::RedrawControl2()
{
/*
	static bool bInited = false;
	static RECT rc1, rc2, rc3;

	if (!bInited) {
		m_stcSpeed.GetWindowRect(&rc1);
		m_tab.ScreenToClient(&rc1);
		m_stcETime.GetWindowRect(&rc2);
		m_tab.ScreenToClient(&rc2);
		m_stcLTime.GetWindowRect(&rc3);
		m_tab.ScreenToClient(&rc3);

		bInited = true;
	}

	m_tab.InvalidateRect(&rc1, FALSE);
	m_tab.InvalidateRect(&rc2, FALSE);
	m_tab.InvalidateRect(&rc3, FALSE);
*/
	m_stcSpeed.ShowWindow(SW_HIDE);
	m_stcSpeed.ShowWindow(SW_SHOW);
	m_stcETime.ShowWindow(SW_HIDE);
	m_stcETime.ShowWindow(SW_SHOW);
	m_stcLTime.ShowWindow(SW_HIDE);
	m_stcLTime.ShowWindow(SW_SHOW);
}

BEGIN_EVENTSINK_MAP(CTransferDlg, CDialog)
	ON_EVENT(CTransferDlg, IDC_WB_ADVERT, 259, DocumentCompleteWBAdvert, VTS_DISPATCH VTS_PVARIANT)
	ON_EVENT(CTransferDlg, IDC_WB_ADVERT, 271, NavigateErrorWBAdvert, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL)
END_EVENTSINK_MAP()

void CTransferDlg::DocumentCompleteWBAdvert(LPDISPATCH pDisp, VARIANT* URL)
{
}

void CTransferDlg::NavigateErrorWBAdvert(LPDISPATCH pDisp, VARIANT* URL, VARIANT* Frame, VARIANT* StatusCode, BOOL* Cancel)
{
}

void CTransferDlg::FileOptLogsRequest(PTRANFILE_STRUCT ptf)
{
	TADDINFO tdi;
	
	ptf->bFolder	? tdi.bFolder='D' : tdi.bFolder='F';

	strncpy(tdi.szFileName , m_szTargetPath , 2048-1);

	HWND hWnd = m_tp.hwnd;
	if (hWnd!=NULL)
	{
		COPYDATASTRUCT copydata;
		copydata.dwData=1000;
		copydata.cbData=sizeof(TADDINFO);
		copydata.lpData=&tdi;

		::SendMessage(hWnd , WM_COPYDATA , (WPARAM)m_hWnd , (LPARAM)&copydata);
	}
}

void CTransferDlg::SendMailWhenUploadFail(const char* file_name)
{
	char local_file[2048];
	strncpy(local_file , file_name , 2048);

	HWND hWnd = m_tp.hwnd;
	if (hWnd!=NULL)
	{
		COPYDATASTRUCT copydata;
		copydata.dwData=2000;
		copydata.cbData=2048;
		copydata.lpData=local_file;

		::SendMessage(hWnd , WM_COPYDATA , (WPARAM)m_hWnd , (LPARAM)&copydata);
	}
}

void CTransferDlg::WriteWhenUploadFail(const char* sfile_name , const char* tfile_name)
{
	char log_file_path[256];
	char log_contents[4096];

	::_mkdir(LOG_PATH1);
	::_mkdir(LOG_PATH2);

	::sprintf(log_file_path , "%s\\%s" , LOG_PATH2 , LOG_FILE);
	::sprintf(log_contents , "%s\r\n" , sfile_name);

	FILE* fp;
	if (NULL != (fp = ::fopen(log_file_path , "a+")))
	{
		::fwrite(log_contents , ::strlen(log_contents) , 1 , fp);
	}

	fclose(fp);
}

void CTransferDlg::WriteDebugLog(const char* sfile_name , const char* tfile_name , const char* action)
{
#if 0

	SYSTEMTIME systime;
    GetSystemTime(&systime);

	CTime ct = CTime( systime );
	CString time_str = ct.Format( "%H:%M:%S" );

	char log_file_path[256];
	char log_contents[8000];

	::_mkdir(LOG_PATH1);
	::_mkdir(LOG_PATH2);

	::sprintf(log_file_path , "%s\\%s" , LOG_PATH2 , DEBUG_FILE);
	::sprintf(log_contents , "[%s][%s]%s=>%s\n" , time_str , action ,sfile_name ,tfile_name  );

	FILE* fp;
	if (NULL != (fp = ::fopen(log_file_path , "a+")))
	{
		::fwrite(log_contents , ::strlen(log_contents) , 1 , fp);
	}

	fclose(fp);
#endif 
}

void CTransferDlg::AddFailedFile(CString strPathName, bool bDirectory)
{
	CString str;
	str.Format(_T("[%s] %s\r\n"), bDirectory ? _T("디렉토리") : _T("파일"), strPathName);

	m_strFailedFiles += str;
	m_nFailedFileCount++;
}

CString CTransferDlg::GetHashedPath(CString strPath)
{
	CString strHashedPath;

	char szHash[1024];
	::memset(szHash, NULL, sizeof(szHash));
	CMD5::GetHash(strPath.GetBuffer(), szHash);
	
	strHashedPath.Format(_T("%s_%s"), strPath, szHash);

	return strHashedPath;
}