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

#include "pch.h"
#include <process.h>

#include "..\..\..\..\Source\WiFi\wclWiFi.h"

using namespace std;

using namespace wclCommon;
using namespace wclWiFi;

string wtoa(const tstring& w)
{
	return string(w.begin(), w.end());
}

class CWiFiDirect
{
private:
	HANDLE	TerminateEvent;
	HANDLE	Thread;
	
	void wclWiFiDirectAdvertiserStarted(void* Sender)
	{
		UNREFERENCED_PARAMETER(Sender);

		cout << "WiFi Direct Advertiser has been started" << endl;
	}

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

		cout << "WiFi Direct Advertiser has been stopped" << endl;
	}

	void wclWiFiDirectAdvertiserAcceptDevice(void* Sender, CwclWiFiDirectDevice* const Device,
		bool& Accept)
	{
		UNREFERENCED_PARAMETER(Sender);

		cout << endl << "Device " << wtoa(Device->Name).c_str() << " requires connection. Accept." << endl;
		Accept = true;
	}

	void wclWiFiDirectAdvertiserDeviceConnected(void* Sender, CwclWiFiDirectDevice* const Device, 
		const int Error)
	{
		UNREFERENCED_PARAMETER(Sender);

		if (Error != WCL_E_SUCCESS)
			cout << "Device " << wtoa(Device->Name).c_str() << " connect error: 0x" << hex << Error << dec << endl;
		else
		{
			cout << "Device " << wtoa(Device->Name).c_str() << " has been connected" << endl;
			cout << "  Local IP: " << wtoa(Device->LocalAddress).c_str() << endl;
			cout << "  Remote IP: " << wtoa(Device->RemoteAddress).c_str() << endl;
		}
	}

	void wclWiFiDirectAdvertiserDeviceDisconnected(void* Sender, CwclWiFiDirectDevice* const Device, 
		const int Reason)
	{
		UNREFERENCED_PARAMETER(Sender);

		cout << "Device " << wtoa(Device->Name).c_str() << " has been disconnected by reason: 0x" << hex << Reason << dec << endl;
	}

	void wclWiFiDirectAdvertiserPairCompleted(void* Sender, CwclWiFiDirectDevice* const Device, 
		const int Result)
	{
		UNREFERENCED_PARAMETER(Sender);

		cout << "Pairing with device " << wtoa(Device->Name).c_str() << " has been completed with result: 0x" << hex << Result << dec << endl;
	}

	void wclWiFiDirectAdvertiserPairConfirm(void* Sender, CwclWiFiDirectDevice* const Device, 
		bool& Confirm)
	{
		UNREFERENCED_PARAMETER(Sender);

		cout << "Pairing with device " << wtoa(Device->Name).c_str() << " has been confirmed" << endl;
		Confirm = true;
	}

	void wclWiFiDirectAdvertiserPairDisplayPin(void* Sender, CwclWiFiDirectDevice* const Device, 
		const tstring& Pin)
	{
		UNREFERENCED_PARAMETER(Sender);

		cout << "To pair with device " << wtoa(Device->Name).c_str() << " type this PIN: " << wtoa(Pin).c_str() << " on device keyboard" << endl;
	}

	void wclWiFiDirectAdvertiserPairGetParams(void* Sender, CwclWiFiDirectDevice* const Device, 
		short& GroupOwnerIntent, wclWiFiDirectConfigurationMethods& ConfigurationMethods, 
		wclWiFiDirectPairingProcedure& PairingProcedure)
	{
		UNREFERENCED_PARAMETER(Sender);
		UNREFERENCED_PARAMETER(Device);

		cout << "Connection is accepted with following parameters:" << endl;
		cout << "  Pairing procedure: Group Owner Negotiation" << endl;
		cout << "  GroupOwnerIntent: default (14)" << endl;
		cout << "  Configuration (pairing) method: Push Button (Configm Only)" << endl;

		PairingProcedure = ppGroupOwnerNegotiation;
		GroupOwnerIntent = 14;
		ConfigurationMethods.clear();
		ConfigurationMethods.insert(cmPushButton);
	}

	void wclWiFiDirectAdvertiserPairProvidePin(void* Sender, CwclWiFiDirectDevice* const Device, 
		tstring& Pin)
	{
		UNREFERENCED_PARAMETER(Sender);
		UNREFERENCED_PARAMETER(Device);

		cout << "Device requires pairing with entering PIN on Advertiser side. This type of pairing is not supported in this demo" << endl;
		Pin = _T("");
	}

	static UINT __stdcall _ThreadProc(LPVOID Param)
	{
		((CWiFiDirect*)Param)->ThreadProc();
		return 0;
	}

	void ThreadProc()
	{
		CwclWiFiDirectAdvertiser* Advertiser = new CwclWiFiDirectAdvertiser();
		__hook(&CwclWiFiDirectAdvertiser::OnStarted, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserStarted);
		__hook(&CwclWiFiDirectAdvertiser::OnStopped, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserStopped);
		__hook(&CwclWiFiDirectAdvertiser::OnAcceptDevice, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserAcceptDevice);
		__hook(&CwclWiFiDirectAdvertiser::OnDeviceConnected, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserDeviceConnected);
		__hook(&CwclWiFiDirectAdvertiser::OnDeviceDisconnected, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserDeviceDisconnected);
		__hook(&CwclWiFiDirectAdvertiser::OnPairCompleted, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserPairCompleted);
		__hook(&CwclWiFiDirectAdvertiser::OnPairConfirm, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserPairConfirm);
		__hook(&CwclWiFiDirectAdvertiser::OnPairDisplayPin, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserPairDisplayPin);
		__hook(&CwclWiFiDirectAdvertiser::OnPairProvidePin, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserPairProvidePin);
		__hook(&CwclWiFiDirectAdvertiser::OnPairGetParams, Advertiser, &CWiFiDirect::wclWiFiDirectAdvertiserPairGetParams);

		Advertiser->AutonomousGroupOwnerEnabled = false;
		Advertiser->Discoverability = adNormal;
		Advertiser->Legacy = false;

		int Res = Advertiser->Start();
		if (Res != WCL_E_SUCCESS)
			cout << "Failed to start WiFi Direct Advertiser: 0x" << hex << Res << dec << endl;

		CwclMessageBroadcaster::Wait(TerminateEvent);

		if (Advertiser->Active)
		{
			Res = Advertiser->Stop();
			if (Res != WCL_E_SUCCESS)
				cout << "Failed to stop WiFi Direct Advertiser: 0x" << hex << Res << dec << endl;
		}

		__unhook(Advertiser);
		delete Advertiser;
	}

public: 
	CWiFiDirect()
	{
		TerminateEvent = NULL;
		Thread = NULL;
	}

	void Start()
	{
		TerminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		Thread = (HANDLE)_beginthreadex(NULL, 0, _ThreadProc, this, 0, NULL);
	}

	void Stop()
	{
		SetEvent(TerminateEvent);
		WaitForSingleObject(Thread, INFINITE);
		CloseHandle(Thread);
		CloseHandle(TerminateEvent);
	}
};

int main(int argc, char **argv)
{
	UNREFERENCED_PARAMETER(argc);
	UNREFERENCED_PARAMETER(argv);

	CwclMessageBroadcaster::SetSyncMethod(skApc);

	system("cls");
	cout << "WIFI DIRECT ADVERTISER DEMO" << endl;
	cout << "===========================" << endl;
	cout << "The following parameters will be used:" << endl;
	cout << "  Discoverability: Normal" << endl;
	cout << "  Autonomous Group Owner: Disabled" << endl;
	cout << "  Legacy mode: Disabled" << endl;

	CWiFiDirect* Adv = new CWiFiDirect();
	Adv->Start();
	system("pause");
	Adv->Stop();
	delete Adv;
}

