#pragma once

#include <ppltasks.h>	// For create_task

#ifndef __cplusplus_winrt
# include <PathCch.h>
# pragma comment(lib, "PathCch.lib")
#endif

namespace DX {
	inline void ThrowIfFailed(HRESULT hr) {
		if(FAILED(hr)) {
			// Set a breakpoint on this line to catch Win32 API errors.
#ifdef __cplusplus_winrt
			throw Platform::Exception::CreateException(hr);
#else
			_com_raise_error(hr);
#endif
		}
	}

	// Function that reads from a binary file asynchronously.
	inline Concurrency::task<std::vector<byte>> ReadDataAsync(const std::wstring& filename) {
		using namespace Concurrency;
#ifdef __cplusplus_winrt
		using namespace Windows::Storage;

		auto folder = Windows::ApplicationModel::Package::Current->InstalledLocation;

		return create_task(folder->GetFileAsync(Platform::StringReference(filename.c_str()))).then([](StorageFile^ file) {
			return FileIO::ReadBufferAsync(file);
		}).then([](Streams::IBuffer^ fileBuffer) -> std::vector<byte> {
			std::vector<byte> returnBuffer;
			returnBuffer.resize(fileBuffer->Length);
			Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(Platform::ArrayReference<byte>(returnBuffer.data(), fileBuffer->Length));
			return returnBuffer;
		});
#else
		return create_task([filename] {
			TCHAR path[MAX_PATH];
			GetModuleFileName(NULL, path, _countof(path));
			PathCchRemoveFileSpec(path, _countof(path));
			PathCchAppend(path, _countof(path), filename.c_str());
			std::vector<byte> returnBuffer;
			std::ifstream fin(path, std::ios::binary);
			fin.unsetf(std::ios::skipws);
			returnBuffer.insert(returnBuffer.begin(),
				std::istream_iterator<BYTE>(fin),
				std::istream_iterator<BYTE>());
			return returnBuffer;
		});
#endif
	}

	// Converts a length in device-independent pixels (DIPs) to a length in physical pixels.
	inline float ConvertDipsToPixels(float dips, float dpi) {
		static const float dipsPerInch = 96.0f;
		return floorf(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer.
	}

#if defined(_DEBUG)
	// Check for SDK Layer support.
	inline bool SdkLayersAvailable() {
		HRESULT hr = D3D11CreateDevice(
			nullptr,
			D3D_DRIVER_TYPE_NULL,       // There is no need to create a real hardware device.
			0,
			D3D11_CREATE_DEVICE_DEBUG,  // Check for the SDK layers.
			nullptr,                    // Any feature level will do.
			0,
			D3D11_SDK_VERSION,          // Always set this to D3D11_SDK_VERSION for Windows Store apps.
			nullptr,                    // No need to keep the D3D device reference.
			nullptr,                    // No need to know the feature level.
			nullptr                     // No need to keep the D3D device context reference.
		);

		return SUCCEEDED(hr);
	}
#endif
}
