#include "ApplicationData.h"
#include "Util.h"
#include "AudioApi.h"
#include <functiondiscoverykeys.h>

AudioDevice::AudioDevice(IMMDevice* device, LPCWSTR deviceId)
{
	id = std::wstring(deviceId);

	IPropertyStore* propertyStore;
	HRESULT err = device->OpenPropertyStore(STGM_READ, &propertyStore);
	isError(err, "Failed to open prop store: ");

	PROPVARIANT deviceNameProp;
	const wchar_t* deviceName;
	err = getDevicePropertyString(propertyStore, PKEY_Device_FriendlyName, &deviceNameProp, deviceName);
	isError(err, "Failed to read name of device :");
	name = utf8Encode(deviceName);

	err = device->GetState(&state);
	isError(err, "Failed to reat state of device: ");

	err = device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&volumeInterface);
	isError(err, "Failed to get audio endpoint volume interface: ");

	err = device->Activate(__uuidof(IAudioMeterInformation), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&meterInterface);
	isError(err, "Failed to get audio meter interface: ");

	if (propertyStore)
	{
		propertyStore->Release();
	}
}

AudioDevice::AudioDevice(AudioDevice&& other) noexcept
	: device(other.device), volumeInterface(other.volumeInterface), meterInterface(other.meterInterface),
	id(other.id), name(other.name), state(other.state),
	isDefaultConsole(other.isDefaultConsole), isDefaultMedia(other.isDefaultMedia), isDefaultCommunication(other.isDefaultCommunication)
{
	other.device = nullptr;
	other.volumeInterface = nullptr;
	other.meterInterface = nullptr;
}

AudioDevice& AudioDevice::operator=(AudioDevice&& other) noexcept
{
	this->device = other.device;
	this->volumeInterface = other.volumeInterface;
	this->meterInterface = other.meterInterface;
	this->id = other.id;
	this->name = other.name;
	this->state = other.state;
	this->isDefaultConsole = other.isDefaultConsole;
	this->isDefaultMedia = other.isDefaultMedia;
	this->isDefaultCommunication = other.isDefaultCommunication;

	other.device = nullptr;
	other.volumeInterface = nullptr;
	other.meterInterface = nullptr;
	return *this;
}

AudioDevice::~AudioDevice()
{
	if (volumeInterface)
	{
		volumeInterface->Release();
		volumeInterface = nullptr;
	}
	if (meterInterface)
	{
		meterInterface->Release();
		meterInterface = nullptr;
	}
	if (device)
	{
		device->Release();
		device = nullptr;
	}
}

AudioData::AudioData()
{
}

AudioData::AudioData(AudioData&& other) noexcept
	: playbackDevices(std::move(other.playbackDevices)), recordingDevices(std::move(other.recordingDevices)),
	deviceEnumerator(other.deviceEnumerator), audioNotificationListener(other.audioNotificationListener)
{
	other.deviceEnumerator = nullptr;
	other.audioNotificationListener = nullptr;
}

AudioData& AudioData::operator=(AudioData&& other) noexcept
{
	playbackDevices = std::move(other.playbackDevices);
	recordingDevices = std::move(other.recordingDevices);
	deviceEnumerator = other.deviceEnumerator;
	audioNotificationListener = other.audioNotificationListener;

	other.deviceEnumerator = nullptr;
	other.audioNotificationListener = nullptr;
	return *this;
}

AudioData::~AudioData()
{
	if (deviceEnumerator)
	{
		deviceEnumerator->Release();
		deviceEnumerator = nullptr;
	}
	if (audioNotificationListener)
	{
		audioNotificationListener->Release();
		audioNotificationListener = nullptr;
	}
}
