/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#if (defined(WIN32) || defined(_WIN32)) && !defined(_WIN32_WCE)

#include <apr_strings.h>

#include <log4cxx/nt/nteventlogappender.h>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/level.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/pool.h>

using namespace log4cxx;
using namespace log4cxx::spi;
using namespace log4cxx::helpers;
using namespace log4cxx::nt;

class CCtUserSIDHelper
{
	public:
		static bool FreeSid(SID* pSid)
		{
			return ::HeapFree(GetProcessHeap(), 0, (LPVOID)pSid) != 0;
		}

		static bool CopySid(SID * * ppDstSid, SID* pSrcSid)
		{
			bool bSuccess = false;

			DWORD dwLength = ::GetLengthSid(pSrcSid);
			*ppDstSid = (SID*) ::HeapAlloc(GetProcessHeap(),
					HEAP_ZERO_MEMORY, dwLength);

			if (::CopySid(dwLength, *ppDstSid, pSrcSid))
			{
				bSuccess = true;
			}
			else
			{
				FreeSid(*ppDstSid);
			}

			return bSuccess;
		}

		static bool GetCurrentUserSID(SID * * ppSid)
		{
			bool bSuccess = false;

			// Pseudohandle so don't need to close it
			HANDLE hProcess = ::GetCurrentProcess();
			HANDLE hToken = NULL;

			if (::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
			{
				// Get the required size
				DWORD tusize = 0;
				GetTokenInformation(hToken, TokenUser, NULL, 0, &tusize);
				TOKEN_USER* ptu = (TOKEN_USER*)new BYTE[tusize];

				if (GetTokenInformation(hToken, TokenUser, (LPVOID)ptu, tusize, &tusize))
				{
					bSuccess = CopySid(ppSid, (SID*)ptu->User.Sid);
				}

				CloseHandle(hToken);
				delete [] ptu;
			}

			return bSuccess;
		}
};

IMPLEMENT_LOG4CXX_OBJECT(NTEventLogAppender)

NTEventLogAppender::NTEventLogAppender() : hEventLog(NULL), pCurrentUserSID(NULL)
{
}

NTEventLogAppender::NTEventLogAppender(const LogString& server, const LogString& log, const LogString& source, const LayoutPtr& layout)
	: server(server), log(log), source(source), hEventLog(NULL), pCurrentUserSID(NULL)
{
	this->layout = layout;
	Pool pool;
	activateOptions(pool);
}

NTEventLogAppender::~NTEventLogAppender()
{
	finalize();
}


void NTEventLogAppender::close()
{
	if (hEventLog != NULL)
	{
		::DeregisterEventSource(hEventLog);
		hEventLog = NULL;
	}

	if (pCurrentUserSID != NULL)
	{
		CCtUserSIDHelper::FreeSid((::SID*) pCurrentUserSID);
		pCurrentUserSID = NULL;
	}
}

void NTEventLogAppender::setOption(const LogString& option, const LogString& value)
{
	if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SERVER"), LOG4CXX_STR("server")))
	{
		server = value;
	}
	else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOG"), LOG4CXX_STR("log")))
	{
		log = value;
	}
	else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("SOURCE"), LOG4CXX_STR("source")))
	{
		source = value;
	}
	else
	{
		AppenderSkeleton::setOption(option, value);
	}
}

void NTEventLogAppender::activateOptions(Pool&)
{
	if (source.empty())
	{
		LogLog::warn(
			((LogString) LOG4CXX_STR("Source option not set for appender ["))
			+ name + LOG4CXX_STR("]."));
		return;
	}

	if (log.empty())
	{
		log = LOG4CXX_STR("Application");
	}

	close();

	// current user security identifier
	CCtUserSIDHelper::GetCurrentUserSID((::SID**) &pCurrentUserSID);

	addRegistryInfo();

	LOG4CXX_ENCODE_WCHAR(wsource, source);
	LOG4CXX_ENCODE_WCHAR(wserver, server);
	hEventLog = ::RegisterEventSourceW(
			wserver.empty() ? NULL : wserver.c_str(),
			wsource.c_str());

	if (hEventLog == NULL)
	{
		LogString msg(LOG4CXX_STR("Cannot register NT EventLog -- server: '"));
		msg.append(server);
		msg.append(LOG4CXX_STR("' source: '"));
		msg.append(source);
		LogLog::error(msg);
		LogLog::error(getErrorString(LOG4CXX_STR("RegisterEventSource")));
	}
}

void NTEventLogAppender::append(const LoggingEventPtr& event, Pool& p)
{
	if (hEventLog == NULL)
	{
		LogLog::warn(LOG4CXX_STR("NT EventLog not opened."));
		return;
	}

	LogString oss;
	layout->format(oss, event, p);
	wchar_t* msgs = Transcoder::wencode(oss, p);
	BOOL bSuccess = ::ReportEventW(
			hEventLog,
			getEventType(event),
			getEventCategory(event),
			0x1000,
			pCurrentUserSID,
			1,
			0,
			(LPCWSTR*) &msgs,
			NULL);

	if (!bSuccess)
	{
		LogLog::error(getErrorString(LOG4CXX_STR("ReportEvent")));
	}
}

/*
 * Add this source with appropriate configuration keys to the registry.
 */
void NTEventLogAppender::addRegistryInfo()
{
	DWORD disposition = 0;
	::HKEY hkey = 0;
	LogString subkey(LOG4CXX_STR("SYSTEM\\CurrentControlSet\\Services\\EventLog\\"));
	subkey.append(log);
	subkey.append(1, (logchar) 0x5C /* '\\' */);
	subkey.append(source);
	LOG4CXX_ENCODE_WCHAR(wsubkey, subkey);

	long stat = RegCreateKeyExW(HKEY_LOCAL_MACHINE, wsubkey.c_str(), 0, NULL,
			REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL,
			&hkey, &disposition);

	if (stat == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY)
	{
		HMODULE hmodule = GetModuleHandleW(L"log4cxx");

		if (hmodule == NULL)
		{
			hmodule = GetModuleHandleW(0);
		}

		wchar_t modpath[_MAX_PATH];
		DWORD modlen = GetModuleFileNameW(hmodule, modpath, _MAX_PATH - 1);

		if (modlen > 0)
		{
			modpath[modlen] = 0;
			RegSetValueExW(hkey, L"EventMessageFile", 0, REG_SZ,
				(LPBYTE) modpath, wcslen(modpath) * sizeof(wchar_t));
			RegSetValueExW(hkey, L"CategoryMessageFile", 0, REG_SZ,
				(LPBYTE) modpath, wcslen(modpath) * sizeof(wchar_t));
			DWORD typesSupported = 7;
			DWORD categoryCount = 6;
			RegSetValueExW(hkey, L"TypesSupported", 0, REG_DWORD,
				(LPBYTE)&typesSupported, sizeof(DWORD));
			RegSetValueExW(hkey, L"CategoryCount", 0, REG_DWORD,
				(LPBYTE)&categoryCount, sizeof(DWORD));
		}
	}

	RegCloseKey(hkey);
	return;
}

WORD NTEventLogAppender::getEventType(const LoggingEventPtr& event)
{
	int priority = event->getLevel()->toInt();
	WORD type = EVENTLOG_SUCCESS;

	if (priority >= Level::INFO_INT)
	{
		type = EVENTLOG_INFORMATION_TYPE;

		if (priority >= Level::WARN_INT)
		{
			type = EVENTLOG_WARNING_TYPE;

			if (priority >= Level::ERROR_INT)
			{
				type = EVENTLOG_ERROR_TYPE;
			}
		}
	}

	return type;
}

WORD NTEventLogAppender::getEventCategory(const LoggingEventPtr& event)
{
	int priority = event->getLevel()->toInt();
	WORD category = 1;

	if (priority >= Level::DEBUG_INT)
	{
		category = 2;

		if (priority >= Level::INFO_INT)
		{
			category = 3;

			if (priority >= Level::WARN_INT)
			{
				category = 4;

				if (priority >= Level::ERROR_INT)
				{
					category = 5;

					if (priority >= Level::FATAL_INT)
					{
						category = 6;
					}
				}
			}
		}
	}

	return category;
}

LogString NTEventLogAppender::getErrorString(const LogString& function)
{
	Pool p;
	enum { MSGSIZE = 5000 };

	wchar_t* lpMsgBuf = (wchar_t*) p.palloc(MSGSIZE * sizeof(wchar_t));
	DWORD dw = GetLastError();

	FormatMessageW(
		FORMAT_MESSAGE_FROM_SYSTEM,
		NULL,
		dw,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		lpMsgBuf,
		MSGSIZE, NULL );

	LogString msg(function);
	msg.append(LOG4CXX_STR(" failed with error "));
	StringHelper::toString((size_t) dw, p, msg);
	msg.append(LOG4CXX_STR(": "));
	Transcoder::decode(lpMsgBuf, msg);

	return msg;
}

#endif // WIN32
