//
//  DDLog.h
//
//  Created by Boisy G. Pitre on 9/1/11.
//  Copyright 2011 Nuance Communications, Inc. All rights reserved.
//
//  How this would normally get used:
//
//    1. An application would include "DDLog.h" in its .pch file
//    2. applicationDidFinishLaunching: would have the following lines:
//          log = [[DDLog sharedLog] start];
//    3. The rest of the application would use the following to send message:
//          [[DDLog sharedLog] logLevel:DDLogLevelError message:@"Some log message"];
//              ... OR one of the convenience macros ...
//          DDLogError(@"This is a %@ message", @"Error");
//    4.  applicationWillTerminate: would have the following lines:
//          [[DDLog sharedLog] stop];

#import <asl.h>

/// \brief DDLogLevel enumeration
/// \details The values in the enumeration mimics ASL log levels
typedef enum
{
    DDLogLevelEmergency = ASL_LEVEL_EMERG,
    DDLogLevelAlert = ASL_LEVEL_ALERT,
    DDLogLevelCritical = ASL_LEVEL_CRIT,
    DDLogLevelError = ASL_LEVEL_ERR,
    DDLogLevelWarning = ASL_LEVEL_WARNING,
    DDLogLevelNotice = ASL_LEVEL_NOTICE,
    DDLogLevelInfo = ASL_LEVEL_INFO,
    DDLogLevelDebug = ASL_LEVEL_DEBUG
} DDLogLevel;

#define DDLogFormat(format, ...) [NSString stringWithFormat:(format), ##__VA_ARGS__]

// Convenience macros
// Set the log level
#define  DDLogLevel(lvl)              [[DDLog sharedLog] setLogLevel:lvl]
// Turn standard error logging on to see log messages in your Xcode console window
#define  DDLogStdErr(boolValue)       [[DDLog sharedLog] setLogStandardError:boolValue]

#define DDLogEmergency(format, ...)   [[DDLog sharedLog] logLevel:DDLogLevelEmergency message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]
#define DDLogAlert(format, ...)       [[DDLog sharedLog] logLevel:DDLogLevelAlert message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]
#define DDLogCritical(format, ...)    [[DDLog sharedLog] logLevel:DDLogLevelCritical message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]
#define DDLogError(format, ...)       [[DDLog sharedLog] logLevel:DDLogLevelError message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]
#define DDLogWarning(format, ...)     [[DDLog sharedLog] logLevel:DDLogLevelWarning message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]
#define DDLogNotice(format, ...)      [[DDLog sharedLog] logLevel:DDLogLevelNotice message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]
#define DDLogInfo(format, ...)        [[DDLog sharedLog] logLevel:DDLogLevelInfo message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]
#define DDLogDebug(format, ...)       [[DDLog sharedLog] logLevel:DDLogLevelDebug message:[NSString stringWithFormat:(format), ##__VA_ARGS__]]

#define kLogState               @"logState"
#define kLogLevel               @"logLevel"
#define kLogStandardError       @"logStandardError"
#define kDebugProfile           @"DebugProfile"
#define kNumberOfDaysToKeepLogs @"logDaysToKeep"

#define kNeedsDebugLogFile      @"#DebugLogFile"

@interface DDLog : NSObject
{
    DDLogLevel  logLevel;
    BOOL        logState;
    NSString     *bundleName;
    NSString     *bundleID;
    NSDictionary *logTags;
    FILE          *_logFD;
}

/// \brief Returns the log object
+ (DDLog *)sharedLog;

- (NSArray *)logLevelNameArray;

/// \brief Dumps the current stack frame
- (void)dumpFrames;

/// \brief Send a message to the logging system
/// \param level The log level to send the message as
/// \param message The message to send
- (void)logLevel:(DDLogLevel)level message:(NSString *)message;

/// \brief Send a message to the logging system
/// \param level The log level to send the message as
/// \param message The message to send
/// \param msgInfo Name value pairs to be associated with the logged message
- (void)logLevel:(DDLogLevel)level message:(NSString *)message info:(NSDictionary *)msgInfo;

/// \brief Send a message to the logging system along with an attachment
/// \param level The log level to send the message as
/// \param message The message to send
/// \param uti The uniform type identifier to send
/// \param attachmentName The name of the file that the attachment will be saved to
/// \param attachment The attachment data
- (void)logLevel:(DDLogLevel)level message:(NSString *)message uti:(NSString *)uti attachmentName:(NSString *)attachmentName attachment:(NSData *)attachment;

/// \brief Send a message to the logging system along with an URL
/// \param level The log level to send the message as
/// \param message The message to send
/// \param uti The uniform type identifier to send
/// \param url The URL to send
- (void)logLevel:(DDLogLevel)level message:(NSString *)message uti:(NSString *)uti url:(NSString *)url;

/// \brief Set the log level using a string
/// \param level The log level string to set the logging system to
- (void)setLogLevelFromString:(NSString *)level;

/// \brief Set the log level
/// \param level The log level to set the logging system to
- (void)setLogLevel:(DDLogLevel)level;

- (BOOL)logStandardError;

- (void)setLogStandardError:(BOOL)value;

/// \brief Starts logging
- (void)start;

/// \brief Stops logging
- (void)stop;

/// \brief Establishes a new set of filtering hashTags
- (void)loadTagsForProfile:(NSInteger)profile level:(DDLogLevel)level;

@end



// DDLog Macros
#define DDSetProfile(num) {\
    [[DDLog sharedLog] loadTagsForProfile:num level:DDLogLevelDebug];\
}


#define DDFatal(format, ...)       {\
    NSString *_ddMsg = [NSString stringWithFormat:(format @" #%s"), ##__VA_ARGS__, MODULE_HASHTAG];\
    [[DDLog sharedLog] logLevel:DDLogLevelCritical message:_ddMsg];\
}

#define DDError(format, ...)       {\
    NSString *_ddMsg = [NSString stringWithFormat:(format @" #%s"), ##__VA_ARGS__, MODULE_HASHTAG];\
    [[DDLog sharedLog] logLevel:DDLogLevelError message:_ddMsg];\
}


#define DDTrace(format, ...)       {\
    NSString *_ddMsg = [NSString stringWithFormat:(format @" #%s"), ##__VA_ARGS__, MODULE_HASHTAG];\
    [[DDLog sharedLog] logLevel:DDLogLevelNotice message:_ddMsg];\
}

#define DDFileTrace(format, ...)       {\
NSString *_ddMsg = [NSString stringWithFormat:(format @" #%s %@"), ##__VA_ARGS__, MODULE_HASHTAG, kNeedsDebugLogFile];\
[[DDLog sharedLog] logLevel:DDLogLevelNotice message:_ddMsg];\
}


#if DEBUG
#define DDLog(format, ...)         {\
    NSString *_sourceFile = [[NSString stringWithUTF8String:__FILE__] lastPathComponent];\
    NSDictionary *_ddInfo = [NSDictionary dictionaryWithObjectsAndKeys:\
        [NSString stringWithFormat:@"%@:%d",_sourceFile,__LINE__], @"SourceFile",\
        [NSString stringWithUTF8String:__PRETTY_FUNCTION__], @"SourceMethod",\
        nil];\
    NSString *_ddMsg = [NSString stringWithFormat:(format @" #%s"), ##__VA_ARGS__, MODULE_HASHTAG];\
    [[DDLog sharedLog] logLevel:DDLogLevelDebug message:_ddMsg info:_ddInfo];\
}
#else
#define DDLog(format, ...) 
#endif

#define DDStackTrace() [[DDLog sharedLog] dumpFrames]

#define DDFatalException2(ex,msg)       {\
NSString *_ddMsg = [NSString stringWithFormat:@"%@ %@ #%s", msg, GTMStackTraceFromException(ex), MODULE_HASHTAG];\
[[DDLog sharedLog] logLevel:DDLogLevelCritical message:_ddMsg];\
}

#define DDFatalException(ex, format, ...)       {\
    NSString *_ddMsg = [NSString stringWithFormat:(format @" %@ %@ #%s"), ##__VA_ARGS__,  GTMStackTraceFromException(ex),  MODULE_HASHTAG]; \
    [[DDLog sharedLog] logLevel:DDLogLevelCritical message:_ddMsg];\
}
