/*
 * Copyright 2009 Funambol, Inc.
 *
 * Licensed 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.
 */

/* $Id$ */

#pragma once

#include <cwchar>
#include <cstdarg>

#include "platform.h"
#include "commontypes.h"

#ifdef PLATFORM_LINUX
#define LOGGER_API
#elif defined(PLATFORM_WINDOWS)
#ifdef LOGGER_EXPORTS
#define LOGGER_API __declspec(dllexport)
#else
#define LOGGER_API __declspec(dllimport)
#endif // LOGGER_EXPORTS
#else
#define LOGGER_API
#endif

namespace NS_DM_Client
{
	namespace NS_Common
	{
		class CritSection;
		class IOutStream;
	}
}

namespace NS_Logging
{
	class IOutStream;

	// NS_Logging category, allows to make some Log-messages more important then others
	enum Category
	{
		e_criticalError = 0,
		e_error = 1,
		e_warning,
		e_info,
		e_debug,
		e_dump
	};

	class Logger
	{
		friend class LoggerFactory;
		friend struct FunctionNameLogHelper;

	public:
		Logger(const char* name);
		~Logger();

		bool IsEnabled() { return m_enabled; };

		void SetMinimalCategory(Category cat);
		void SetMaxMessageSize(size_t size);

		// logs error messages
		void Error(const char* format, ...);
		// logs regular info messages
		void Info(const char* format, ...);
		void Warning(const char* format, ...);
		// logs debug messages, this category is recommended for messages that is required only for deep diagnosis and usually is turned off by NS_Logging::SetMinimalCategory() */
		void Debug(const char* format, ...);
		// log with info category
		void Log(const char* format, ...);

	private:
		void enable(NS_DM_Client::NS_Common::IOutStream* stream, NS_DM_Client::NS_Common::CritSection& critSection);
		void log(Category category, char const* functionName, char const* format, va_list va);

	private:
		long volatile m_minimalCategory; // long instead of Category for interlocked exchange
		long volatile m_bufSize;
		NS_DM_Client::NS_Common::IOutStream* m_ostream;
		bool m_enabled;
		String m_name;
		NS_DM_Client::NS_Common::CritSection* m_critSection;
	};

	// get logger by name. If logger doesn't exist - create it
	LOGGER_API Logger& GetLogger(const char* name);
	void ReleaseLoggers();

 	// trick to be able to implement LOG macro that logs function name and accepts "ellipsis" parameters
	struct LOGGER_API FunctionNameLogHelper
	{
		FunctionNameLogHelper(const char* funcName, Category cat);
		void Log(Logger& logger, char const* format, ...);

	private:
		char const* m_funcName;
		Category m_category;
	};
}

// following macros allows automatic logging of function's name where logging is occurred */
#define LOG_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_info).Log
#define LOG_ERROR_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_error).Log
#define LOG_WARNING_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_warning).Log
#define LOG_DEBUG_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_debug).Log
#define LOG_INFO_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_info).Log
#define LOG_DUMP_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_dump).Log
#define LOG_CRITICAL_ NS_Logging::FunctionNameLogHelper(__FUNCTION__, NS_Logging::e_criticalError).Log

