/*!
  @header ECLogging
  @abstract Module of Encore
 
  @availability OS X, GNUstep
  @copyright 2004, 2005, 2006 Oliver Langer

  Author: Oliver Langer

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA

  <pre>
  -------------------------------------------------------------------------
  Modification history

  16.01.06 ola     initial version
  22.08.06 ola     license changed
  -------------------------------------------------------------------------
  </pre>
*/

#if !defined(__ECLogging_H)
#define __ECLogging_H

#include <Foundation/Foundation.h>
#include <Encore/ECObject.h>

/*!
 * @typedef ECLoggingLevel
 * @discussion defines all available logging levels in their corresponding
 * order.
 */
typedef enum {
  LOGLEVEL_UNKNOWN,
  LOGLEVEL_DEBUG,
  LOGLEVEL_TRACE,
  LOGLEVEL_INFO,
  LOGLEVEL_WARN,
  LOGLEVEL_ERROR,
  LOGLEVEL_CRITICAL,
  LOGLEVEL_FATAL
} ECLoggingLevel;

@protocol ECLoggingFormatter;
@class ECLoggingConfiguration;
@class ECLogger;

/*!
 * @class ECLogging
 * @abstract Class used for logging.
 * @discussion The logging mechanism behind is based on the following concepts:
 *   <ul>
 *     <li><b>Logging Levels</b>: Logging is categorized through logging levels.
 *       DEBUG, TRACE, INFO, WARN, ERROR, CRITICAL, FATAL are the supported
 *       levels.</li>
 *     <li><b>Logging Writers</b>: The logging data can be written on various 
 *       channels. At present a file writer as well as a NSLog writer are 
 *       supported. </li>
 *     <li><b>Logging formatters</b>: Logging formatters are used to format the 
 *       the output before it is being sent to the writer...</li>
 *     <li><b>context</b>: A context is used to select a certain logger.
 *   </ul>
 * All the objects behind can be configured and/or enhanced. They are bundled
 * through a so-called logging configuration (instances of
 * ECLoggingConfiguration). A logging configuration defines which format and
 * which writer a certain level may use. Afterwards this configuration is
 * registered under a certain so-called <b>context</b>. Objects use this context
 * in order to get access to the corresponding logger.<p/>
 * Example of the definition of a logger:
 * <pre>
  ECLoggingConfiguration *loggingConfiguration;
  ECDefaultLoggingFormatter *loggingFormatter
  
  loggingWriter = [[[ECFileLoggingWriter alloc] init] autorelease];
  [loggingWriter setBaseFilename: \@"sample.log"];
    
  loggingConfiguration = [[[ECLoggingConfiguration alloc] init] autorelease];

  [loggingConfiguration setLoggingLevel: \@"DEBUG ];
  [loggingConfiguration setLoggingWriter: loggingWriter];
  [loggingConfiguration 
    setLoggingFormatter: 
      [[[ECDefaultLoggingFormatter alloc] init] autorelease]];
      
  [[ECLogging instance] addLoggingConfiguration: loggingConfiguration
      forContext: \@"sample.context"];
 </pre>
 * The previous code registered a particular logging configuration using the
 * context name "sample.context". Implementations may now use this
 * configuration/logger by referring to this context: <p/>
 <pre>
  ECLogger *logger = [ECLogging loggerForContext: \@"sample.context"];
 
  if( [logger isDebugEnabled] ) {
    [logger debug: \@"This is a logging message of level DEBUG!"];
  }

  if( [logger isTraceEnabled] ) {
    [logger trace: \@"Trace is given hereby..."];
  }
  
  if( [logger isInfoEnabled] ) {
    [logger info: \@"This is a logging message of level INFO!"];
  }
  
  [logger error: \@"Logging with error code=%u and msg=%\@", 112,
    \@"Error Message" ];
    
 </pre>
 * Contexts are hierarchically organized, where the dot "." separates a
 * super-context from its sub-contexts. The selection of a logger therefor 
 * functions as follows: a configuration for a given context is valid for all 
 * the sub-contexts except for those child contexts defining their own 
 * configuration.<p/>
 * Say you have defined logging configurations for the following contexts:
 * <ul>
 *   <li>C1 defined for context: sample.context</li>
 *   <li>C2 defined for context: sample.context.A</li>
 *   <li>C2 defined for context: sample.context.A.B</li>
 * </ul>
 * For given contexts the following logging configurations will be used:
 * <ul>
 *   <li>sample.context.x chooses C1</li>
 *   <li>sample.context.A.a chooses C2</li>
 *   <li>sample.context.A.B.a.b chooses C3</li>
 * </ul>
 * If no logger could be found (e.g. "sample" wrt. example) then the root 
 * logger will be chosen, if defined.<p/>
 * The logging formatter as well as the logging writer can be configured in
 * diverse ways. Additionally it should be easy to integrate own formatter or
 * writers.
 */
@interface ECLogging : ECObject {
  @private
    NSMutableDictionary *contextToLogger;
    ECLogger *rootLogger;
}

+ initialize;

/*!
 * @method forContext
 * @abstract Return a logging instance suitable for the given context.
 * @param aContext implicitly specifies the output channel to be used
 * @result returns a logging instance suitable for the given context.
 */
+ (ECLogger *) loggerForContext: (NSString *) aContext;


/*! 
 * @method instance
 * @result the one and only logging instance
 */
+ (ECLogging *) instance;


/*!
 * @method init
 * @abstract initializes this object using the default logging formatter 
 * {@link ECDefaultLoggingFormatterImpl} and ECNSLogLoggingWriter as the
 * default logging writer
 * @result self
 */
- init;
- (void) dealloc;


/*!
 * @method addRootLoggingConfiguration
 * @abstract defines the logger which is used in case a logger could not be
 *   found for a particular context
 * @param aConfiguration configuration of the logger 
 * @result self
 */
- addRootLoggingConfiguration: (ECLoggingConfiguration *) aConfiguration;


/*!
 * @method addLoggingConfiguration:
 * @abstract adds a logging configuration for the given context.
 * @param aConfiguration configuration to register
 * @param aContext context to register the configuration under
 * @result self
 */
- addLoggingConfiguration: (ECLoggingConfiguration *) aConfiguration
  forContext: (NSString *) aContext;


/*!
 * @method createAllSupercontextsOf
 * @abstract creates all super contexts of a given context string.
 * @discussion The set of super contexts of e.g. "com.company.context"
 *   is {"com.company", "com"}.
 * @result array of super contexts where the first entry is the overall
 *   root context. The array may be empty if there exists no super
 *   context. The result does <b>not contain</b> the specified
 *   context strin g aContextStr itself.
 */
- (NSArray *) createAllSupercontextsOf: (NSString *) aContextStr;


/*!
 * @method loggerForContext
 * @abstract determines the logger for the given context
 * @result returns the logger which is suitable for the given context
 */
- (ECLogger *)  loggerForContext: (NSString *) aContext;
@end
#endif
