/*
 * 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.
 */

#include <log4cxx/logger.h>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/logmanager.h>
#include <log4cxx/appender.h>
#include <log4cxx/level.h>
#include <log4cxx/hierarchy.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/appenderattachableimpl.h>
#include <log4cxx/helpers/exception.h>
#if !defined(LOG4CXX)
	#define LOG4CXX 1
#endif
#include <log4cxx/private/log4cxx_private.h>
#include <log4cxx/helpers/aprinitializer.h>

using namespace LOG4CXX_NS;
using namespace LOG4CXX_NS::helpers;
using namespace LOG4CXX_NS::spi;

struct Logger::LoggerPrivate
{
	LoggerPrivate(const LogString& name1)
		: name(name1)
		, repositoryRaw(0)
		, additive(true)
		, levelData(Level::getData())
		{}

	/**
	The name of this logger.
	*/
	LogString name;

	/**
	The assigned level of this logger.  The
	<code>level</code> variable need not be assigned a value in
	which case it is inherited form the hierarchy.  */
	LevelPtr level;

	/**
	The parent of this logger. All loggers have at least one
	ancestor which is the root logger. */
	LoggerPtr parent;

	/** The resourceBundle for localized messages.

	@see setResourceBundle, getResourceBundle
	*/
	helpers::ResourceBundlePtr resourceBundle;


	// Loggers need to know what Hierarchy they are in
	spi::LoggerRepository* repositoryRaw;

	helpers::AppenderAttachableImpl aai;

	/** Additivity is set to true by default, that is children inherit
	        the appenders of their ancestors by default. If this variable is
	        set to <code>false</code> then the appenders found in the
	        ancestors of this logger are not used. However, the children
	        of this logger will inherit its appenders, unless the children
	        have their additivity flag set to <code>false</code> too. See
	        the user manual for more details. */
	bool additive;

	Level::DataPtr levelData;
};

IMPLEMENT_LOG4CXX_OBJECT(Logger)

Logger::Logger(const LogString& name1)
	: m_priv(std::make_unique<LoggerPrivate>(name1))
	, m_threshold(0)
{
}

#if LOG4CXX_ABI_VERSION <= 15
Logger::Logger(Pool& p, const LogString& name)
	: Logger(name)
{
}
#endif

Logger::~Logger()
{
}

void Logger::addAppender(const AppenderPtr newAppender)
{
	m_priv->aai.addAppender(newAppender);
	if (auto rep = getHierarchy())
	{
		rep->fireAddAppenderEvent(this, newAppender.get());
	}
}

void Logger::reconfigure( const std::vector<AppenderPtr>& appenders, bool additive1 )
{
	m_priv->additive = additive1;

	m_priv->aai.removeAllAppenders();

	for (auto const& item : appenders)
	{
		m_priv->aai.addAppender(item);

		if (auto rep = getHierarchy())
		{
			rep->fireAddAppenderEvent(this, item.get());
		}
	}
}

void Logger::callAppenders(const spi::LoggingEventPtr& event, Pool& p) const
{
	int writes = 0;

	for (const Logger* logger = this;
		logger != 0;
		logger = logger->m_priv->parent.get())
	{
		writes += logger->m_priv->aai.appendLoopOnAppenders(event, p);

		if (!logger->m_priv->additive)
		{
			break;
		}
	}

	auto rep = getHierarchy();

	if (writes == 0 && rep)
	{
		rep->emitNoAppenderWarning(this);
	}
}

void Logger::closeNestedAppenders()
{
	for (auto& item : getAllAppenders())
	{
		item->close();
	}
}

void Logger::addEvent(const LevelPtr& level, std::string&& message, const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
#if LOG4CXX_LOGCHAR_IS_UTF8
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(message));
#else
	LOG4CXX_DECODE_CHAR(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(msg));
#endif
	Pool p;
	callAppenders(event, p);
}

void Logger::addFatalEvent(std::string&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Fatal, std::move(message), location);
}

void Logger::addErrorEvent(std::string&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Error, std::move(message), location);
}

void Logger::addWarnEvent(std::string&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Warn, std::move(message), location);
}

void Logger::addInfoEvent(std::string&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Info, std::move(message), location);
}

void Logger::addDebugEvent(std::string&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Debug, std::move(message), location);
}

void Logger::addTraceEvent(std::string&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Trace, std::move(message), location);
}

void Logger::forcedLog(const LevelPtr& level, const std::string& message,
	const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
#if LOG4CXX_LOGCHAR_IS_UTF8
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, message, location);
#else
	LOG4CXX_DECODE_CHAR(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(msg));
#endif
	Pool p;
	callAppenders(event, p);
}

void Logger::forcedLog(const LevelPtr& level1, const std::string& message) const
{
	forcedLog(level1, message, LocationInfo::getLocationUnavailable());
}

void Logger::addEventLS(const LevelPtr& level, LogString&& message, const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(message));
	Pool p;
	callAppenders(event, p);
}

void Logger::forcedLogLS(const LevelPtr& level1, const LogString& message,
	const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, message, location);
	Pool p;
	callAppenders(event, p);
}


bool Logger::getAdditivity() const
{
	return m_priv->additive;
}

AppenderList Logger::getAllAppenders() const
{
	return m_priv->aai.getAllAppenders();
}

AppenderPtr Logger::getAppender(const LogString& name1) const
{
	return m_priv->aai.getAppender(name1);
}

const LevelPtr& Logger::getEffectiveLevel() const
{
	for (const Logger* l = this; l != 0; l = l->m_priv->parent.get())
	{
		if (l->m_priv->level != 0)
		{
			return l->m_priv->level;
		}
	}

	throw NullPointerException(LOG4CXX_STR("No level specified for logger or ancestors."));
#if LOG4CXX_RETURN_AFTER_THROW
	return m_priv->level;
#endif
}

LoggerRepository* Logger::getLoggerRepository() const
{
	return m_priv->repositoryRaw;
}

LoggerRepository* Logger::getHierarchy() const
{
	return m_priv->repositoryRaw;
}

ResourceBundlePtr Logger::getResourceBundle() const
{
	for (const Logger* l = this; l != 0; l = l->m_priv->parent.get())
	{
		if (l->m_priv->resourceBundle != 0)
		{
			return l->m_priv->resourceBundle;
		}
	}

	// It might be the case that there is no resource bundle
	return 0;
}


LogString Logger::getResourceBundleString(const LogString& key) const
{
	ResourceBundlePtr rb = getResourceBundle();

	// This is one of the rare cases where we can use logging in order
	// to report errors from within log4j.
	if (rb == 0)
	{
		return LogString();
	}
	else
	{
		try
		{
			return rb->getString(key);
		}
		catch (MissingResourceException&)
		{
			logLS(Level::getError(), LOG4CXX_STR("No resource is associated with key \"") +
				key + LOG4CXX_STR("\"."), LocationInfo::getLocationUnavailable());

			return LogString();
		}
	}
}


LoggerPtr Logger::getParent() const
{
	return m_priv->parent;
}

const LevelPtr& Logger::getLevel() const
{
	return m_priv->level;
}

bool Logger::isAttached(const AppenderPtr appender) const
{
	return m_priv->aai.isAttached(appender);
}

bool Logger::isTraceEnabled() const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(Level::TRACE_INT))
	{
		return false;
	}

	return getEffectiveLevel()->toInt() <= Level::TRACE_INT;
}

bool Logger::isDebugEnabled() const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(Level::DEBUG_INT))
	{
		return false;
	}

	return getEffectiveLevel()->toInt() <= Level::DEBUG_INT;
}

bool Logger::isEnabledFor(const LevelPtr& level1) const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(level1->toInt()))
	{
		return false;
	}

	return level1->isGreaterOrEqual(getEffectiveLevel());
}


bool Logger::isInfoEnabled() const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(Level::INFO_INT))
	{
		return false;
	}

	return getEffectiveLevel()->toInt() <= Level::INFO_INT;
}

bool Logger::isErrorEnabled() const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(Level::ERROR_INT))
	{
		return false;
	}

	return getEffectiveLevel()->toInt() <= Level::ERROR_INT;
}

bool Logger::isWarnEnabled() const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(Level::WARN_INT))
	{
		return false;
	}

	return getEffectiveLevel()->toInt() <= Level::WARN_INT;
}

bool Logger::isFatalEnabled() const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(Level::FATAL_INT))
	{
		return false;
	}

	return getEffectiveLevel()->toInt() <= Level::FATAL_INT;
}

/*void Logger::l7dlog(const LevelPtr& level, const String& key,
                        const char* file, int line)
{
	auto rep = getHierarchy();

        if (!rep || rep->isDisabled(level->level))
        {
                return;
        }

        if (level->isGreaterOrEqual(getEffectiveLevel()))
        {
                String msg = getResourceBundleString(key);

                // if message corresponding to 'key' could not be found in the
                // resource bundle, then default to 'key'.
                if (msg.empty())
                {
                        msg = key;
                }

                forcedLog(FQCN, level, msg, file, line);
        }
}*/



void Logger::l7dlog(const LevelPtr& level1, const LogString& key,
	const LocationInfo& location, const std::vector<LogString>& params) const
{
	auto rep = getHierarchy();

	if (!rep || rep->isDisabled(level1->toInt()))
	{
		return;
	}

	if (level1->isGreaterOrEqual(getEffectiveLevel()))
	{
		LogString pattern = getResourceBundleString(key);
		LogString msg;

		if (pattern.empty())
		{
			msg = key;
		}
		else
		{
			msg = StringHelper::format(pattern, params);
		}

		addEventLS(level1, std::move(msg), location);
	}
}

void Logger::l7dlog(const LevelPtr& level1, const std::string& key,
	const LocationInfo& location) const
{
	LOG4CXX_DECODE_CHAR(lkey, key);

	std::vector<LogString> values(0);
	l7dlog(level1, lkey, location, values);
}

void Logger::l7dlog(const LevelPtr& level1, const std::string& key,
	const LocationInfo& location, const std::string& val1) const
{
	LOG4CXX_DECODE_CHAR(lkey, key);
	LOG4CXX_DECODE_CHAR(lval1, val1);

	std::vector<LogString> values(1);
	values[0] = lval1;
	l7dlog(level1, lkey, location, values);
}

void Logger::l7dlog(const LevelPtr& level1, const std::string& key,
	const LocationInfo& location,
	const std::string& val1, const std::string& val2) const
{
	LOG4CXX_DECODE_CHAR(lkey, key);
	LOG4CXX_DECODE_CHAR(lval1, val1);
	LOG4CXX_DECODE_CHAR(lval2, val2);

	std::vector<LogString> values(2);
	values[0] = lval1;
	values[1] = lval2;
	l7dlog(level1, lkey, location, values);
}

void Logger::l7dlog(const LevelPtr& level1, const std::string& key,
	const LocationInfo& location,
	const std::string& val1, const std::string& val2, const std::string& val3) const
{
	LOG4CXX_DECODE_CHAR(lkey, key);
	LOG4CXX_DECODE_CHAR(lval1, val1);
	LOG4CXX_DECODE_CHAR(lval2, val2);
	LOG4CXX_DECODE_CHAR(lval3, val3);

	std::vector<LogString> values(3);
	values[0] = lval1;
	values[1] = lval2;
	values[2] = lval3;
	l7dlog(level1, lkey, location, values);
}

void Logger::removeAllAppenders()
{
	AppenderList currentAppenders = m_priv->aai.getAllAppenders();
	m_priv->aai.removeAllAppenders();

	auto rep = getHierarchy();
	if(rep){
		for(AppenderPtr appender : currentAppenders){
			rep->fireRemoveAppenderEvent(this, appender.get());
		}
	}
}

void Logger::removeAppender(const AppenderPtr appender)
{
	m_priv->aai.removeAppender(appender);
	if (auto rep = getHierarchy())
	{
		rep->fireRemoveAppenderEvent(this, appender.get());
	}
}

void Logger::removeAppender(const LogString& name1)
{
	AppenderPtr appender = m_priv->aai.getAppender(name1);
	if(appender){
		removeAppender(appender);
	}
}

void Logger::removeHierarchy()
{
	m_priv->repositoryRaw = 0;
}

void Logger::setAdditivity(bool additive1)
{
	m_priv->additive = additive1;
}

void Logger::setHierarchy(spi::LoggerRepository* repository1)
{
	m_priv->repositoryRaw = repository1;
}

void Logger::setParent(LoggerPtr parentLogger)
{
	m_priv->parent = parentLogger;
	updateThreshold();
}

void Logger::setLevel(const LevelPtr level1)
{
	if (m_priv->level != level1)
	{
		m_priv->level = level1;
		updateThreshold();
		if (auto rep = dynamic_cast<Hierarchy*>(getHierarchy()))
			rep->updateChildren(this);
	}
}

void Logger::updateThreshold()
{
	m_threshold = getEffectiveLevel()->toInt();
}

const LogString& Logger::getName() const
{
	return m_priv->name;
}

LoggerPtr Logger::getLogger(const std::string& name)
{
	return LogManager::getLogger(name);
}


LoggerPtr Logger::getLogger(const char* const name)
{
	return LogManager::getLogger(name);
}

void Logger::setResourceBundle(const helpers::ResourceBundlePtr& bundle)
{
	m_priv->resourceBundle = bundle;
}

LoggerPtr Logger::getRootLogger()
{
	return LogManager::getRootLogger();
}

LoggerPtr Logger::getLoggerLS(const LogString& name,
	const spi::LoggerFactoryPtr& factory)
{
	return LogManager::getLoggerLS(name, factory);
}

void Logger::getName(std::string& rv) const
{
	Transcoder::encode(m_priv->name, rv);
}


void Logger::trace(const std::string& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg, location);
	}
}


void Logger::trace(const std::string& msg) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg);
	}
}

void Logger::debug(const std::string& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg, location);
	}
}

void Logger::debug(const std::string& msg) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg);
	}
}


void Logger::error(const std::string& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg, location);
	}
}


void Logger::error(const std::string& msg) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg);
	}
}

void Logger::fatal(const std::string& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg, location);
	}
}

void Logger::fatal(const std::string& msg) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg);
	}
}

void Logger::info(const std::string& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg, location);
	}
}

void Logger::info(const std::string& msg) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg);
	}
}

void Logger::log(const LevelPtr& level1, const std::string& message,
	const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message, location);
	}
}

void Logger::log(const LevelPtr& level1, const std::string& message) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message);
	}
}

void Logger::logLS(const LevelPtr& level1, const LogString& message,
	const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isEnabledFor(level1))
	{
		forcedLogLS(level1, message, location);
	}
}

void Logger::warn(const std::string& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg, location);
	}
}

void Logger::warn(const std::string& msg) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg);
	}
}

LoggerPtr Logger::getLoggerLS(const LogString& name)
{
	return LogManager::getLoggerLS(name);
}




#if LOG4CXX_WCHAR_T_API
void Logger::addEvent(const LevelPtr& level, std::wstring&& message, const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
#if LOG4CXX_LOGCHAR_IS_WCHAR
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(message));
#else
	LOG4CXX_DECODE_WCHAR(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(msg));
#endif
	Pool p;
	callAppenders(event, p);
}

void Logger::addFatalEvent(std::wstring&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Fatal, std::move(message), location);
}

void Logger::addErrorEvent(std::wstring&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Error, std::move(message), location);
}

void Logger::addWarnEvent(std::wstring&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Warn, std::move(message), location);
}

void Logger::addInfoEvent(std::wstring&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Info, std::move(message), location);
}

void Logger::addDebugEvent(std::wstring&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Debug, std::move(message), location);
}

void Logger::addTraceEvent(std::wstring&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Trace, std::move(message), location);
}

void Logger::forcedLog(const LevelPtr& level, const std::wstring& message,
	const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
#if LOG4CXX_LOGCHAR_IS_WCHAR
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, message, location);
#else
	LOG4CXX_DECODE_WCHAR(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(msg));
#endif
	Pool p;
	callAppenders(event, p);
}

void Logger::forcedLog(const LevelPtr& level1, const std::wstring& message) const
{
	forcedLog(level1, message, LocationInfo::getLocationUnavailable());
}

void Logger::getName(std::wstring& rv) const
{
	Transcoder::encode(m_priv->name, rv);
}

LoggerPtr Logger::getLogger(const std::wstring& name)
{
	return LogManager::getLogger(name);
}

LoggerPtr Logger::getLogger(const wchar_t* const name)
{
	return LogManager::getLogger(name);
}

void Logger::trace(const std::wstring& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg, location);
	}
}


void Logger::trace(const std::wstring& msg) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg);
	}
}

void Logger::debug(const std::wstring& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg, location);
	}
}

void Logger::debug(const std::wstring& msg) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg);
	}
}

void Logger::error(const std::wstring& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg, location);
	}
}

void Logger::error(const std::wstring& msg) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg);
	}
}

void Logger::fatal(const std::wstring& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg, location);
	}
}

void Logger::fatal(const std::wstring& msg) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg);
	}
}

void Logger::info(const std::wstring& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg, location);
	}
}

void Logger::info(const std::wstring& msg) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg);
	}
}

void Logger::log(const LevelPtr& level1, const std::wstring& message,
	const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message, location);
	}
}

void Logger::log(const LevelPtr& level1, const std::wstring& message) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message);
	}
}

void Logger::warn(const std::wstring& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg, location);
	}
}

void Logger::warn(const std::wstring& msg) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg);
	}
}

#endif


#if LOG4CXX_UNICHAR_API
void Logger::addEvent(const LevelPtr& level1, std::basic_string<UniChar>&& message,	const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
	LOG4CXX_DECODE_UNICHAR(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, location, std::move(msg));
	Pool p;
	callAppenders(event, p);
}

void Logger::addFatalEvent(std::basic_string<UniChar>&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Fatal, std::move(message), location);
}

void Logger::addErrorEvent(std::basic_string<UniChar>&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Error, std::move(message), location);
}

void Logger::addWarnEvent(std::basic_string<UniChar>&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Warn, std::move(message), location);
}

void Logger::addInfoEvent(std::basic_string<UniChar>&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Info, std::move(message), location);
}

void Logger::addDebugEvent(std::basic_string<UniChar>&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Debug, std::move(message), location);
}

void Logger::addTraceEvent(std::basic_string<UniChar>&& message, const LocationInfo& location) const
{
	addEvent(m_priv->levelData->Trace, std::move(message), location);
}

void Logger::forcedLog(const LevelPtr& level1, const std::basic_string<UniChar>& message,
	const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
	LOG4CXX_DECODE_UNICHAR(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, location, std::move(msg));
	Pool p;
	callAppenders(event, p);
}

void Logger::forcedLog(const LevelPtr& level1, const std::basic_string<UniChar>& message) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
	LOG4CXX_DECODE_UNICHAR(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level1, msg,
			LocationInfo::getLocationUnavailable());
	Pool p;
	callAppenders(event, p);
}

void Logger::getName(std::basic_string<UniChar>& rv) const
{
	Transcoder::encode(m_priv->name, rv);
}

LoggerPtr Logger::getLogger(const std::basic_string<UniChar>& name)
{
	return LogManager::getLogger(name);
}

void Logger::trace(const std::basic_string<UniChar>& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg, location);
	}
}


void Logger::trace(const std::basic_string<UniChar>& msg) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg);
	}
}

void Logger::debug(const std::basic_string<UniChar>& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg, location);
	}
}

void Logger::debug(const std::basic_string<UniChar>& msg) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg);
	}
}

void Logger::error(const std::basic_string<UniChar>& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg, location);
	}
}

void Logger::error(const std::basic_string<UniChar>& msg) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg);
	}
}

void Logger::fatal(const std::basic_string<UniChar>& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg, location);
	}
}

void Logger::fatal(const std::basic_string<UniChar>& msg) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg);
	}
}

void Logger::info(const std::basic_string<UniChar>& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg, location);
	}
}

void Logger::info(const std::basic_string<UniChar>& msg) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg);
	}
}

void Logger::log(const LevelPtr& level1, const std::basic_string<UniChar>& message,
	const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message, location);
	}
}

void Logger::log(const LevelPtr& level1, const std::basic_string<UniChar>& message) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message);
	}
}

void Logger::warn(const std::basic_string<UniChar>& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg, location);
	}
}

void Logger::warn(const std::basic_string<UniChar>& msg) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg);
	}
}

#endif


#if LOG4CXX_CFSTRING_API
void Logger::forcedLog(const LevelPtr& level, const CFStringRef& message,
	const LocationInfo& location) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
	LOG4CXX_DECODE_CFSTRING(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, location, std::move(msg));
	Pool p;
	callAppenders(event, p);
}

void Logger::forcedLog(const LevelPtr& level, const CFStringRef& message) const
{
	if (!getHierarchy()) // Has removeHierarchy() been called?
		return;
	LOG4CXX_DECODE_CFSTRING(msg, message);
	auto event = std::make_shared<LoggingEvent>(m_priv->name, level, msg,
			LocationInfo::getLocationUnavailable());
	Pool p;
	callAppenders(event, p);
}

void Logger::getName(CFStringRef& rv) const
{
	rv = Transcoder::encode(m_priv->name);
}

LoggerPtr Logger::getLogger(const CFStringRef& name)
{
	return LogManager::getLogger(name);
}

void Logger::trace(const CFStringRef& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg, location);
	}
}


void Logger::trace(const CFStringRef& msg) const
{
	if (isTraceEnabled())
	{
		forcedLog(m_priv->levelData->Trace, msg);
	}
}

void Logger::debug(const CFStringRef& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg, location);
	}
}

void Logger::debug(const CFStringRef& msg) const
{
	if (isDebugEnabled())
	{
		forcedLog(m_priv->levelData->Debug, msg);
	}
}

void Logger::error(const CFStringRef& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg, location);
	}
}

void Logger::error(const CFStringRef& msg) const
{
	if (isErrorEnabled())
	{
		forcedLog(m_priv->levelData->Error, msg);
	}
}

void Logger::fatal(const CFStringRef& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg, location);
	}
}

void Logger::fatal(const CFStringRef& msg) const
{
	if (isFatalEnabled())
	{
		forcedLog(m_priv->levelData->Fatal, msg);
	}
}

void Logger::info(const CFStringRef& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg, location);
	}
}

void Logger::info(const CFStringRef& msg) const
{
	if (isInfoEnabled())
	{
		forcedLog(m_priv->levelData->Info, msg);
	}
}

void Logger::log(const LevelPtr& level1, const CFStringRef& message,
	const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message, location);
	}
}

void Logger::log(const LevelPtr& level1, const CFStringRef& message) const
{
	if (isEnabledFor(level1))
	{
		forcedLog(level1, message);
	}
}

void Logger::warn(const CFStringRef& msg, const LOG4CXX_NS::spi::LocationInfo& location) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg, location);
	}
}

void Logger::warn(const CFStringRef& msg) const
{
	if (isWarnEnabled())
	{
		forcedLog(m_priv->levelData->Warn, msg);
	}
}

#endif


