// Console.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>

#include "..\..\..\..\Source\Bluetooth\wclBluetooth.h"

using namespace wclCommon;
using namespace wclBluetooth;

#pragma comment(lib, "ws2_32.lib")

std::string IntToHex(const int i)
{
	CHAR buf[10];
	sprintf_s(buf, 10, "%.8X", i);
	return std::string(buf);
}

std::string IntToHex(const __int64 i)
{
	CHAR buf[20];
	sprintf_s(buf, 20, "%.4X%.8X", static_cast<INT32>((i >> 32) & 0x00000FFFF),
		static_cast<INT32>(i) & 0xFFFFFFFF);
	return std::string(buf);
}

void WriteLn(const std::string& Str)
{
	std::cout << Str.c_str() << std::endl;
}

class CwclConsole
{
private:
	HANDLE FEvent;

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

		SetEvent(FEvent);
	}

	void ManagerClosed(void* Sender)
	{
		UNREFERENCED_PARAMETER(Sender);

		SetEvent(FEvent);
	}
	
	void ManagerDiscoveringStarted(void* Sender, CwclBluetoothRadio* const Radio)
	{
		UNREFERENCED_PARAMETER(Sender);
		UNREFERENCED_PARAMETER(Radio);

		WriteLn("Discovering has been started");
	}
	
	void ManagerDiscoveringCompleted(void* Sender, CwclBluetoothRadio* const Radio,
		const int Error)
	{
		UNREFERENCED_PARAMETER(Sender);
		UNREFERENCED_PARAMETER(Radio);
		UNREFERENCED_PARAMETER(Error);

		WriteLn("Discoverign has been compledted");
		SetEvent(FEvent);
	}
	
	void ManagerDeviceFound(void* Sender, CwclBluetoothRadio* const Radio, const __int64 Address)
	{
		UNREFERENCED_PARAMETER(Sender);
		UNREFERENCED_PARAMETER(Radio);

		WriteLn("Device " + IntToHex(Address) + " found");
	}

	void WaitForOperationCompletion()
	{
		CwclMessageBroadcaster::Wait(FEvent);
	}

public:
	void Run()
	{
		WriteLn("Bluetooth Framework Console Demo application");
		WriteLn("  The demo is very simple: it just discovers nearby classic and LE");
		WriteLn("  devices.");
		WriteLn("  The demo shows how to use Bluetooth Framework in console");
		WriteLn("  applications with APC synchronization.");
		system("pause");
		
		// Change default synchronization method.
		CwclMessageBroadcaster::SetSyncMethod(skApc);
		
		// Create classes we have to use.
		CwclBluetoothManager* Manager = new CwclBluetoothManager();
		__hook(&CwclBluetoothManager::AfterOpen, Manager, &CwclConsole::ManagerAfterOpen);
		__hook(&CwclBluetoothManager::OnClosed, Manager, &CwclConsole::ManagerClosed);
		__hook(&CwclBluetoothManager::OnDeviceFound, Manager, &CwclConsole::ManagerDeviceFound);
		__hook(&CwclBluetoothManager::OnDiscoveringCompleted, Manager, &CwclConsole::ManagerDiscoveringCompleted);
		__hook(&CwclBluetoothManager::OnDiscoveringStarted, Manager, &CwclConsole::ManagerDiscoveringStarted);
		
		// The event used to notify about event completion.
		FEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
		if (FEvent == NULL)
			WriteLn("Unable to create synchronization event!");
		else
		{
			// Open Bluetooth Manager
			int Res = Manager->Open();
			if (Res != WCL_E_SUCCESS)
				WriteLn("Open Bluetooth Manager failed: 0x" + IntToHex(Res));
			else
			{
				// Wait for Open completion.
				WaitForOperationCompletion();
				
				// Try to find available Bluetooth Radio. Use first one found.
				if (Manager->Count == 0)
					WriteLn("No Bluetooth Hardware connected.");
				else
				{
					CwclBluetoothRadio* Radio = NULL;
					for (size_t i = 0; i < Manager->Count; i++)
					{
						if (Manager->Radios[i]->Available)
						{
							Radio = Manager->Radios[i];
							break;
						}
					}
					
					if (Radio == NULL)
						WriteLn("Available BluetoothRadio not found.");
					else
					{
						// Discover classic devices
						WriteLn("Try to start classic discovering");
						Res = Radio->Discover(10, dkClassic);
						if (Res != WCL_E_SUCCESS)
							WriteLn("Start classic discovering failed: 0x" + IntToHex(Res));
						else
							// Wait for discovering completion.
							WaitForOperationCompletion();
						
						// Discover LE devices
						WriteLn("Try to start LE discovering");
						Res = Radio->Discover(10, dkBle);
						if (Res != WCL_E_SUCCESS)
							WriteLn("Start LE discovering failed: 0x" + IntToHex(Res));
						else
							// Wait for discovering completion.
							WaitForOperationCompletion();
					}
				}
				
				// Close Bluetooth Manager.
				Res = Manager->Close();
				if (Res != WCL_E_SUCCESS)
					WriteLn("Open Bluetooth Manager failed: 0x" + IntToHex(Res));
				else
					// Wait for Close completion.
					WaitForOperationCompletion();
			}
			
			// Do not forget about event.
			CloseHandle(FEvent);
		}
		
		// 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(Manager);
		// Do not forget to destroy Bluetooth Manager.
		delete Manager;
		
		system("pause");
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	UNREFERENCED_PARAMETER(argc);
	UNREFERENCED_PARAMETER(argv);

	CwclConsole c;
	c.Run();
}
