// BluetoothManagerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "BluetoothManager.h"
#include "BluetoothManagerDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CBluetoothManagerDlg dialog




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

void CBluetoothManagerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT_NAME, edName);
	DDX_Control(pDX, IDC_LIST_RADIOS, lvRadios);
	DDX_Control(pDX, IDC_EDIT_TIMEOUT, edTimeout);
	DDX_Control(pDX, IDC_EDIT_PIN, edPIN);
	DDX_Control(pDX, IDC_LIST_DEVICES, lvDevices);
	DDX_Control(pDX, IDC_LIST_SERVICES, lvServices);
	DDX_Control(pDX, IDC_LIST_EVENTS, lvEvents);
	DDX_Control(pDX, IDC_LIST_COM_PORTS, lvComPorts);
	DDX_Control(pDX, IDC_CHECK_ENUM_PREINSTALLED, cbEnumPreinstalled);
	DDX_Control(pDX, IDC_COMBO_DISCOVERING_MODE, cbDiscoveringMode);
	DDX_Control(pDX, IDC_COMBO_MITM, cbMitmProtection);
	DDX_Control(pDX, IDC_COMBO_IO_CAP, cbIoCap);
	DDX_Control(pDX, IDC_COMBO1, cbBleProtection);
	DDX_Control(pDX, IDC_COMBO_PAIRING_METHOD, cbPairingMethod);
	DDX_Control(pDX, IDC_CHECK_HANDLE_PAIRING, cbHandlePairing);
	DDX_Control(pDX, IDC_CHECK_DONT_TURN_OFF, cbDontTurnOff);
}

BEGIN_MESSAGE_MAP(CBluetoothManagerDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON_CLEAR, &CBluetoothManagerDlg::OnBnClickedButtonClear)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CBluetoothManagerDlg::OnBnClickedButtonRefresh)
	ON_BN_CLICKED(IDC_BUTTON_OPEN, &CBluetoothManagerDlg::OnBnClickedButtonOpen)
	ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CBluetoothManagerDlg::OnBnClickedButtonClose)
	ON_BN_CLICKED(IDC_BUTTON_SET_CONNECTABLE, &CBluetoothManagerDlg::OnBnClickedButtonSetConnectable)
	ON_BN_CLICKED(IDC_BUTTON_SET_DISCOVERABLE, &CBluetoothManagerDlg::OnBnClickedButtonSetDiscoverable)
	ON_BN_CLICKED(IDC_BUTTON_SET_NAME, &CBluetoothManagerDlg::OnBnClickedButtonSetName)
	ON_BN_CLICKED(IDC_BUTTON_ENUM_PAIRED, &CBluetoothManagerDlg::OnBnClickedButtonEnumPaired)
	ON_BN_CLICKED(IDC_BUTTON_REFRESH_DEVICE, &CBluetoothManagerDlg::OnBnClickedButtonRefreshDevice)
	ON_BN_CLICKED(IDC_BUTTON_ENUM_SERVICES, &CBluetoothManagerDlg::OnBnClickedButtonEnumServices)
	ON_BN_CLICKED(IDC_BUTTON_DISCOVER, &CBluetoothManagerDlg::OnBnClickedButtonDiscover)
	ON_BN_CLICKED(IDC_BUTTON_TERMINATE, &CBluetoothManagerDlg::OnBnClickedButtonTerminate)
	ON_BN_CLICKED(IDC_BUTTON_UNPAIR, &CBluetoothManagerDlg::OnBnClickedButtonUnpair)
	ON_BN_CLICKED(IDC_BUTTON_PAIR, &CBluetoothManagerDlg::OnBnClickedButtonPair)
	ON_BN_CLICKED(IDC_BUTTON_RSSI, &CBluetoothManagerDlg::OnBnClickedButtonRssi)
	ON_BN_CLICKED(IDC_BUTTON_TURN_ON, &CBluetoothManagerDlg::OnBnClickedButtonTurnOn)
	ON_BN_CLICKED(IDC_BUTTON_TURN_OFF, &CBluetoothManagerDlg::OnBnClickedButtonTurnOff)
	ON_BN_CLICKED(IDC_BUTTON_ENUM_COMS, &CBluetoothManagerDlg::OnBnClickedButtonEnumComs)
	ON_BN_CLICKED(IDC_BUTTON_CREATE_PORT, &CBluetoothManagerDlg::OnBnClickedButtonCreatePort)
	ON_BN_CLICKED(IDC_BUTTON_DESTROY_COM, &CBluetoothManagerDlg::OnBnClickedButtonDestroyCom)
	ON_BN_CLICKED(IDC_BUTTON_INSTALL_DEVICE, &CBluetoothManagerDlg::OnBnClickedButtonInstallDevice)
	ON_BN_CLICKED(IDC_BUTTON_UNINSTALL_DEVICE, &CBluetoothManagerDlg::OnBnClickedButtonUninstallDevice)
	ON_BN_CLICKED(IDC_BUTTON_IS_IN_RANGE, &CBluetoothManagerDlg::OnBnClickedButtonIsInRange)
	ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, &CBluetoothManagerDlg::OnBnClickedButtonDisconnect)
	ON_BN_CLICKED(IDC_BUTTON_ENUM_CONNECTED, &CBluetoothManagerDlg::OnBnClickedButtonEnumConnected)
	ON_BN_CLICKED(IDC_BUTTON_ENUM_INSTALLED_SERVICES, &CBluetoothManagerDlg::OnBnClickedButtonEnumInstalledServices)
END_MESSAGE_MAP()


// CBluetoothManagerDlg message handlers

BOOL CBluetoothManagerDlg::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

	__hook(&CwclBluetoothManager::AfterOpen, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerAfterOpen);
	__hook(&CwclBluetoothManager::BeforeClose, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerBeforeClose);
	__hook(&CwclBluetoothManager::OnAuthenticationCompleted, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerAuthenticationCompleted);
	__hook(&CwclBluetoothManager::OnDeviceFound, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerDeviceFound);
	__hook(&CwclBluetoothManager::OnDiscoveringCompleted, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerDiscoveringCompleted);
	__hook(&CwclBluetoothManager::OnDiscoveringStarted, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerDiscoveringStarted);
	__hook(&CwclBluetoothManager::OnNumericComparison, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerNumericComparison);
	__hook(&CwclBluetoothManager::OnPasskeyNotification, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerPasskeyNotification);
	__hook(&CwclBluetoothManager::OnPasskeyRequest, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerPasskeyRequest);
	__hook(&CwclBluetoothManager::OnPinRequest, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerPinRequest);
	__hook(&CwclBluetoothManager::OnStatusChanged, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerStatusChanged);
	__hook(&CwclBluetoothManager::OnConfirm, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerConfirm);
	__hook(&CwclBluetoothManager::OnIoCapabilityRequest, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerIoCapabilityRequest);
	__hook(&CwclBluetoothManager::OnOobDataRequest, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerOobDataRequest);
	__hook(&CwclBluetoothManager::OnProtectionLevelRequest, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerProtectionRequest);
	__hook(&CwclBluetoothManager::OnClosed, &wclBluetoothManager,
		&CBluetoothManagerDlg::wclBluetoothManagerClosed);

	__hook(&CwclPowerEventsMonitor::OnPowerStateChanged, &FPowerMonitor,
		&CBluetoothManagerDlg::PowerStateChanged);

	edName.SetWindowText(_T("NewRadioName"));

	lvRadios.InsertColumn(0, _T("Driver"), 0, 100);
	lvRadios.InsertColumn(1, _T("Available"), 0, 70);
	lvRadios.InsertColumn(2, _T("Address"), 0, 100);
	lvRadios.InsertColumn(3, _T("Connectable"), 0, 80);
	lvRadios.InsertColumn(4, _T("Discoverable"), 0, 80);
	lvRadios.InsertColumn(5, _T("HCI version"), 0, 70);
	lvRadios.InsertColumn(6, _T("LMP version"), 0, 80);
	lvRadios.InsertColumn(7, _T("Manufacturer"), 0, 80);
	lvRadios.InsertColumn(8, _T("Name"), 0, 100);
	lvRadios.InsertColumn(9, _T("COD"), 0, 100);
	lvRadios.SetExtendedStyle(lvRadios.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	edTimeout.SetWindowText(_T("10"));

	edPIN.SetWindowText(_T("0000"));

	lvDevices.InsertColumn(0, _T("Driver"), 0, 100);
	lvDevices.InsertColumn(1, _T("Address"), 0, 100);
	lvDevices.InsertColumn(2, _T("Class Of Device"), 0, 90);
	lvDevices.InsertColumn(3, _T("Device type"), 0, 80);
	lvDevices.InsertColumn(4, _T("Name"), 0, 100);
	lvDevices.InsertColumn(5, _T("Paired"), 0, 50);
	lvDevices.InsertColumn(6, _T("Connected"), 0, 80);
	lvDevices.InsertColumn(7, _T("Address type"), 0, 80);
	lvDevices.SetExtendedStyle(lvDevices.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	lvServices.InsertColumn(0, _T("Driver"), 0, 80);
	lvServices.InsertColumn(1, _T("Address"), 0, 90);
	lvServices.InsertColumn(2, _T("Handle"), 0, 80);
	lvServices.InsertColumn(3, _T("UUID"), 0, 230);
	lvServices.InsertColumn(4, _T("Channel"), 0, 60);
	lvServices.InsertColumn(5, _T("Name"), 0, 200);
	lvServices.InsertColumn(6, _T("Comment"), 0, 100);
	lvServices.SetExtendedStyle(lvServices.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	lvEvents.InsertColumn(0, _T("Driver"), 0, 100);
	lvEvents.InsertColumn(1, _T("Event"), 0, 220);
	lvEvents.InsertColumn(2, _T("Parameter"), 0, 220);
	lvEvents.InsertColumn(3, _T("Value"), 0, 220);
	lvEvents.SetExtendedStyle(lvEvents.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	lvComPorts.InsertColumn(0, _T("Driver"), 0, 80);
	lvComPorts.InsertColumn(1, _T("Address"), 0, 90);
	lvComPorts.InsertColumn(2, _T("UUID"), 0, 230);
	lvComPorts.InsertColumn(3, _T("Number"), 0, 60);
	lvComPorts.SetExtendedStyle(lvComPorts.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

	cbDiscoveringMode.AddString(_T("Classic"));
	cbDiscoveringMode.AddString(_T("BLE"));
	cbDiscoveringMode.SetCurSel(0);

	cbMitmProtection.AddString(_T("mitmProtectionNotRequired"));
	cbMitmProtection.AddString(_T("mitmProtectionRequired"));
	cbMitmProtection.AddString(_T("mitmProtectionNotRequiredBonding"));
	cbMitmProtection.AddString(_T("mitmProtectionRequiredBonding"));
	cbMitmProtection.AddString(_T("mitmProtectionNotRequiredGeneralBonding"));
	cbMitmProtection.AddString(_T("mitmProtectionRequiredGeneralBonding"));
	cbMitmProtection.AddString(_T("mitmProtectionNotDefined"));
	cbMitmProtection.SetCurSel(3);

	cbIoCap.AddString(_T("iocapDisplayOnly"));
	cbIoCap.AddString(_T("iocapDisplayYesNo"));
	cbIoCap.AddString(_T("iocapKeyboardOnly"));
	cbIoCap.AddString(_T("iocapNoInputNoOutput"));
	cbIoCap.AddString(_T("iocapDisplayKeyboard"));
	cbIoCap.AddString(_T("iocapNotDefined"));
	cbIoCap.SetCurSel(1);
	
	cbBleProtection.AddString(_T("pplDefault"));
	cbBleProtection.AddString(_T("pplNone"));
	cbBleProtection.AddString(_T("pplEncryption"));
	cbBleProtection.AddString(_T("pplEncryptionAndAuthentication"));
	cbBleProtection.SetCurSel(1);

	cbPairingMethod.AddString(_T("pmAuto"));
	cbPairingMethod.AddString(_T("pmClassic"));
	cbPairingMethod.AddString(_T("pmLe"));
	cbPairingMethod.SetCurSel(0);

	FPowerMonitor.Open();

	cbHandlePairing.SetCheck(TRUE);

	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 CBluetoothManagerDlg::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 CBluetoothManagerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CBluetoothManagerDlg::OnBnClickedButtonClear()
{
	lvEvents.DeleteAllItems();
}

void CBluetoothManagerDlg::TraceEvent(const CwclBluetoothRadio* const Radio, const CString& Event,
	const CString& Parameter, const CString& Value)
{
	int i = lvEvents.GetItemCount();
	
	if (Radio != NULL)
		lvEvents.InsertItem(i, Radio->ApiName.c_str());
	else
		lvEvents.InsertItem(i, _T(""));

	lvEvents.SetItemText(i, 1, Event);
	lvEvents.SetItemText(i, 2, Parameter);
	lvEvents.SetItemText(i, 3, Value);
}

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

	// TODO: Add your message handler code here

	wclBluetoothManager.Close();
	FPowerMonitor.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(&FPowerMonitor);
}

void CBluetoothManagerDlg::wclBluetoothManagerProtectionRequest(void* Sender,
	CwclBluetoothRadio* const Radio, const __int64 Address,
	wclBluetoothLeProtectionLevel& Protection)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);

	switch (cbBleProtection.GetCurSel())
	{
		case 0:
			Protection = pplDefault;
			break;
		case 1:
			Protection = pplNone;
			break;
		case 2:
			Protection = pplEncryption;
			break;
		case 3:
			Protection = pplEncryptionAndAuthentication;
			break;
		default:
			Protection = pplDefault;
	}
}

void CBluetoothManagerDlg::ClearRadios()
{
	lvRadios.DeleteAllItems();
	ClearDevices();
}

CString CBluetoothManagerDlg::BoolToStr(const bool b) const
{
	if (b)
		return CString(_T("True"));

	return CString(_T("false"));
}

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

CString CBluetoothManagerDlg::IntToHex(const unsigned long i) const
{
	CString s;
	s.Format(_T("%.8X"), i);
	return s;
}

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

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

void CBluetoothManagerDlg::RefreshRadio(const int Item)
{
	CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);

	lvRadios.SetItemText(Item, 0, Radio->ApiName.c_str());
	lvRadios.SetItemText(Item, 1, BoolToStr(Radio->Available));
	
	__int64 Address;
	int Res = Radio->GetAddress(Address);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 2, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 2, IntToHex(Address));
	
	bool BoolVal;
	Res = Radio->GetConnectable(BoolVal);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 3, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 3, BoolToStr(BoolVal));
	
	Res = Radio->GetDiscoverable(BoolVal);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 4, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 4, BoolToStr(BoolVal));
	
	unsigned char ByteVal;
	unsigned short WordVal;
	Res = Radio->GetHciVersion(ByteVal, WordVal);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 5, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 5, IntToStr(ByteVal) + _T(".") + IntToStr(WordVal));
	
	Res = Radio->GetLmpVersion(ByteVal, WordVal);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 6, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 6, IntToStr(ByteVal) + _T(".") + IntToStr(WordVal));
	
	Res = Radio->GetManufacturer(WordVal);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 7, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 7, IntToStr(WordVal));
	
	tstring StrVal;
	Res = Radio->GetName(StrVal);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 8, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 8, StrVal.c_str());

	unsigned long Cod;
	Res = Radio->GetCod(Cod);
	if (Res != WCL_E_SUCCESS)
		lvRadios.SetItemText(Item, 9, _T("Error: 0x") + IntToHex(Res));
	else
		lvRadios.SetItemText(Item, 9, _T("0x") + IntToHex(Cod));
}

void CBluetoothManagerDlg::ClearDevices()
{
	lvDevices.DeleteAllItems();
	ClearServices();
}

void CBluetoothManagerDlg::ClearComPorts()
{
	lvComPorts.DeleteAllItems();
}

void CBluetoothManagerDlg::ClearServices()
{
	lvServices.DeleteAllItems();
	ClearComPorts();
}

void CBluetoothManagerDlg::OnBnClickedButtonRefresh()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
		RefreshRadio(lvRadios.GetNextSelectedItem(Pos));
}

void CBluetoothManagerDlg::OnBnClickedButtonOpen()
{
	int Res = wclBluetoothManager.Open(cbHandlePairing.GetCheck() == TRUE);
	if (Res != WCL_E_SUCCESS)
		ShowError(Res);
}

void CBluetoothManagerDlg::OnBnClickedButtonClose()
{
	int Res = wclBluetoothManager.Close();
	if (Res != WCL_E_SUCCESS)
		ShowError(Res);
}

void CBluetoothManagerDlg::ShowError(const int Error) const
{
	AfxMessageBox(_T("Error: 0x") + IntToHex(Error));
}

void CBluetoothManagerDlg::OnBnClickedButtonSetConnectable()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		int Mr = AfxMessageBox(_T("[YES] - turn connectable ON, [NO] - turn connectable OFF"),
			MB_ICONINFORMATION | MB_YESNOCANCEL, 0);
		if (Mr != IDCANCEL)
		{
			int Item = lvRadios.GetNextSelectedItem(Pos);
			CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
			
			int Res = Radio->SetConnectable(Mr == IDYES);
			if (Res != WCL_E_SUCCESS)
				ShowError(Res);
			
			RefreshRadio(Item);
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonSetDiscoverable()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		int Mr = AfxMessageBox(_T("[YES] - turn discoverable ON, [NO] - turn discoverable OFF"),
			MB_ICONINFORMATION | MB_YESNOCANCEL, 0);
		if (Mr != IDCANCEL)
		{
			int Item = lvRadios.GetNextSelectedItem(Pos);
			CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
			
			int Res = Radio->SetDiscoverable(Mr == IDYES);
			if (Res != WCL_E_SUCCESS)
				ShowError(Res);
			
			RefreshRadio(Item);
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonSetName()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
		
		CString Name;
		edName.GetWindowText(Name);
		int Res = Radio->SetName(tstring(Name));
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		
		RefreshRadio(Item);
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonEnumPaired()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		ClearDevices();

		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
		
		wclBluetoothAddresses Devices;
		int Res = Radio->EnumPairedDevices(Devices);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		else
		{
			if (Devices.size() != 0)
			{
				for (wclBluetoothAddresses::iterator i = Devices.begin(); i != Devices.end(); i++)
					AddDevice(Radio, (*i));
				
				RefreshDevices();
				
				Devices.clear();
			}
		}
	}
}

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

void CBluetoothManagerDlg::RefreshDevice(const int Item)
{
	CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);

	__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));
	
	unsigned long Cod;
	int Res = Radio->GetRemoteCod(Address, Cod);
	if (Res != WCL_E_SUCCESS)
		lvDevices.SetItemText(Item, 2, _T("Error: 0x") + IntToHex(Res));
	else
		lvDevices.SetItemText(Item, 2, IntToHex((int)Cod));
	
	wclBluetoothDeviceType DevType;
	Res = Radio->GetRemoteDeviceType(Address, DevType);
	if (Res != WCL_E_SUCCESS)
		lvDevices.SetItemText(Item, 3, _T("Error: 0x") + IntToHex(Res));
	else
	{
		switch (DevType)
		{
			case dtClassic:
				lvDevices.SetItemText(Item, 3, _T("Classic"));
				break;
			case dtBle:
				lvDevices.SetItemText(Item, 3, _T("BLE"));
				break;
			case dtMixed:
				lvDevices.SetItemText(Item, 3, _T("Mixed"));
				break;
			default:
				lvDevices.SetItemText(Item, 3, _T("Unknown"));
				break;
		}
	}
	
	tstring DevName;
	Res = Radio->GetRemoteName(Address, DevName);
	if (Res != WCL_E_SUCCESS)
		lvDevices.SetItemText(Item, 4, _T("Error: 0x") + IntToHex(Res));
	else
		lvDevices.SetItemText(Item, 4, DevName.c_str());
	
	bool Paired;
	Res = Radio->GetRemotePaired(Address, Paired);
	if (Res != WCL_E_SUCCESS)
		lvDevices.SetItemText(Item, 5, _T("Error: 0x") + IntToHex(Res));
	else
		lvDevices.SetItemText(Item, 5, BoolToStr(Paired));
	
	bool Connected;
	Res = Radio->GetRemoteConnectedStatus(Address, Connected);
	if (Res != WCL_E_SUCCESS)
		lvDevices.SetItemText(Item, 6, _T("Error: 0x") + IntToHex(Res));
	else
		lvDevices.SetItemText(Item, 6, BoolToStr(Connected));

	wclBluetoothAddressType AddrType;
	Res = Radio->GetRemoteAddressType(Address, AddrType);
	if (Res != WCL_E_SUCCESS)
		lvDevices.SetItemText(Item, 7, _T("Error: 0x") + IntToHex(Res));
	else 
	{
		switch (AddrType)
		{
			case atClassic:
				lvDevices.SetItemText(Item, 7, _T("Classic"));
				break;
			case atPublic:
				lvDevices.SetItemText(Item, 7, _T("LE Public"));
				break;
			case atRandom:
				lvDevices.SetItemText(Item, 7, _T("LE Random"));
				break;
			case atUnspecified:
				lvDevices.SetItemText(Item, 7, _T("Unspecified"));
				break;
			default:
				lvDevices.SetItemText(Item, 7, _T("Unknown"));
				break;
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonRefreshDevice()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
		RefreshDevice(lvDevices.GetNextSelectedItem(Pos));
}

void CBluetoothManagerDlg::OnBnClickedButtonEnumServices()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		ClearServices();
		
		int Item = lvDevices.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);
		__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));
		
		wclBluetoothServices Services;
		int Res = Radio->EnumRemoteServices(Address, NULL, Services);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		else
		{
			if (Services.size() > 0)
			{
				int ndx = 0;
				for (wclBluetoothServices::iterator i = Services.begin(); i != Services.end(); i++)
				{
					LPOLESTR Guid;
					StringFromCLSID((*i).Uuid, &Guid);

					lvServices.InsertItem(ndx, Radio->ApiName.c_str());
					lvServices.SetItemText(ndx, 1, IntToHex(Address));
					lvServices.SetItemText(ndx, 2, IntToHex((int)(*i).Handle));
					lvServices.SetItemText(ndx, 3, Guid);
					lvServices.SetItemText(ndx, 4, IntToStr((*i).Channel));
					lvServices.SetItemText(ndx, 5, (*i).Name.c_str());
					lvServices.SetItemText(ndx, 6, (*i).Comment.c_str());

					CoTaskMemFree(Guid);
					ndx ++;
				}
				
				Services.clear();
			}
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonDiscover()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		ClearDevices();

		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
		
		CString s;
		edTimeout.GetWindowText(s);
		wclBluetoothDiscoverKind Kind;
		if (cbDiscoveringMode.GetCurSel() == 0)
			Kind = dkClassic;
		else
			Kind = dkBle;

		int Res = Radio->Discover(LOBYTE(LOWORD(StrToInt(s))), Kind);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
	}
}

int CBluetoothManagerDlg::StrToInt(const CString& s) const
{
	return _tcstol(s, NULL, 10);
}

void CBluetoothManagerDlg::OnBnClickedButtonTerminate()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);

		int Res = Radio->Terminate();
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
	}
}

void CBluetoothManagerDlg::AddDevice(CwclBluetoothRadio* const Radio,
	const __int64 Address)
{
	int Item = lvDevices.GetItemCount();
	lvDevices.InsertItem(Item, Radio->ApiName.c_str());
	lvDevices.SetItemData(Item, (DWORD_PTR)Radio);
	lvDevices.SetItemText(Item, 1, IntToHex(Address));
	lvDevices.SetItemText(Item, 2, _T("")); // Class Of Device
	lvDevices.SetItemText(Item, 3, _T("")); // Device type
	lvDevices.SetItemText(Item, 4, _T("")); // Name
	lvDevices.SetItemText(Item, 5, _T("")); // Paired
	lvDevices.SetItemText(Item, 6, _T("")); // Connected
	lvDevices.SetItemText(Item, 7, _T("")); // Address type
}

void CBluetoothManagerDlg::RefreshDevices()
{
	for (int i = 0; i < lvDevices.GetItemCount(); i++)
		RefreshDevice(i);
}

void CBluetoothManagerDlg::OnBnClickedButtonUnpair()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		int Item = lvDevices.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);
		__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));
		
		wclBluetoothPairingMethod Method;
		switch (cbPairingMethod.GetCurSel())
		{
			case 1:
				Method = pmClassic;
				break;
			case 2:
				Method = pmLe;
				break;
			default:
				Method = pmAuto;
				break;
		}

		int Res = Radio->RemoteUnpair(Address, Method);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		
		RefreshDevice(Item);
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonPair()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		int Item = lvDevices.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);
		__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));

		wclBluetoothPairingMethod Method;
		switch (cbPairingMethod.GetCurSel())
		{
			case 1:
				Method = pmClassic;
				break;
			case 2:
				Method = pmLe;
				break;
			default:
				Method = pmAuto;
				break;
		}

		int Res = Radio->RemotePair(Address, Method);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonRssi()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		int Item = lvDevices.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);
		__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));
		
		char Rssi;
		int Res = Radio->GetRemoteRssi(Address, Rssi);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		else
			AfxMessageBox(_T("RSSI: ") + IntToStr(Rssi) + _T("dB"));
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonTurnOn()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
		
		int Res = Radio->TurnOn();
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		
		RefreshRadio(Item);
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonTurnOff()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
		
		int Res = Radio->TurnOff();
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		
		RefreshRadio(Item);
	}
}

void CBluetoothManagerDlg::wclBluetoothManagerAfterOpen(void* Sender)
{
	UNREFERENCED_PARAMETER(Sender);

	CString s;
	if (wclBluetoothManager.HandlePairing)
		s = _T("True");
	else
		s = _T("False");
	TraceEvent(NULL, _T("AfterOpen"), _T("Handle pairing"), s);
}

void CBluetoothManagerDlg::wclBluetoothManagerBeforeClose(void* Sender)
{
	UNREFERENCED_PARAMETER(Sender);

	TraceEvent(NULL, _T("BeforeClose"), _T(""), _T(""));
}

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

	TraceEvent(Radio, _T("AuthenticationCompleted"), _T("Address"), IntToHex(Address));
	TraceEvent(NULL, _T(""), _T("Error"), _T("0x") + IntToHex(Error));
}

void CBluetoothManagerDlg::wclBluetoothManagerDeviceFound(void* Sender, CwclBluetoothRadio* const Radio,
	const __int64 Address)
{
	UNREFERENCED_PARAMETER(Sender);

	TraceEvent(Radio, _T("DeviceFound"), _T("Address"), IntToHex(Address));
	
	AddDevice(Radio, Address);
}

void CBluetoothManagerDlg::wclBluetoothManagerDiscoveringCompleted(void* Sender,
	CwclBluetoothRadio* const Radio, const int Error)
{
	UNREFERENCED_PARAMETER(Sender);

	TraceEvent(Radio, _T("DiscoveringCompleted"), _T("Error"), _T("0x") + IntToHex(Error));
	
	RefreshDevices();
}

void CBluetoothManagerDlg::wclBluetoothManagerDiscoveringStarted(void* Sender,
	CwclBluetoothRadio* const Radio)
{
	UNREFERENCED_PARAMETER(Sender);

	ClearDevices();
	
	TraceEvent(Radio, _T("DiscoveringStarted"), _T(""), _T(""));
}

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

	Confirm = true;
	
	TraceEvent(Radio, _T("NumericComparison"), _T("Address"), IntToHex(Address));
	TraceEvent(NULL, _T(""), _T("Number"), IntToStr(Number));
	TraceEvent(NULL, _T(""), _T("Confirm"), BoolToStr(Confirm));
}

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

	TraceEvent(Radio, _T("PasskeyNotification"), _T("Address"), IntToHex(Address));
	TraceEvent(NULL, _T(""), _T("Passkey"), IntToStr(Passkey));
}

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

	Passkey = 123456;
	
	TraceEvent(Radio, _T("PasskeyRequest"), _T("Address"), IntToHex(Address));
	TraceEvent(NULL, _T(""), _T("Passkey"), IntToStr(Passkey));
}

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

	CString s;
	edPIN.GetWindowText(s);
	Pin = s;
	
	TraceEvent(Radio, _T("PinRequest"), _T("Address"), IntToHex(Address));
	TraceEvent(NULL, _T(""), _T("PIN"), s);
}

void CBluetoothManagerDlg::wclBluetoothManagerStatusChanged(void* Sender, CwclBluetoothRadio* const Radio)
{
	UNREFERENCED_PARAMETER(Sender);

	CString Status;
	if (Radio->Available)
		Status = _T("Available");
	else
	{
		if (Radio->Plugged)
			Status = _T("Not available, Plugged");
		else
			Status = _T("Unplugged");
	}
	TraceEvent(Radio, _T("StatusChanged"), _T("New status"), Status);
	
	bool Found = false;
	for (int i = 0; i < lvRadios.GetItemCount(); i++)
	{
		if (((CwclBluetoothRadio*)lvRadios.GetItemData(i)) == Radio)
		{
			Found = true;
			RefreshRadio(i);
			break;
		}
	}

	if (!Found)
	{
		int i = lvRadios.GetItemCount();

		lvRadios.InsertItem(i, _T("")); // Api
		lvRadios.SetItemData(i, (DWORD_PTR)Radio);
		lvRadios.SetItemText(i, 1, _T("")); // Available
		lvRadios.SetItemText(i, 2, _T("")); // Address
		lvRadios.SetItemText(i, 3, _T("")); // Connectable
		lvRadios.SetItemText(i, 4, _T("")); // Discoverable
		lvRadios.SetItemText(i, 5, _T("")); // HCI version
		lvRadios.SetItemText(i, 6, _T("")); // LMP version
		lvRadios.SetItemText(i, 7, _T("")); // Manufacturer
		lvRadios.SetItemText(i, 8, _T("")); // Name
		lvRadios.SetItemText(i, 9, _T("")); // COD
		
		RefreshRadio(i);
	}

	if (cbDontTurnOff.GetCheck() && Radio->Plugged && !Radio->Available)
	{
		int Res = Radio->TurnOn();
		if (Res == WCL_E_BLUETOOTH_DRIVER_BUSY)
		{
			Sleep(200);
			Res = Radio->TurnOn();
		}
		if (Res != WCL_E_SUCCESS)
			TraceEvent(Radio, _T("Turn ON"), _T("Error"), IntToHex(Res));
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonEnumComs()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
		RefreshVComs();
}

void CBluetoothManagerDlg::RefreshVComs()
{
	ClearComPorts();

	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos != NULL)
	{
		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);

		wclVirtualComPorts Ports;
		int Res;
		if (cbEnumPreinstalled.GetCheck())
			Res = Radio->EnumComPorts(Ports);
		else
		{
			Ports = Radio->ComPorts;
			Res = WCL_E_SUCCESS;
		}
		
		if (Res != WCL_E_SUCCESS)
			AfxMessageBox(_T("Error enumerating vCOMs: 0x") + IntToHex(Res));
		else
		{
			int n = 0;
			for (wclVirtualComPorts::iterator i = Ports.begin(); i != Ports.end(); i++)
			{
				wclVirtualComPort Port = (*i);
				LPOLESTR Guid;
				StringFromCLSID(Port.Service, &Guid);
				
				lvComPorts.InsertItem(n, Radio->ApiName.c_str());
				lvComPorts.SetItemText(n, 1, IntToHex(Port.Address));
				lvComPorts.SetItemText(n, 2, Guid);
				lvComPorts.SetItemText(n, 3, IntToStr(Port.Number));
				lvComPorts.SetItemData(n, (DWORD_PTR)Radio);
				n++;
			}
		}
	}
}
void CBluetoothManagerDlg::OnBnClickedButtonCreatePort()
{
	POSITION DevPos = lvDevices.GetFirstSelectedItemPosition();
	if (DevPos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		POSITION SrvPos = lvServices.GetFirstSelectedItemPosition();
		if (SrvPos == NULL)
			AfxMessageBox(_T("Select service"));
		else
		{
			int DevItem = lvDevices.GetNextSelectedItem(DevPos);
			CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(DevItem);
			__int64 Address = StrToInt64(lvDevices.GetItemText(DevItem, 1));

			int SrvItem = lvServices.GetNextSelectedItem(SrvPos);
			CString s = lvServices.GetItemText(SrvItem, 3);
			GUID Service;
			CLSIDFromString((LPOLESTR)s.GetBuffer(), &Service);
			
			unsigned short Number;
			int Res = Radio->CreateComPort(Address, Service, Number);
			if (Res != WCL_E_SUCCESS)
				ShowError(Res);
			else
			{
				TraceEvent(Radio, _T("Create vCOM"), _T("Number"), IntToStr(Number));
				
				RefreshVComs();
			}
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonDestroyCom()
{
	POSITION Pos = lvComPorts.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select vCOM"));
	else
	{
		int Item = lvComPorts.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvComPorts.GetItemData(Item);
		unsigned short Number = LOWORD(StrToInt(lvComPorts.GetItemText(Item, 3)));
		
		int Res = Radio->DestroyComPort(Number);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		else
		{
			TraceEvent(Radio, _T("Destroy vCOM"), _T("Number"), IntToStr(Number));
			
			RefreshVComs();
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonInstallDevice()
{
	POSITION DevPos = lvDevices.GetFirstSelectedItemPosition();
	if (DevPos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		POSITION SrvPos = lvServices.GetFirstSelectedItemPosition();
		if (SrvPos == NULL)
			AfxMessageBox(_T("Select service"));
		else
		{
			int DevItem = lvDevices.GetNextSelectedItem(DevPos);
			CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(DevItem);
			__int64 Address = StrToInt64(lvDevices.GetItemText(DevItem, 1));

			int SrvItem = lvServices.GetNextSelectedItem(SrvPos);
			CString s = lvServices.GetItemText(SrvItem, 3);
			GUID Service;
			CLSIDFromString((LPOLESTR)s.GetBuffer(), &Service);

			int Res = Radio->InstallDevice(Address, Service);
			if (Res == WCL_E_BLUETOOTH_DEVICE_ALREADY_INSTALLED)
			{
				// Reinstall to reconnect!
				Radio->UninstallDevice(Address, Service);
				Res = Radio->InstallDevice(Address, Service);
			}

			if (Res != WCL_E_SUCCESS)
				ShowError(Res);
			else
				AfxMessageBox(_T("Device installed"));
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonUninstallDevice()
{
	POSITION DevPos = lvDevices.GetFirstSelectedItemPosition();
	if (DevPos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		POSITION SrvPos = lvServices.GetFirstSelectedItemPosition();
		if (SrvPos == NULL)
			AfxMessageBox(_T("Select service"));
		else
		{
			int DevItem = lvDevices.GetNextSelectedItem(DevPos);
			CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(DevItem);
			__int64 Address = StrToInt64(lvDevices.GetItemText(DevItem, 1));

			int SrvItem = lvServices.GetNextSelectedItem(SrvPos);
			CString s = lvServices.GetItemText(SrvItem, 3);
			GUID Service;
			CLSIDFromString((LPOLESTR)s.GetBuffer(), &Service);

			int Res = Radio->UninstallDevice(Address, Service);
			if (Res != WCL_E_SUCCESS)
				ShowError(Res);
			else
				AfxMessageBox(_T("Device uninstalled"));
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonIsInRange()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		int Item = lvDevices.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);
		__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));
		
		bool InRange;
		int Res = Radio->IsRemoteDeviceInRange(Address, InRange);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		else
		{
			if (InRange)
				AfxMessageBox(_T("Device is in range"));
			else
				AfxMessageBox(_T("Device is NOT in range"));
		}
	}
}

void CBluetoothManagerDlg::wclBluetoothManagerConfirm(void* Sender, CwclBluetoothRadio* const Radio, 
	const __int64 Address, bool& Confirm)
{
	UNREFERENCED_PARAMETER(Sender);

	Confirm = true;
	
	TraceEvent(Radio, _T("Just Works pairing"), _T("Address"), IntToHex(Address));
}

void CBluetoothManagerDlg::wclBluetoothManagerIoCapabilityRequest(void* Sender,
	CwclBluetoothRadio* const Radio, const __int64 Address, wclBluetoothMitmProtection& Mitm,
	wclBluetoothIoCapability& IoCapability, bool& OobPresent)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);

	switch (cbMitmProtection.GetCurSel())
	{
		case 0:
			Mitm = mitmProtectionNotRequired;
			break;
		case 1:
			Mitm = mitmProtectionRequired;
			break;
		case 2:
			Mitm = mitmProtectionNotRequiredBonding;
			break;
		case 3:
			Mitm = mitmProtectionRequiredBonding;
			break;
		case 4:
			Mitm = mitmProtectionNotRequiredGeneralBonding;
			break;
		case 5:
			Mitm = mitmProtectionRequiredGeneralBonding;
			break;
		default:
			Mitm = mitmProtectionNotDefined;
			break;
	}
	
	switch (cbIoCap.GetCurSel())
	{
		case 0:
			IoCapability = iocapDisplayOnly;
			break;
		case 1:
			IoCapability = iocapDisplayYesNo;
			break;
		case 2:
			IoCapability = iocapKeyboardOnly;
			break;
		case 3:
			IoCapability = iocapNoInputNoOutput;
			break;
		case 4:
			IoCapability = iocapDisplayKeyboard;
			break;
		default:
			IoCapability = iocapNotDefined;
			break;
	}
	
	// To accept OOB pairing set this parameter to True.
	OobPresent = false;
}

void CBluetoothManagerDlg::wclBluetoothManagerOobDataRequest(void* Sender, 
	CwclBluetoothRadio* const Radio, const __int64 Address, wclBluetoothOobData& OobData)
{
	UNREFERENCED_PARAMETER(Sender);
	UNREFERENCED_PARAMETER(Radio);
	UNREFERENCED_PARAMETER(Address);
	
	// This event fires when a remote device requests OOB data.
	ZeroMemory(&OobData, sizeof(wclBluetoothOobData));
}

void CBluetoothManagerDlg::PowerStateChanged(void* Sender, const wclPowerState State)
{
	UNREFERENCED_PARAMETER(Sender);

	static bool WasOpened = false;
	
	switch (State)
	{
		case psResumeAutomatic:
			TraceEvent(NULL, _T("Power"), _T("State"), _T("psResumeAutomatic"));
			if (WasOpened)
			{
				WasOpened = false;
				wclBluetoothManager.Open();
			}
			break;

		case psResume:
			TraceEvent(NULL, _T("Power"), _T("State"), _T("psResume"));
			break;

		case psSuspend:
			TraceEvent(NULL, _T("Power"), _T("State"), _T("psSuspend"));
			if (wclBluetoothManager.Active)
			{
				WasOpened = true;
				wclBluetoothManager.Close();
			}
			break;

		case psPowerStatusChanged:
			TraceEvent(NULL, _T("Power"), _T("State"), _T("psPowerStatusChanged"));
			break;

		case psUnknown:
			TraceEvent(NULL, _T("Power"), _T("State"), _T("psUnknown"));
			break;
	}
}

void CBluetoothManagerDlg::wclBluetoothManagerClosed(void* Sender)
{
	UNREFERENCED_PARAMETER(Sender);

	ClearRadios();
	TraceEvent(NULL, _T("Closed"), _T(""), _T(""));
}

void CBluetoothManagerDlg::OnBnClickedButtonDisconnect()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		int Item = lvDevices.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);
		__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));

		int Res = Radio->RemoteDisconnect(Address);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonEnumConnected()
{
	POSITION Pos = lvRadios.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select radio"));
	else
	{
		ClearDevices();

		int Item = lvRadios.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvRadios.GetItemData(Item);
		
		wclBluetoothAddresses Devices;
		int Res = Radio->EnumConnectedDevices(Devices);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		else
		{
			if (Devices.size() != 0)
			{
				for (wclBluetoothAddresses::iterator i = Devices.begin(); i != Devices.end(); i++)
					AddDevice(Radio, (*i));
				
				RefreshDevices();
				
				Devices.clear();
			}
		}
	}
}

void CBluetoothManagerDlg::OnBnClickedButtonEnumInstalledServices()
{
	POSITION Pos = lvDevices.GetFirstSelectedItemPosition();
	if (Pos == NULL)
		AfxMessageBox(_T("Select device"));
	else
	{
		ClearServices();

		int Item = lvDevices.GetNextSelectedItem(Pos);
		CwclBluetoothRadio* Radio = (CwclBluetoothRadio*)lvDevices.GetItemData(Item);
		__int64 Address = StrToInt64(lvDevices.GetItemText(Item, 1));

		wclBluetoothInstalledServices Services;
		int Res = Radio->EnumInstalledServices(Address, Services);
		if (Res != WCL_E_SUCCESS)
			ShowError(Res);
		else
		{
			if (Services.size() > 0)
			{
				int ndx = 0;
				for (wclBluetoothInstalledServices::iterator i = Services.begin(); i != Services.end(); i++)
				{
					LPOLESTR Guid;
					StringFromCLSID((*i), &Guid);

					lvServices.InsertItem(ndx, Radio->ApiName.c_str());
					lvServices.SetItemText(ndx, 1, IntToHex(Address));
					lvServices.SetItemText(ndx, 2, _T(""));
					lvServices.SetItemText(ndx, 3, Guid);
					lvServices.SetItemText(ndx, 4, _T(""));
					lvServices.SetItemText(ndx, 5, _T(""));
					lvServices.SetItemText(ndx, 6, _T(""));

					CoTaskMemFree(Guid);
					ndx ++;
				}
			}
		}
	}
}
