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

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

#include <iostream>
#include <string>

#ifndef VCZH_GCC
static_assert(false, "Do not build this file for 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.");
			std::wstring s(string, string + length);
			std::wcout << s << std::flush;
		}

		Nullable<WString> Console::TryRead()
		{
			CHECK_ERROR(IsEnabled(), L"vl::console::Console::TryRead()#Console operations are disabled.");
			std::wstring s;
			if (!std::getline(std::wcin, s, L'\n'))
			{
				if (s.empty())
				{
					return {};
				}
			}
			if (!s.empty() && s[s.size() - 1] == L'\r')
			{
				s.pop_back();
			}
			return WString::CopyFrom(s.c_str(), (vint)s.size());
		}

		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.");
			int color = (blue ? 1 : 0) * 4 + (green ? 1 : 0) * 2 + (red ? 1 : 0);
			if (light)
				wprintf(L"\x1B[00;3%dm", color);
			else
				wprintf(L"\x1B[01;3%dm", color);
		}

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


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

#include <time.h>
#include <memory.h>
#include <sys/time.h>

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

namespace vl
{

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

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

		static void TimeToOSInternal(time_t timer, vint milliseconds, vuint64_t& osInternal)
		{
			osInternal = (vuint64_t)timer * 1000 + milliseconds;
		}

		static void OSInternalToTime(vuint64_t osInternal, time_t& timer, vint& milliseconds)
		{
			timer = (time_t)(osInternal / 1000);
			milliseconds = (vint)(osInternal % 1000);
		}

		static vuint64_t ConvertTMTToOSInternal(tm* timeinfo, vint milliseconds)
		{
			time_t timer = mktime(timeinfo);
			vuint64_t osInternal;
			TimeToOSInternal(timer, milliseconds, osInternal);
			return osInternal;
		}

		static DateTime ConvertTMToDateTime(tm* timeinfo, vint milliseconds)
		{
			time_t timer = mktime(timeinfo);
			DateTime dt;
			dt.year = timeinfo->tm_year + 1900;
			dt.month = timeinfo->tm_mon + 1;
			dt.day = timeinfo->tm_mday;
			dt.dayOfWeek = timeinfo->tm_wday;
			dt.hour = timeinfo->tm_hour;
			dt.minute = timeinfo->tm_min;
			dt.second = timeinfo->tm_sec;
			dt.milliseconds = milliseconds;

			// in Linux and macOS, filetime will be mktime(t) * 1000 + gettimeofday().tv_usec / 1000
			TimeToOSInternal(timer, milliseconds, dt.osInternal);
			dt.osMilliseconds = dt.osInternal;
			return dt;
		}

		DateTime FromDateTime(vint _year, vint _month, vint _day, vint _hour, vint _minute, vint _second, vint _milliseconds) override
		{
			tm timeinfo;
			memset(&timeinfo, 0, sizeof(timeinfo));
			timeinfo.tm_year = _year - 1900;
			timeinfo.tm_mon = _month - 1;
			timeinfo.tm_mday = _day;
			timeinfo.tm_hour = _hour;
			timeinfo.tm_min = _minute;
			timeinfo.tm_sec = _second;
			timeinfo.tm_isdst = -1;
			return ConvertTMToDateTime(&timeinfo, _milliseconds);
		}

		DateTime FromOSInternal(vuint64_t osInternal) override
		{
			time_t timer;
			vint milliseconds;
			OSInternalToTime(osInternal, timer, milliseconds);

			tm timeinfo;
			localtime_r(&timer, &timeinfo);
			return ConvertTMToDateTime(&timeinfo, milliseconds);
		}

		vuint64_t LocalTime() override
		{
			struct timeval tv;
			gettimeofday(&tv, nullptr);
			tm timeinfo;
			localtime_r(&tv.tv_sec, &timeinfo);
			return ConvertTMTToOSInternal(&timeinfo, tv.tv_usec / 1000);
		}

		vuint64_t UtcTime() override
		{
			struct timeval tv;
			gettimeofday(&tv, nullptr);
			tm timeinfo;
			gmtime_r(&tv.tv_sec, &timeinfo);
			return ConvertTMTToOSInternal(&timeinfo, tv.tv_usec / 1000);
		}

		vuint64_t LocalToUtcTime(vuint64_t osInternal) override
		{
			time_t timer;
			vint milliseconds;
			OSInternalToTime(osInternal, timer, milliseconds);

			tm timeinfo;
			gmtime_r(&timer, &timeinfo);
			return ConvertTMTToOSInternal(&timeinfo, milliseconds);
		}

		vuint64_t UtcToLocalTime(vuint64_t osInternal) override
		{
			time_t timer;
			vint milliseconds;
			OSInternalToTime(osInternal, timer, milliseconds);

			tm localTimeInfo, utcTimeInfo;
			localtime_r(&timer, &localTimeInfo);
			gmtime_r(&timer, &utcTimeInfo);
			time_t localTimer = mktime(&localTimeInfo);
			time_t utcTimer = mktime(&utcTimeInfo);
			timer += localTimer - utcTimer;

			TimeToOSInternal(timer, milliseconds, osInternal);
			return osInternal;
		}

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

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

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


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

#include <stdio.h>
#include <ctype.h>
#include <wctype.h>

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

	vint _wtoa(const wchar_t* w, char* a, vint chars)
	{
		return wcstombs(a, w, chars - 1) + 1;
	}

	vint _atow(const char* a, wchar_t* w, vint chars)
	{
		return mbstowcs(w, a, chars - 1) + 1;
	}
}


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


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

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

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

