/***********************************************************************
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
DEVELOPER: Zihan Chen(vczh)
***********************************************************************/
#include "Vlpp.h"

/***********************************************************************
.\CONSOLE.WINDOWS.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/

#define _WINSOCKAPI_
#include <Windows.h>

#ifndef VCZH_MSVC
static_assert(false, "Do not build this file for non-Windows applications.");
#endif

namespace vl
{
	namespace console
	{

/***********************************************************************
Console
***********************************************************************/

		void Console::Write(const wchar_t* string, vint length)
		{
			CHECK_ERROR(IsEnabled(), L"vl::console::Console::Write(const wchar_t*, vint)#Console operations are disabled.");
			HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE);
			DWORD fileMode = 0;
			DWORD written = 0;
			if ((GetFileType(outHandle) & FILE_TYPE_CHAR) && GetConsoleMode(outHandle, &fileMode))
			{
				WriteConsole(outHandle, string, (int)length, &written, 0);
			}
			else
			{
				int codePage = GetConsoleOutputCP();
				int charCount = WideCharToMultiByte(codePage, 0, string, -1, 0, 0, 0, 0);
				char* codePageBuffer = new char[charCount];
				WideCharToMultiByte(codePage, 0, string, -1, codePageBuffer, charCount, 0, 0);
				WriteFile(outHandle, codePageBuffer, charCount - 1, &written, 0);
				delete[] codePageBuffer;
			}
		}

		Nullable<WString> Console::TryRead()
		{
			CHECK_ERROR(IsEnabled(), L"vl::console::Console::TryRead()#Console operations are disabled.");
			auto inHandle = GetStdHandle(STD_INPUT_HANDLE);
			if (inHandle == INVALID_HANDLE_VALUE || inHandle == NULL)
			{
				return {};
			}

			WString result;
			DWORD fileMode = 0;
			if ((GetFileType(inHandle) & FILE_TYPE_CHAR) && GetConsoleMode(inHandle, &fileMode))
			{
				for (;;)
				{
					wchar_t buffer = 0;
					DWORD count = 0;
					if (!ReadConsole(inHandle, &buffer, 1, &count, 0) || count == 0)
					{
						return result.Length() == 0 ? Nullable<WString>() : Nullable<WString>(result);
					}

					if (buffer == L'\r')
					{
						if (!ReadConsole(inHandle, &buffer, 1, &count, 0) || count == 0)
						{
							return result;
						}
						break;
					}
					else if (buffer == L'\n')
					{
						break;
					}
					else
					{
						result = result + WString::FromChar(buffer);
					}
				}
				return result;
			}
			else
			{
				AString buffer;
				for (;;)
				{
					char c = 0;
					DWORD count = 0;
					if (!ReadFile(inHandle, &c, 1, &count, 0) || count == 0)
					{
						if (buffer.Length() == 0)
						{
							return {};
						}
						break;
					}

					if (c == '\n')
					{
						break;
					}
					else
					{
						buffer = buffer + AString::FromChar(c);
					}
				}

				if (buffer.Length() > 0 && buffer[buffer.Length() - 1] == '\r')
				{
					buffer = buffer.Left(buffer.Length() - 1);
				}
				int codePage = GetConsoleCP();
				if (codePage == 0)
				{
					codePage = CP_THREAD_ACP;
				}
				auto charCount = MultiByteToWideChar(codePage, 0, buffer.Buffer(), (int)buffer.Length(), nullptr, 0);
				auto wbuffer = new wchar_t[charCount + 1];
				MultiByteToWideChar(codePage, 0, buffer.Buffer(), (int)buffer.Length(), wbuffer, charCount);
				wbuffer[charCount] = 0;
				return WString::TakeOver(wbuffer, charCount);
			}
		}

		WString Console::Read()
		{
			auto result = TryRead();
			return result ? result.Value() : WString::Empty;
		}

		void Console::SetColor(bool red, bool green, bool blue, bool light)
		{
			CHECK_ERROR(IsEnabled(), L"vl::console::Console::SetColor(bool, bool, bool, bool)#Console operations are disabled.");
			WORD attribute = 0;
			if (red)attribute |= FOREGROUND_RED;
			if (green)attribute |= FOREGROUND_GREEN;
			if (blue)attribute |= FOREGROUND_BLUE;
			if (light)attribute |= FOREGROUND_INTENSITY;
			SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attribute);
			SetConsoleTextAttribute(GetStdHandle(STD_INPUT_HANDLE), attribute);
		}

		void Console::SetTitle(const WString& string)
		{
			CHECK_ERROR(IsEnabled(), L"vl::console::Console::SetTitle(const WString&)#Console operations are disabled.");
			SetConsoleTitle(string.Buffer());
		}
	}
}


/***********************************************************************
.\PRIMITIVES\DATETIME.WINDOWS.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/

#include <time.h>
#define _WINSOCKAPI_

#ifndef VCZH_MSVC
static_assert(false, "Do not build this file for non-Windows applications.");
#endif

namespace vl
{

/***********************************************************************
DateTime
***********************************************************************/

	class WindowsDateTimeImpl : public feature_injection::FeatureImpl<IDateTimeImpl>
	{
	public:

		static vuint64_t FileTimeToOSInternal(FILETIME fileTime)
		{
			ULARGE_INTEGER largeInteger;
			largeInteger.HighPart = fileTime.dwHighDateTime;
			largeInteger.LowPart = fileTime.dwLowDateTime;
			return largeInteger.QuadPart;
		}

		static FILETIME OSInternalToFileTime(vuint64_t osInternal)
		{
			ULARGE_INTEGER largeInteger;
			largeInteger.QuadPart = osInternal;

			FILETIME fileTime;
			fileTime.dwHighDateTime = largeInteger.HighPart;
			fileTime.dwLowDateTime = largeInteger.LowPart;
			return fileTime;
		}

		static DateTime SystemTimeToDateTime(const SYSTEMTIME& systemTime)
		{
			DateTime dateTime;
			dateTime.year = systemTime.wYear;
			dateTime.month = systemTime.wMonth;
			dateTime.dayOfWeek = systemTime.wDayOfWeek;
			dateTime.day = systemTime.wDay;
			dateTime.hour = systemTime.wHour;
			dateTime.minute = systemTime.wMinute;
			dateTime.second = systemTime.wSecond;
			dateTime.milliseconds = systemTime.wMilliseconds;

			FILETIME fileTime;
			SystemTimeToFileTime(&systemTime, &fileTime);
			dateTime.osInternal = FileTimeToOSInternal(fileTime);
			dateTime.osMilliseconds = dateTime.osInternal / 10000;

			return dateTime;
		}

		DateTime FromDateTime(vint _year, vint _month, vint _day, vint _hour, vint _minute, vint _second, vint _milliseconds) override
		{
			SYSTEMTIME systemTime;
			memset(&systemTime, 0, sizeof(systemTime));
			systemTime.wYear = (WORD)_year;
			systemTime.wMonth = (WORD)_month;
			systemTime.wDay = (WORD)_day;
			systemTime.wHour = (WORD)_hour;
			systemTime.wMinute = (WORD)_minute;
			systemTime.wSecond = (WORD)_second;
			systemTime.wMilliseconds = (WORD)_milliseconds;

			FILETIME fileTime;
			SystemTimeToFileTime(&systemTime, &fileTime);
			FileTimeToSystemTime(&fileTime, &systemTime);
			return SystemTimeToDateTime(systemTime);
		}

		DateTime FromOSInternal(vuint64_t osInternal) override
		{
			ULARGE_INTEGER largeInteger;
			largeInteger.QuadPart = osInternal;
			FILETIME fileTime;
			fileTime.dwHighDateTime = largeInteger.HighPart;
			fileTime.dwLowDateTime = largeInteger.LowPart;

			SYSTEMTIME systemTime;
			FileTimeToSystemTime(&fileTime, &systemTime);
			return SystemTimeToDateTime(systemTime);
		}

		vuint64_t LocalTime() override
		{
			SYSTEMTIME systemTime;
			GetLocalTime(&systemTime);

			FILETIME fileTime;
			SystemTimeToFileTime(&systemTime, &fileTime);
			return FileTimeToOSInternal(fileTime);
		}

		vuint64_t UtcTime() override
		{
			FILETIME fileTime;
			GetSystemTimeAsFileTime(&fileTime);
			return FileTimeToOSInternal(fileTime);
		}

		vuint64_t LocalToUtcTime(vuint64_t osInternal) override
		{
			FILETIME fileTime = OSInternalToFileTime(osInternal);
			SYSTEMTIME utcTime, localTime;
			FileTimeToSystemTime(&fileTime, &localTime);
			TzSpecificLocalTimeToSystemTime(NULL, &localTime, &utcTime);
			SystemTimeToFileTime(&utcTime, &fileTime);
			return FileTimeToOSInternal(fileTime);
		}

		vuint64_t UtcToLocalTime(vuint64_t osInternal) override
		{
			FILETIME fileTime = OSInternalToFileTime(osInternal);
			SYSTEMTIME utcTime, localTime;
			FileTimeToSystemTime(&fileTime, &utcTime);
			SystemTimeToTzSpecificLocalTime(NULL, &utcTime, &localTime);
			SystemTimeToFileTime(&localTime, &fileTime);
			return FileTimeToOSInternal(fileTime);
		}

		vuint64_t Forward(vuint64_t osInternal, vuint64_t milliseconds) override
		{
			return osInternal + milliseconds * 10000;
		}

		vuint64_t Backward(vuint64_t osInternal, vuint64_t milliseconds) override
		{
			return osInternal - milliseconds * 10000;
		}
	};

	IDateTimeImpl* GetOSDateTimeImpl()
	{
		static WindowsDateTimeImpl osDateTimeImpl;
		return &osDateTimeImpl;
	}
}


/***********************************************************************
.\STRINGS\CONVERSION.WINDOWS.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/

#define _WINSOCKAPI_

#ifndef VCZH_MSVC
static_assert(false, "Do not build this file for non-Windows applications.");
#endif

namespace vl
{
/***********************************************************************
String Conversions (buffer walkthrough)
***********************************************************************/

	vint _wtoa(const wchar_t* w, char* a, vint chars)
	{
		return WideCharToMultiByte(CP_THREAD_ACP, 0, w, -1, a, (int)(a ? chars : 0), 0, 0);
	}

	vint _atow(const char* a, wchar_t* w, vint chars)
	{
		return MultiByteToWideChar(CP_THREAD_ACP, 0, a, -1, w, (int)(w ? chars : 0));
	}
}


/***********************************************************************
.\UNITTEST\UNITTEST.WINDOWS.CPP
***********************************************************************/
/***********************************************************************
Author: Zihan Chen (vczh)
Licensed under https://github.com/vczh-libraries/License
***********************************************************************/

#define _WINSOCKAPI_

#ifndef VCZH_MSVC
static_assert(false, "Do not build this file for non-Windows applications.");
#endif

namespace vl
{
	namespace unittest
	{
/***********************************************************************
UnitTest
***********************************************************************/

		bool UnitTest::IsDebuggerAttached()
		{
			return IsDebuggerPresent();
		}
	}
}

