/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework Core Library
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#ifndef __IWEAR_DEBUGMANAGER_H
#define __IWEAR_DEBUGMANAGER_H

#ifndef __IWEAR_DEBUGMODULECONSOLE_H
#include <iwear/debugmoduleconsole.h>
#endif

#ifndef __IWEAR_DEBUG_ENUM_H
#include <iwear/debug_enum.h>
#endif

#ifndef __IWEAR_EXCEPTIONS_H
#include <iwear/exceptions.h>
#endif

#ifndef __IWEAR_THREAD_H
#include <iwear/thread.h>
#endif

#ifndef __IWEAR_DEBUGAREA_H
#include <iwear/debugarea.h>
#endif

extern "C" {
#include <stdarg.h>
}

#include <set>
#include <map>
using std::set;

namespace iwear
{

/**
 * The debugmanager manages a set of output modules for debugging streams.
 * Currently known are the console and logfile modules, which can be attached,
 * so everything logged goes to them.
 */
class debugmanager/*{{{*/
{
private:
   /**
    * The Set of modules this manager knows. Debugging messages will be passed
    * to all of them
    */
    set<debugmodule*> DbgMods;

   /**
    * The current debuglevel this manager is in. Everything above this level
    * will not be passed to the modules.
    */
//    debuglevel current_level;

    /**
     * specifies if we should check the actual level value or bitfields
     */
    debugleveltype lvltype;

    bool check_level( debuglevel dlev );
protected:
public:
   /**
    * We have a static default manager, that the default debugstreams are
    * connected to.
    */
    static debugmanager DebugManager;

   /**
    * This is the static default module connected to the static default
    * manager. So everything goes per default to the screen.
    */
    static debugmoduleconsole DefaultModule;

   /**
    * We do not need anything special to construct the manager.
    */
    debugmanager( );

   /**
    * Attaches a module to the manager. Everything from then beeing passed to
    * the manager will also be logged to this module.
    */
    bool attach( debugmodule* );

   /**
    * Detaches a module from the manager. From then on, everything will only be
    * passed to the remaining modules.
    */
    bool detach( debugmodule* );

   /**
    * Logs a c-string message.
    */
    int log( debuglevel dlev, const char * );

   /**
    * Logs a format string and a list of arguments for it. Similar to vsprintf.
    */
    int log( debuglevel dlev, const char *, va_list&  );

   /**
    * Sets the current debuglevel for the manager.
    */
    void set_debuglevel( debuglevel dblev );

    void set_debuglevel( debuglevel dblev, const debugarea& );

    inline void set_levelmode( debugleveltype nl ) { lvltype = nl; }

   /**
    * Gets the current set debuglevel.
    */
    inline debuglevel get_debuglevel( void ) const { 
	std::map<pthread_t,int>::const_iterator at = area_of_thread.find(Thread::self_id());
	if( at != area_of_thread.end() )
	{
	    std::map<int,debuglevel>::const_iterator ci = current_levels.find(at->second);
	    if( ci != current_levels.end() )
	    {
		return ci->second;
	    }
	}
	return error;
    }

    std::map<pthread_t,int> area_of_thread;

    std::map<int,debuglevel> current_levels;

    void set_debugarea( int a, pthread_t t = Thread::self_id() );
};/*}}}*/

// Sets the currently valid area for the thread we are in
inline void debugmanager::set_debugarea( int a, pthread_t t)
{
    area_of_thread[t] = a;
    //XXX flush previous buffers if needed
}

inline bool debugmanager::attach( debugmodule* newmod )/*{{{*/
{
    DbgMods.insert(newmod);
    return true;
}/*}}}*/

inline bool debugmanager::detach( debugmodule* rmmod )/*{{{*/
{
    DbgMods.erase(rmmod);
    return true;
}/*}}}*/

inline void debugmanager::set_debuglevel( debuglevel dblev ) 
{
    set_debuglevel( dblev, debugarea(0) );
}

}
#endif
