// FtpClientDlg.cpp : implementation file
//

#include "stdafx.h"
#include "FtpClient.h"
#include "FtpClientDlg.h"

#include "..\..\..\..\Source\Bluetooth\wclUUIDs.h"
#include "..\..\..\..\Source\Common\wclErrors.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CString IntToHex(const int i)
{
	CString s;
	s.Format(_T("%.8X"), i);
	return s;
}

CString IntToHex(const __int64 i)
{
	CString s;
	s.Format(_T("%.4X%.8X"), static_cast<INT32>((i >> 32) & 0x00000FFFF),
		static_cast<INT32>(i) & 0xFFFFFFFF);
	return s;
}

__int64 StrToInt64(const CString& s)
{
	return _tcstoi64(s, NULL, 16);
}

CString IntToStr(const int i)
{
	CString s;
	s.Format(_T("%d"), i);
	return s;
}


// CFtpClientDlg dialog




CFtpClientDlg::CFtpClientDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CFtpClientDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFtpClientDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST_DEVICES, lvDevices);
	DDX_Control(pDX, IDC_EDIT_FILE_NAME, edFileName);
	DDX_Control(pDX, IDC_PROGRESS, ProgressBar);
	DDX_Control(pDX, IDC_EDIT_NEW_DIR_NAME, edNewDirName);
	DDX_Control(pDX, IDC_LIST_FILES, lvFiles);
	DDX_Control(pDX, IDC_LIST_LOG, lbLog);
}

BEGIN_MESSAGE_MAP(CFtpClientDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON_CLEAR, &CFtpClientDlg::OnBnClickedButtonClear)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BUTTON_DISCOVER, &CFtpClientDlg::OnBnClickedButtonDiscover)
	ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, &CFtpClientDlg::OnBnClickedButtonDisconnect)
	ON_BN_CLICKED(IDC_BUTTON_CLOSE_SESSION, &CFtpClientDlg::OnBnClickedButtonCloseSession)
	ON_BN_CLICKED(IDC_BUTTON_OPEN_SESSION, &CFtpClientDlg::OnBnClickedButtonOpenSession)
	ON_BN_CLICKED(IDC_BUTTON_CONNECT, &CFtpClientDlg::OnBnClickedButtonConnect)
	ON_BN_CLICKED(IDC_BUTTON_SELECT_FILE, &CFtpClientDlg::OnBnClickedButtonSelectFile)
	ON_BN_CLICKED(IDC_BUTTON_ABORT, &CFtpClientDlg::OnBnClickedButtonAbort)
	ON_BN_CLICKED(IDC_BUTTON_SEND_FILE, &CFtpClientDlg::OnBnClickedButtonSendFile)
	ON_BN_CLICKED(IDC_BUTTON_DIR, &CFtpClientDlg::OnBnClickedButtonDir)
	ON_NOTIFY(NM_DBLCLK, IDC_LIST_FILES, &CFtpClientDlg::OnNMDblclkListFiles)
	ON_BN_CLICKED(IDC_BUTTON_ROOT, &CFtpClientDlg::OnBnClickedButtonRoot)
	ON_BN_CLICKED(IDC_BUTTON_DELETE, &CFtpClientDlg::OnBnClickedButtonDelete)
	ON_BN_CLICKED(IDC_BUTTON_MK_DIR, &CFtpClientDlg::OnBnClickedButtonMkDir)
END_MESSAGE_MAP()


// CFtpClientDlg message handlers

BOOL CFtpClientDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	lvDevices.InsertColumn(0, _T("Address"), 0, 150);
	lvDevices.InsertColumn(1, _T("Name"), 0, 150);
	lvDevices.SetExtendedStyle(lvDevices.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	lvFiles.InsertColumn(0, _T("Object name"), 0, 150);
	lvFiles.InsertColumn(1, _T("Type"), 0, 100);
	lvFiles.InsertColumn(2, _T("Size"), 0, 80);
	lvFiles.InsertColumn(3, _T("Permissions"), 0, 80);
	lvFiles.InsertColumn(4, _T("Modified"), 0, 80);
	lvFiles.InsertColumn(5, _T("Created"), 0, 80);
	lvFiles.InsertColumn(6, _T("Accessed"), 0, 80);
	lvFiles.InsertColumn(7, _T("Description"), 0, 100);
	lvFiles.SetExtendedStyle(lvFiles.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	// We use ObjectPush Profile so must set the profile's UUID.
	wclRfCommClient.Service = OBEXFileTransferServiceClass_UUID;
	
	FFtp = NULL;

	__hook(&CwclBluetoothManager::AfterOpen, &wclBluetoothManager,
		&CFtpClientDlg::ManagerAfterOpen);
	__hook(&CwclBluetoothManager::OnAuthenticationCompleted, &wclBluetoothManager,
		&CFtpClientDlg::ManagerAuthenticationCompleted);
	__hook(&CwclBluetoothManager::OnDiscoveringCompleted, &wclBluetoothManager,
		&CFtpClientDlg::ManagerDiscoveringCompleted);
	__hook(&CwclBluetoothManager::OnDiscoveringStarted, &wclBluetoothManager,
		&CFtpClientDlg::ManagerDiscoveringStarted);
	__hook(&CwclBluetoothManager::OnNumericComparison, &wclBluetoothManager,
		&CFtpClientDlg::ManagerNumericComparison);
	__hook(&CwclBluetoothManager::OnPasskeyNotification, &wclBluetoothManager,
		&CFtpClientDlg::ManagerPasskeyNotification);
	__hook(&CwclBluetoothManager::OnPasskeyRequest, &wclBluetoothManager,
		&CFtpClientDlg::ManagerPasskeyRequest);
	__hook(&CwclBluetoothManager::OnPinRequest, &wclBluetoothManager,
		&CFtpClientDlg::ManagerPinRequest);
	__hook(&CwclBluetoothManager::OnDeviceFound, &wclBluetoothManager,
		&CFtpClientDlg::ManagerDeviceFound);

	__hook(&CwclRfCommClient::OnDisconnect, &wclRfCommClient,
		&CFtpClientDlg::ClientDisconnect);
	__hook(&CwclRfCommClient::OnConnect, &wclRfCommClient,
		&CFtpClientDlg::ClientConnect);
	__hook(&CwclRfCommClient::OnDestroyProcessor, &wclRfCommClient,
		&CFtpClientDlg::ClientDestroyProcessor);
	__hook(&CwclRfCommClient::OnCreateProcessor, &wclRfCommClient,
		&CFtpClientDlg::ClientCreateProcessor);

	// Try to open Bluetooth Manager.
	int Res = wclBluetoothManager.Open();
	if (Res != WCL_E_SUCCESS)
		lbLog.AddString(_T("Bluetooth Manager Open failed: 0x") + IntToHex(Res));

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CFtpClientDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CFtpClientDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

CwclBluetoothRadio* CFtpClientDlg::GetRadio() const
{
	CwclBluetoothRadio* Radio;
	int Res = wclBluetoothManager.GetClassicRadio(Radio);
	if (Res != WCL_E_SUCCESS)
	{
		AfxMessageBox(_T("Get working radio failed"));
		return NULL;
	}
	return Radio;
}

void CFtpClientDlg::ClientCreateProcessor(void* Sender, CwclClientDataConnection* const Connection)
{
	UNREFERENCED_PARAMETER(Sender);

	// here we must create the data processor for the connection. In this demo
	// we use OPPClient.
	FFtp = new CwclObexFtpClient(Connection);
	__hook(&CwclObexFtpClient::OnConnect, FFtp, &CFtpClientDlg::FtpConnect);
	__hook(&CwclObexFtpClient::OnDisconnect, FFtp, &CFtpClientDlg::FtpDisconnect);
	__hook(&CwclObexFtpClient::OnGetComplete, FFtp, &CFtpClientDlg::FtpGetComplete);
	__hook(&CwclObexFtpClient::OnPutComplete, FFtp, &CFtpClientDlg::FtpPutComplete);
	__hook(&CwclObexFtpClient::OnProgress, FFtp, &CFtpClientDlg::FtpProgress);
	__hook(&CwclObexFtpClient::OnDirComplete, FFtp, &CFtpClientDlg::FtpDirComplete);
	__hook(&CwclObexFtpClient::OnChangeDirComplete, FFtp, &CFtpClientDlg::FtpChangeDirComplete);
	__hook(&CwclObexFtpClient::OnDeleteComplete, FFtp, &CFtpClientDlg::FtpDeleteComplete);
	__hook(&CwclObexFtpClient::OnMakeDirComplete, FFtp, &CFtpClientDlg::FtpMakeDirComplete);
}

void CFtpClientDlg::FtpMakeDirComplete(void* Sender, const int Error, const tstring& Description)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Make dir completed with result: 0x") + IntToHex(Error) +
		_T(". Description: ") + CString(Description.c_str()));

	ProgressBar.SetPos(0);
	ProgressBar.SetRange32(0, 0);

	lvFiles.DeleteAllItems();
	FFtp->Dir();
}

void CFtpClientDlg::FtpDeleteComplete(void* Sender, const int Error, const tstring& Description)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Delete completed with result: 0x") + IntToHex(Error) +
		_T(". Description: ") + CString(Description.c_str()));

	ProgressBar.SetPos(0);
	ProgressBar.SetRange32(0, 0);

	lvFiles.DeleteAllItems();
	FFtp->Dir();
}

void CFtpClientDlg::FtpChangeDirComplete(void* Sender, const int Error, const tstring& Description)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Change dir completed with result: 0x") + IntToHex(Error) +
		_T(". Description: ") + CString(Description.c_str()));

	ProgressBar.SetPos(0);
	ProgressBar.SetRange32(0, 0);

	lvFiles.DeleteAllItems();
	FFtp->Dir();
}

bool IsNullDateTime(const SYSTEMTIME& dt)
{
	return (dt.wDay == 0 && dt.wDayOfWeek == 0 && dt.wHour == 0 && dt.wMilliseconds == 0 &&
		dt.wMinute == 0 && dt.wMonth == 0 && dt.wSecond == 0 && dt.wYear == 0);
}

void CFtpClientDlg::FtpDirComplete(void* Sender, const int Error, const tstring& Description, 
	const wclObexFileObjects& Dirs)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Dir completed with result: 0x") + IntToHex(Error) +
		_T(". Description: ") + CString(Description.c_str()));

	ProgressBar.SetPos(0);
	ProgressBar.SetRange32(0, 0);
	
	if (Dirs.size() > 0)
	{
		UINT n = 0;
		for (wclObexFileObjects::const_iterator i = Dirs.begin(); i != Dirs.end(); i++)
		{
			lvFiles.InsertItem(n, i->Name.c_str());
			if (i->IsDirectory)
				lvFiles.SetItemText(n, 1, _T("Folder"));
			else
				lvFiles.SetItemText(n, 1, _T("File"));
			lvFiles.SetItemText(n, 2, IntToStr(i->Size));

			CString Perm = _T("");
			if (i->Permissions.find(opRead) != i->Permissions.end())
				Perm = Perm + _T("R");
			if (i->Permissions.find(opWrite) != i->Permissions.end())
				Perm = Perm + _T("W");
			if (i->Permissions.find(opDelete) != i->Permissions.end())
				Perm = Perm + _T("D");
			lvFiles.SetItemText(n, 3, Perm);
			if (!IsNullDateTime(i->Modified))
			{
				Perm.Format(_T("%02d.%02d.%04d %02d:%02d:%02d"), i->Modified.wDay,
					i->Modified.wMonth, i->Modified.wYear, i->Modified.wHour,
					i->Modified.wMinute, i->Modified.wSecond);
			}
			else
				Perm = _T("");
			lvFiles.SetItemText(n, 4, Perm);
			if (!IsNullDateTime(i->Created))
			{
				Perm.Format(_T("%02d.%02d.%04d %02d:%02d:%02d"), i->Created.wDay,
					i->Created.wMonth, i->Created.wYear, i->Created.wHour,
					i->Created.wMinute, i->Created.wSecond);
			}
			else
				Perm = _T("");
			lvFiles.SetItemText(n, 5, Perm);
			if (!IsNullDateTime(i->Accessed))
			{
				Perm.Format(_T("%02d.%02d.%04d %02d:%02d:%02d"), i->Accessed.wDay,
					i->Accessed.wMonth, i->Accessed.wYear, i->Accessed.wHour,
					i->Accessed.wMinute, i->Accessed.wSecond);
			}
			else
				Perm = _T("");
			lvFiles.SetItemText(n, 6, Perm);

			lvFiles.SetItemText(n, 7, i->Description.c_str());
			n++;
		}
	}
}

void CFtpClientDlg::FtpGetComplete(void* Sender, const int Error, const tstring& Description,
	CwclStream* const Stream)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("File receiving completed with result: 0x") +
		IntToHex(Error) + _T(". Description: ") + CString(Description.c_str()));
	
	ProgressBar.SetPos(0);
	ProgressBar.SetRange32(0, 0);
	
	// We must destroy the stream object here.
	delete Stream;
}

void CFtpClientDlg::FtpProgress(void* Sender, unsigned long Size, unsigned long Position)
{
	UNREFERENCED_PARAMETER(Sender);

	ProgressBar.SetRange32(0, Size);
	ProgressBar.SetPos(Position);
}

void CFtpClientDlg::FtpPutComplete(void* Sender, const int Error, const tstring& Description, 
	CwclStream* const Stream)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("File sending completed with result: 0x") + IntToHex(Error) +
		_T(". Description: ") + CString(Description.c_str()));
	
	ProgressBar.SetPos(0);
	ProgressBar.SetRange32(0, 0);
	
	// We must destroy the stream object here.
	delete Stream;
}

void CFtpClientDlg::FtpConnect(void* Sender, const int Error, const tstring& Description)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("OBEX session opened with result: 0x") + IntToHex(Error) +
		_T(". Description: ") + CString(Description.c_str()));
}

void CFtpClientDlg::FtpDisconnect(void* Sender, const int Error, const tstring& Description)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("OBEX session closed with result: 0x") + IntToHex(Error) +
		_T(". Description: ") + CString(Description.c_str()));
}

void CFtpClientDlg::ClientDestroyProcessor(void* Sender, CwclClientDataConnection* const Connection)
{
	UNREFERENCED_PARAMETER(Sender);

	// Do we have any data processor created?
	if (FFtp != NULL)
	{
		// Make sure it is our connection is goind to destroy.
		if (Connection->Processor == FFtp)
		{
			// On Visual Studio 2015 and above the __unhook() poroduces warning C4458
			// We we have to supress it. By some reason it can not be disabled by pragma
			// so we disabled it in the project settings.
			__unhook(FFtp);
			// Ok, destroy the data processor here.
			delete FFtp;
			FFtp = NULL;
		}
	}
}

void CFtpClientDlg::ClientConnect(void* Sender, const int Error)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Connect. Operation result: 0x") + IntToHex(Error));
}

void CFtpClientDlg::ClientDisconnect(void* Sender, const int Reason)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Disconnected with reason: 0x") + IntToHex(Reason));
}

void CFtpClientDlg::ManagerDeviceFound(void* Sender, CwclBluetoothRadio* const Radio, 
	const __int64 Address)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);

	int Item = lvDevices.GetItemCount();
	lvDevices.InsertItem(Item, IntToHex(Address));
	lvDevices.SetItemText(Item, 1, _T(""));
}

void CFtpClientDlg::ManagerPinRequest(void* Sender, CwclBluetoothRadio* const Radio,
	const __int64 Address, tstring& Pin)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);

	lbLog.AddString(_T("PIN code request. PIN: 0000"));
	Pin = _T("0000");
}

void CFtpClientDlg::ManagerPasskeyRequest(void* Sender, CwclBluetoothRadio* const Radio,
	const __int64 Address, unsigned long& Passkey)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);

	lbLog.AddString(_T("Passkey request. Passkey: 12345678"));
	Passkey = 12345678;
}

void CFtpClientDlg::ManagerPasskeyNotification(void* Sender, CwclBluetoothRadio* const Radio,
	const __int64 Address, const unsigned long Passkey)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);

	lbLog.AddString(_T("Passkey notification. Passkey: ") + IntToStr(Passkey));
}

void CFtpClientDlg::ManagerNumericComparison(void* Sender, CwclBluetoothRadio* const Radio,
	const __int64 Address, const unsigned long Number, bool& Confirm)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);
	UNREFERENCED_PARAMETER(Number);

	lbLog.AddString(_T("Numeric comparison. Accept"));
	Confirm = true;
}

void CFtpClientDlg::ManagerDiscoveringStarted(void* Sender, CwclBluetoothRadio* const Radio)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);

	lbLog.AddString(_T("Discovering started"));
	
	lvDevices.DeleteAllItems();
}

void CFtpClientDlg::ManagerDiscoveringCompleted(void* Sender, CwclBluetoothRadio* const Radio, 
	const int Error)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Discovering completed with result: 0x") + IntToHex(Error));
	
	// Here we can update found devices names.
	for (int i = 0; i < lvDevices.GetItemCount(); i++)
	{
		__int64 Address = StrToInt64(lvDevices.GetItemText(i, 0));
		tstring DevName;
		int Res = Radio->GetRemoteName(Address, DevName);
		if (Res != WCL_E_SUCCESS)
			lvDevices.SetItemText(i, 1, _T("Error: 0x") + IntToHex(Res));
		else
			lvDevices.SetItemText(i, 1, DevName.c_str());
	}
}

void CFtpClientDlg::ManagerAuthenticationCompleted(void* Sender, CwclBluetoothRadio* const Radio,
	const __int64 Address, const int Error)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);

	lbLog.AddString(_T("Authentication completed with result: 0x") + IntToHex(Error));
}

void CFtpClientDlg::ManagerAfterOpen(void* Sender)
{
	UNREFERENCED_PARAMETER(Sender);

	lbLog.AddString(_T("Bluetooth Manager has been opened"));
}

void CFtpClientDlg::OnBnClickedButtonClear()
{
	lbLog.ResetContent();
}

void CFtpClientDlg::OnDestroy()
{
	CDialog::OnDestroy();

	// TODO: Add your message handler code here
	wclRfCommClient.Disconnect();
	wclBluetoothManager.Close();

	// On Visual Studio 2015 and above the __unhook() poroduces warning C4458
	// We we have to supress it. By some reason it can not be disabled by pragma
	// so we disabled it in the project settings.
	__unhook(&wclBluetoothManager);
	__unhook(&wclRfCommClient);
}

void CFtpClientDlg::OnBnClickedButtonDiscover()
{
	CwclBluetoothRadio* Radio = GetRadio();
	if (Radio != NULL)
	{
		// Discover classic devices only.
		int Res = Radio->Discover(10, dkClassic);
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Failed to start discovering: 0x") + IntToHex(Res));
	}
}

void CFtpClientDlg::OnBnClickedButtonDisconnect()
{
	int Res = wclRfCommClient.Disconnect();
	if (Res != WCL_E_SUCCESS)
		AfxMessageBox(_T("Disconnect failed: 0x") + IntToHex(Res));
}

void CFtpClientDlg::OnBnClickedButtonCloseSession()
{
	if (FFtp == NULL)
		AfxMessageBox(_T("Not connected"));
	else
	{
		int Res = FFtp->Disconnect(_T(""));
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Close session failed: 0x") + IntToHex(Res));
	}
}

void CFtpClientDlg::OnBnClickedButtonOpenSession()
{
	if (FFtp == NULL)
		AfxMessageBox(_T("Not connected"));
	else
	{
		int Res = FFtp->Connect();
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Open session failed: 0x") + IntToHex(Res));
	}
}

void CFtpClientDlg::OnBnClickedButtonConnect()
{
	if (wclRfCommClient.State != csDisconnected)
		AfxMessageBox(_T("Client is connected"));
	else
	{
		POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
		if (Pos == NULL)
			AfxMessageBox(_T("Select device"));
		else
		{
			CwclBluetoothRadio* Radio = GetRadio();
			int Item = lvDevices.GetNextSelectedItem(Pos);
			wclRfCommClient.Address = StrToInt64(lvDevices.GetItemText(Item, 0));
			int Res = wclRfCommClient.Connect(Radio);
			if (Res != WCL_E_SUCCESS)
				AfxMessageBox(_T("Error: 0x") + IntToHex(Res));
		}
	}
}

void CFtpClientDlg::OnBnClickedButtonSelectFile()
{
	CFileDialog Dlg(TRUE);
	if (Dlg.DoModal() == IDOK)
		edFileName.SetWindowText(Dlg.GetPathName());
}

void CFtpClientDlg::OnBnClickedButtonAbort()
{
	if (FFtp == NULL)
		AfxMessageBox(_T("Not connected"));
	else
	{
		int Res = FFtp->Abort(_T(""));
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Open session failed: 0x") + IntToHex(Res));
	}
}

void CFtpClientDlg::OnBnClickedButtonSendFile()
{
	if (FFtp == NULL)
		AfxMessageBox(_T("Not connected"));
	else
	{
		CString s;		
		edFileName.GetWindowText(s);
		if (s == _T(""))
			AfxMessageBox(_T("Select file"));
		else
		{
			tstring FileName = tstring(s);
			CwclFileStream* Stream = new CwclFileStream(FileName, OPEN_EXISTING, GENERIC_READ,
				FILE_SHARE_READ);
			size_t last_slash_idx = FileName.find_last_of(_T("\\/"));
			if (tstring::npos != last_slash_idx)
				FileName.erase(0, last_slash_idx + 1);
			
			int Res = FFtp->Put(FileName, _T(""), Stream);
			if (Res != WCL_E_SUCCESS)
			{
				AfxMessageBox(_T("Send file failed: 0x") + IntToHex(Res));
				delete Stream;
			}
		}
	}
}

void CFtpClientDlg::OnBnClickedButtonDir()
{
	if (FFtp == NULL)
		AfxMessageBox(_T("Not connected"));
	else
	{
		int Res = FFtp->Dir();
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Dir failed: 0x") + IntToHex(Res));
		else
			lvFiles.DeleteAllItems();
	}
}

void CFtpClientDlg::OnNMDblclkListFiles(NMHDR *pNMHDR, LRESULT *pResult)
{
	UNREFERENCED_PARAMETER(pNMHDR);

	POSITION Pos = lvFiles.GetFirstSelectedItemPosition();
	if (Pos != NULL)
	{
		if (FFtp == NULL)
			AfxMessageBox(_T("Not connected"));
		else
		{
			int Item = lvFiles.GetNextSelectedItem(Pos);
			CString Type = lvFiles.GetItemText(Item, 1);
			CString FileName = lvFiles.GetItemText(Item, 0);
			if (Type == "Folder")
			{
				int Res = FFtp->ChangeDir(FileName.GetBuffer());
				if (Res != WCL_E_SUCCESS)
					AfxMessageBox(_T("Change path failed 0x") + IntToHex(Res));
			}
			else
			{
				CwclFileStream* Stream = new CwclFileStream(tstring(_T(".\\")) + tstring(FileName.GetBuffer()),
					CREATE_ALWAYS, GENERIC_WRITE, 0);
				int Res = FFtp->Get(FileName.GetBuffer(), Stream);
				if (Res != WCL_E_SUCCESS)
				{
					AfxMessageBox(_T("Get failed 0x") + IntToHex(Res));
					delete Stream;
				}
			}
		}
	}
	
	*pResult = 0;
}

void CFtpClientDlg::OnBnClickedButtonRoot()
{
	if (FFtp == NULL)
		AfxMessageBox(_T("Not connected"));
	else
	{
		int Res = FFtp->ChangeDir(_T(""));
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Root failed 0x") + IntToHex(Res));
	}
}

void CFtpClientDlg::OnBnClickedButtonDelete()
{
	POSITION Pos = lvFiles.GetFirstSelectedItemPosition();
	if (Pos != NULL)
	{
		if (FFtp == NULL)
			AfxMessageBox(_T("Not connected"));
		else
		{
			int Item = lvFiles.GetNextSelectedItem(Pos);
			CString FileName = lvFiles.GetItemText(Item, 0);
			int Res = FFtp->Delete(FileName.GetBuffer());
			if (Res != WCL_E_SUCCESS)
				AfxMessageBox(_T("Delete failed 0x") + IntToHex(Res));
		}
	}
}

void CFtpClientDlg::OnBnClickedButtonMkDir()
{
	if (FFtp == NULL)
		AfxMessageBox(_T("Not connected"));
	else
	{
		CString Str;
		edNewDirName.GetWindowText(Str);
		int Res = FFtp->MkDir(Str.GetBuffer());
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Make sire failed 0x") + IntToHex(Res));
	}
}
