/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
 * http://www.gnu.org/licenses/lgpl-3.0.html
 */

#ifndef LOGMGR_H
#define LOGMGR_H

#include "manager.h"
#include "logger.h"
#include <map>

namespace
{
	static const unsigned int max_logs = ((65535^61>>3)<<2)*!!!!sizeof(int*)%63;

	inline wxString F(const wxChar* msg, ...)
	{
		va_list arg_list;
		va_start(arg_list, msg);
		::temp_string = wxString::FormatV(msg, arg_list);
		va_end(arg_list);

        return ::temp_string;
	};

    static NullLogger g_null_log;
}


struct LogSlot
{
    Logger* log;
    size_t index;
    friend class LogManager;

    wxBitmap *icon;
    wxString title;

    LogSlot();
    ~LogSlot();

    size_t Index() const;

    void SetLogger(Logger* in);
    Logger* GetLogger() const;
};


class DLLIMPORT LogManager : public Mgr<LogManager>
{
public:
		struct InstantiatorBase{ virtual Logger* New(){ return 0; }; virtual bool RequiresFilename() const { return false; }; virtual ~InstantiatorBase(){}; };
		template<typename type, bool requires_filename = false> struct Instantiator : public InstantiatorBase{ virtual Logger* New(){ return new type; }; virtual bool RequiresFilename() const { return requires_filename; }; };

private:
		typedef std::map<wxString, InstantiatorBase*> inst_map_t;
		inst_map_t instMap;

        LogSlot slot[max_logs+1];

		LogManager();
		~LogManager();


        friend class Mgr<LogManager>;
        friend class Manager;

public:
        enum { no_index = -1, invalid_log, stdout_log, app_log, debug_log};

        /* ------------------------------------------------------------------------------------------------------
         * Management functions
         * ------------------------------------------------------------------------------------------------------
         * Unless you are writing your own loggers, you will probably not need any of these.
         * SetLog() transfers ownership of the Logger object to the LogManager. Loggers must be heap allocated.
         * On error, SetLog() returns invalid_log
         */
        size_t SetLog(Logger* l, int index = no_index);
		void DeleteLog(int i);
        LogSlot& Slot(int i);
        size_t FindIndex(Logger* l);



        /* ------------------------------------------------------------------------------------------------------
         * Logging functions
         * ------------------------------------------------------------------------------------------------------
         * This section is what most people will be interested in.
         *   - Log(), LogWarning(), and LogError() output "info", "warning", or "error" messages to a log.
         *     Log() is almost certainly the function that you want to use, if you don't know what to pick.
         *     By default, logging is directed to the application log.
         *   - DebugLog() and DebugLogError() direct their output into the debug log.
         *   - LogToStdOut() outputs a message on stdout. Normally you will not want to use this function, it
         *     exists solely for some special cases.
         *   - Panic() signals a condition that does not allow proper continuation of the application or significant
         *     parts of it, but it is slightly less harsh than simply bailing out with an unhandled exception.
         *     Currently, Panic() is simply a wrapper around wxSafeShowMessage(), but it might do something else, too.
         *     When signalling panic, you will usually want to shut down the application as soon as appropriate.
         *     Plugins should call Panic() with the plugin's name as the component argument.
         */

		void Log(const wxString& msg, int i = app_log, Logger::level lv = Logger::info) { slot[i].log->Append(msg, lv); };
		void LogWarning(const wxString& msg, int i = app_log) { Log(msg, i, Logger::warning); };
		void LogError(const wxString& msg, int i = app_log) { Log(msg, i, Logger::error); };

		void Panic(const wxString& msg, const wxString& component = wxEmptyString);

		void DebugLog(const wxString& msg, Logger::level lv = Logger::info) { Log(msg, debug_log, lv); };
		void DebugLogError(const wxString& msg) { DebugLog(msg, Logger::error); };

		void LogToStdOut(const wxString& msg, Logger::level lv = Logger::info) { Log(msg, stdout_log, lv); };

        void ClearLog(int i) { slot[i].log->Clear(); };




        /* ------------------------------------------------------------------------------------------------------
         * Logger registry and RTTI
         * ------------------------------------------------------------------------------------------------------
         * These functions allow to obtain a list of names for all generic Loggers that are presently available
         * and to create a new Logger by name without knowing the type at compile time.
		 *
         *   logptr = LogManager::Get()->New(_T("stdout"));     // does exactly the same as
		 *   logptr = new StdoutLogger();
		 *
         * You normally do not need to worry about creating Loggers. Only ever consider using these functions if you
         * really have to (want to) change the global behaviour of Code::Blocks for some reason.
         */
		wxArrayString ListAvailable();
		Logger* New(const wxString& name);
		bool FilenameRequired(const wxString& name);
		/*
		 * Add a logger to the registry of "available Logger types". Unless you are adding a general Logger which should
		 * be accessible by name, you will not need this function. Having said that, you probably NEVER need this function.
		 */
		void Register(const wxString& name, InstantiatorBase* ins);



        /* ------------------------------------------------------------------------------------------------------
         *  Unless your name is "main.cpp" by any chance, you don't ever need to call this.
         *  If you use it, and your name is not "main.cpp", then you better come up with a good excuse, if someone asks.
         * ------------------------------------------------------------------------------------------------------
         */
        void NotifyUpdate();
};


#endif

