/*
 * 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/logstring.h>
#include <log4cxx/spi/loggerfactory.h>
#include <log4cxx/hierarchy.h>
#include <log4cxx/defaultloggerfactory.h>
#include <log4cxx/logger.h>
#include <log4cxx/spi/hierarchyeventlistener.h>
#include <log4cxx/level.h>
#include <algorithm>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/appender.h>
#include <log4cxx/logstring.h>
#include <log4cxx/helpers/stringhelper.h>
#if !defined(LOG4CXX)
	#define LOG4CXX 1
#endif
#include <log4cxx/spi/rootlogger.h>
#include <mutex>
#include "assert.h"


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


typedef std::map<LogString, LoggerPtr> LoggerMap;
typedef std::map<LogString, ProvisionNode> ProvisionNodeMap;

struct Hierarchy::HierarchyPrivate
{
	HierarchyPrivate()
		: configured(false)
		, emittedNoAppenderWarning(false)
		, emittedNoResourceBundleWarning(false)
		, thresholdInt(Level::ALL_INT)
	{
	}

	helpers::Pool pool;
	mutable std::recursive_mutex mutex;
	mutable std::mutex configuredMutex;
	bool configured;
	bool emittedNoAppenderWarning;
	bool emittedNoResourceBundleWarning;
	int thresholdInt;

	spi::HierarchyEventListenerList listeners;
	LoggerPtr root;
	LevelPtr threshold;
	LoggerMap loggers;
	ProvisionNodeMap provisionNodes;

	std::vector<AppenderPtr> allAppenders;
};

IMPLEMENT_LOG4CXX_OBJECT(Hierarchy)

Hierarchy::Hierarchy() :
	m_priv(std::make_unique<HierarchyPrivate>())
{
}

Hierarchy::~Hierarchy()
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
	for (auto& item : m_priv->loggers)
	{
		if (auto& pLogger = item.second)
		{
			pLogger->removeHierarchy();
			pLogger->removeAllAppenders();
		}
	}
	if (m_priv->root)
	{
		m_priv->root->removeHierarchy();
		m_priv->root->removeAllAppenders();
	}
}

void Hierarchy::addHierarchyEventListener(const spi::HierarchyEventListenerPtr& listener)
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);

	if (std::find(m_priv->listeners.begin(), m_priv->listeners.end(), listener) != m_priv->listeners.end())
	{
		LogLog::warn(LOG4CXX_STR("Ignoring attempt to add an existent listener."));
	}
	else
	{
		m_priv->listeners.push_back(listener);
	}
}

void Hierarchy::removeHierarchyEventListener(const spi::HierarchyEventListenerPtr& listener)
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);

    auto found = std::find(m_priv->listeners.begin(), m_priv->listeners.end(), listener);
    if(found != m_priv->listeners.end()){
        m_priv->listeners.erase(found);
    }
}

void Hierarchy::clear()
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
	m_priv->loggers.clear();
}

void Hierarchy::emitNoAppenderWarning(const Logger* logger)
{
	bool emitWarning = false;
	{
		std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
		emitWarning = !m_priv->emittedNoAppenderWarning;
		m_priv->emittedNoAppenderWarning = true;
	}

	// No appender in hierarchy, warn user only once.
	if (emitWarning)
	{
		LogLog::warn(((LogString) LOG4CXX_STR("No appender could be found for logger ("))
			+ logger->getName() + LOG4CXX_STR(")."));
		LogLog::warn(LOG4CXX_STR("Please initialize the log4cxx system properly."));
	}
}


LoggerPtr Hierarchy::exists(const LogString& name)
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);

	LoggerPtr logger;
	LoggerMap::iterator it = m_priv->loggers.find(name);

	if (it != m_priv->loggers.end())
	{
		logger = it->second;
	}


	return logger;
}

void Hierarchy::setThreshold(const LevelPtr& l)
{
	if (l != 0)
	{
		std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
		setThresholdInternal(l);
	}
}

void Hierarchy::setThreshold(const LogString& levelStr)
{
	LevelPtr l(Level::toLevelLS(levelStr, 0));

	if (l != 0)
	{
		setThreshold(l);
	}
	else
	{
		LogLog::warn(((LogString) LOG4CXX_STR("No level could be found named \""))
			+ levelStr + LOG4CXX_STR("\"."));
	}
}

void Hierarchy::setThresholdInternal(const LevelPtr& l)
{
	m_priv->thresholdInt = l->toInt();
	m_priv->threshold = l;

	if (m_priv->thresholdInt != Level::ALL_INT)
	{
		m_priv->configured = true;
	}
}

void Hierarchy::fireAddAppenderEvent(const Logger* logger, const Appender* appender)
{
	setConfigured(true);
	HierarchyEventListenerList clonedList;
	{
		std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
		clonedList = m_priv->listeners;
	}

	HierarchyEventListenerList::iterator it, itEnd = clonedList.end();
	HierarchyEventListenerPtr listener;

	for (it = clonedList.begin(); it != itEnd; it++)
	{
		listener = *it;
		listener->addAppenderEvent(logger, appender);
	}
}

void Hierarchy::fireRemoveAppenderEvent(const Logger* logger, const Appender* appender)

{
	HierarchyEventListenerList clonedList;
	{
		std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
		clonedList = m_priv->listeners;
	}
	HierarchyEventListenerList::iterator it, itEnd = clonedList.end();
	HierarchyEventListenerPtr listener;

	for (it = clonedList.begin(); it != itEnd; it++)
	{
		listener = *it;
		listener->removeAppenderEvent(logger, appender);
	}
}

LevelPtr Hierarchy::getThreshold() const
{
	return m_priv->threshold ? m_priv->threshold : Level::getAll();
}

LoggerPtr Hierarchy::getLogger(const LogString& name)
{
	static WideLife<spi::LoggerFactoryPtr> defaultFactory = std::make_shared<DefaultLoggerFactory>();
	return getLogger(name, defaultFactory);
}

LoggerPtr Hierarchy::getLogger(const LogString& name,
	const spi::LoggerFactoryPtr& factory)
{
	auto root = getRootLogger();
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);

	LoggerMap::iterator it = m_priv->loggers.find(name);
	LoggerPtr result;

	if (it != m_priv->loggers.end())
	{
		result = it->second;
	}
	if (!result && factory)
	{
		LoggerPtr logger(factory->makeNewLoggerInstance(m_priv->pool, name));
		logger->setHierarchy(this);
		m_priv->loggers.insert(LoggerMap::value_type(name, logger));

		ProvisionNodeMap::iterator it2 = m_priv->provisionNodes.find(name);

		if (it2 != m_priv->provisionNodes.end())
		{
			updateChildren(it2->second, logger);
			m_priv->provisionNodes.erase(it2);
		}

		updateParents(logger, root);
		result = logger;
	}
	return result;

}

LoggerList Hierarchy::getCurrentLoggers() const
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);

	LoggerList v;
	for (auto& item : m_priv->loggers)
	{
		if (auto pLogger = item.second)
			v.push_back(pLogger);
	}
	return v;
}

LoggerPtr Hierarchy::getRootLogger() const
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
	if (!m_priv->root)
	{
		m_priv->root = std::make_shared<RootLogger>(m_priv->pool, Level::getDebug());
		m_priv->root->setHierarchy(const_cast<Hierarchy*>(this));
	}

	return m_priv->root;
}

bool Hierarchy::isDisabled(int level) const
{
	return m_priv->thresholdInt > level;
}

void Hierarchy::ensureIsConfigured(std::function<void()> configurator)
{
	std::unique_lock<std::mutex> lock(m_priv->configuredMutex);
	if (!m_priv->configured)
	{
		configurator();
		m_priv->configured = true;
	}
}

void Hierarchy::resetConfiguration()
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);

	if (m_priv->root)
	{
		m_priv->root->setLevel(Level::getDebug());
		m_priv->root->setResourceBundle(0);
	}
	setThresholdInternal(Level::getAll());

	shutdownInternal();

	LoggerMap::const_iterator it, itEnd = m_priv->loggers.end();

	for (it = m_priv->loggers.begin(); it != itEnd; it++)
	{
		if (auto pLogger = it->second)
		{
			pLogger->setLevel(0);
			pLogger->setAdditivity(true);
			pLogger->setResourceBundle(0);
		}
	}

	//rendererMap.clear();
}

void Hierarchy::shutdown()
{
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);

	shutdownInternal();
}

void Hierarchy::shutdownInternal()
{
	m_priv->configured = false;

	// begin by closing nested appenders
	if (m_priv->root)
		m_priv->root->closeNestedAppenders();

	LoggerMap::iterator it, itEnd = m_priv->loggers.end();

	for (it = m_priv->loggers.begin(); it != itEnd; it++)
	{
		if (auto pLogger = it->second)
			pLogger->closeNestedAppenders();
	}

	// then, remove all appenders
	if (m_priv->root)
		m_priv->root->removeAllAppenders();

	for (it = m_priv->loggers.begin(); it != itEnd; it++)
	{
		if (auto pLogger = it->second)
			pLogger->removeAllAppenders();
	}
}

void Hierarchy::updateParents(const LoggerPtr& logger, const LoggerPtr& root)
{
	const LogString name(logger->getName());
	size_t length = name.size();
	bool parentFound = false;


	// if name = "w.x.y.z", loop through "w.x.y", "w.x" and "w", but not "w.x.y.z"
	for (size_t i = name.find_last_of(0x2E /* '.' */, length - 1);
		(i != LogString::npos) && (i != 0);
		i = name.find_last_of(0x2E /* '.' */, i - 1))
	{
		LogString substr = name.substr(0, i);

		LoggerMap::iterator it = m_priv->loggers.find(substr);

		if (it != m_priv->loggers.end())
		{
			parentFound = true;
			logger->setParent( it->second );
			break; // no need to update the ancestors of the closest ancestor
		}
		else
		{
			ProvisionNodeMap::iterator it2 = m_priv->provisionNodes.find(substr);

			if (it2 != m_priv->provisionNodes.end())
			{
				it2->second.push_back(logger);
			}
			else
			{
				ProvisionNode node(1, logger);
				m_priv->provisionNodes.insert(
					ProvisionNodeMap::value_type(substr, node));
			}
		}
	}

	// If we could not find any existing parents, then link with root.
	if (!parentFound)
	{
		logger->setParent( root );
	}
}

void Hierarchy::updateChildren(ProvisionNode& pn, const LoggerPtr& logger)
{
	ProvisionNode::iterator it, itEnd = pn.end();

	for (it = pn.begin(); it != itEnd; it++)
	{
		LoggerPtr& l = *it;

		// Unless this child already points to a correct (lower) parent,
		// make logger.parent point to l.parent and l.parent to logger.
		if (!StringHelper::startsWith(l->getParent()->getName(), logger->getName()))
		{
			logger->setParent( l->getParent() );
			l->setParent( logger );
		}
	}
    
}

void Hierarchy::updateChildren(const Logger* parent)
{
	for (auto& item : m_priv->loggers)
	{
		for (auto l = item.second; l; l = l->getParent())
		{
			if (l->getParent().get() == parent)
			{
				item.second->updateThreshold();
				break;
			}
		}
	}
}

void Hierarchy::setConfigured(bool newValue)
{
	std::unique_lock<std::mutex> lock(m_priv->configuredMutex, std::try_to_lock);
	if (lock.owns_lock()) // Not being auto-configured?
		m_priv->configured = newValue;
}

bool Hierarchy::isConfigured()
{
	std::unique_lock<std::mutex> lock(m_priv->configuredMutex); // Blocks while auto-configuration is active
	return m_priv->configured;
}

HierarchyPtr Hierarchy::create()
{
	HierarchyPtr ret(new Hierarchy);
	return ret;
}

void Hierarchy::clearAppenders()
{
	m_priv->allAppenders.clear();
}

void Hierarchy::addAppender(AppenderPtr appender)
{
	m_priv->allAppenders.push_back(appender);
}

bool Hierarchy::removeLogger(const LogString& name, bool ifNotUsed)
{
	auto parentRefCount = [this](const LoggerPtr& child) -> int
	{
		int result = 0;
		for (auto& node : m_priv->provisionNodes)
		{
			if (node.second.end() != std::find(node.second.begin(), node.second.end(), child))
				++result;
		}
		return result;
	};
	bool result = false;
	std::lock_guard<std::recursive_mutex> lock(m_priv->mutex);
	auto it = m_priv->loggers.find(name);
	if (it == m_priv->loggers.end())
		;
	else if (ifNotUsed && 1 + parentRefCount(it->second) < it->second.use_count())
		;
	else
	{
		for (auto& node : m_priv->provisionNodes)
		{
			for (size_t i = node.second.size(); 0 < i; )
			{
				if (node.second[--i] == it->second)
					node.second.erase(node.second.begin() + i);
			}
		}
		m_priv->loggers.erase(it);
		result = true;
	}
	return result;
}
