#include "stdafx.h"
#include "stdio.h"
#include "VRPNDLLClient.h"
#include <signal.h>

#include <iostream>

VRPNDLLClient *VRPNDLLClient::smIntance = NULL;

VRPNDLLClient * VRPNDLLClient::GetInstance()
{
	if( smIntance == NULL )
		smIntance = new VRPNDLLClient;

	return smIntance;
}

VRPNDLLClient::VRPNDLLClient(void)
{
	mAnalog = NULL;
	mButton = NULL;
}

VRPNDLLClient::~VRPNDLLClient(void)
{
	Stop();
}

void VRPNDLLClient::Start()
{
	stopDll = false;
	
	// Create vrpn connections
	mAnalog = new vrpn_Analog_Remote(deviceConnection.c_str());
	if( mAnalog != NULL )
	{
		printf("Good! VRPN Analog connection Created\n");
		mAnalog->register_change_handler(this, handle_analog);
	}
	else
	{
		printf("Error: cannot connect to analog device\n");
	}

	deviceThreadHandle = CreateThread(NULL, 0, &VRPNDLLClient::ThreadDevice, (LPVOID) this, 0, NULL);
}

void VRPNDLLClient::Stop()
{
	stopDll = true;

	if( deviceThreadHandle != NULL )
		WaitForSingleObject(deviceThreadHandle, INFINITE);
	deviceThreadHandle = NULL;

	// Stop vrpn connections
	if( mAnalog != NULL ){
		mAnalog->unregister_change_handler( this, handle_analog );
		
		delete mAnalog;
		mAnalog = NULL;
	}
}

// --------------------------------------------------------------------------------
// Device methods

DWORD WINAPI VRPNDLLClient::ThreadDevice( LPVOID pThis )
{
	VRPNDLLClient * device = (VRPNDLLClient*)pThis;
	device->RunDevice();

	return 0;
}

void VRPNDLLClient::SetupDevice( const char * deviceName, int buttonsChannel, int yawChannel, int pitchChannel, int rollChannel, int deltaXChannel, int deltaYChannel, int deltaZChannel)
{
	this->deviceConnection = "";
	this->deviceConnection.append(deviceName);

	this->buttonsChannel = buttonsChannel;

	this->deltaXChannel = deltaXChannel;
	this->deltaYChannel = deltaYChannel;
	this->deltaZChannel = deltaZChannel;

	this->yawChannel = yawChannel;
	this->pitchChannel = pitchChannel;
	this->rollChannel = rollChannel;
}

void VRPNDLLClient::RunDevice()
{
	while( !stopDll )
	{
		mAnalog->mainloop();
		Sleep((DWORD)1);
	}

	ExitThread(0);
}

void VRPN_CALLBACK VRPNDLLClient::handle_analog( void* userData, const vrpn_ANALOGCB a )
{
	VRPNDLLClient * device = (VRPNDLLClient *)userData;
	device->ProcessAnalog( a );
}

void VRPNDLLClient::ProcessAnalog( const vrpn_ANALOGCB a )
{
	if( a.num_channel < buttonsChannel || a.num_channel < yawChannel || a.num_channel < pitchChannel || a.num_channel < rollChannel || a.num_channel < deltaXChannel || a.num_channel < deltaYChannel || a.num_channel < deltaZChannel)
		return ;

	buttons = (int)a.channel[buttonsChannel];

	yaw = (float)a.channel[yawChannel];
	pitch = (float)a.channel[pitchChannel];
	roll = (float)a.channel[rollChannel];

	deltaX = (float)a.channel[deltaXChannel];
	deltaY = (float)a.channel[deltaYChannel];
	deltaZ = (float)a.channel[deltaZChannel];
}
