// Software License Agreement (BSD License)
//
// Copyright (c) 2010-2023, Deusty, LLC
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
// with or without modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
// * Neither the name of Deusty nor the names of its contributors may be used
//   to endorse or promote products derived from this software without specific
//   prior written permission of Deusty, LLC.

// Disable legacy macros
#ifndef DD_LEGACY_MACROS
    #define DD_LEGACY_MACROS 0
#endif
#ifndef DD_NSLOG_LEVEL
    #define DD_NSLOG_LEVEL 2
#endif






#import "DDLog.h"
#import "DDFileLogger.h"
#import "DDLogFileInfo.h"
#import "DDLogFileManager.h"
#import "DDLogFileManagerDefault.h"
#import "DDLogFileFormatterDefault.h"

#define NSLogError(frmt, ...)    do{ if(DD_NSLOG_LEVEL >= 1) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogWarn(frmt, ...)     do{ if(DD_NSLOG_LEVEL >= 2) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogInfo(frmt, ...)     do{ if(DD_NSLOG_LEVEL >= 3) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogDebug(frmt, ...)    do{ if(DD_NSLOG_LEVEL >= 4) NSLog((frmt), ##__VA_ARGS__); } while(0)
#define NSLogVerbose(frmt, ...)  do{ if(DD_NSLOG_LEVEL >= 5) NSLog((frmt), ##__VA_ARGS__); } while(0)


NS_ASSUME_NONNULL_BEGIN

/**
 * This class provides a logger to write log statements to a file.
 **/


// Default configuration and safety/sanity values.
//
// maximumFileSize         -> kDDDefaultLogMaxFileSize
// rollingFrequency        -> kDDDefaultLogRollingFrequency
// maximumNumberOfLogFiles -> kDDDefaultLogMaxNumLogFiles
// logFilesDiskQuota       -> kDDDefaultLogFilesDiskQuota
//
// You should carefully consider the proper configuration values for your application.

extern unsigned long long const kDDDefaultLogMaxFileSize;
extern NSTimeInterval     const kDDDefaultLogRollingFrequency;
extern NSUInteger         const kDDDefaultLogMaxNumLogFiles;
extern unsigned long long const kDDDefaultLogFilesDiskQuota;



/**
 *  The standard implementation for a file logger
 */
@interface DDFileLogger : DDAbstractLogger <DDLogger>



/**
 *  Designated initializer, requires a `DDLogFileManager` instance.
 *  A global queue w/ default priority is used to run callbacks.
 *  If needed, specify queue using `initWithLogFileManager:completionQueue:`.
 */
- (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager logfileFormatter:(nullable DDLogFileFormatterDefault *)logfileFormatter;

/**
 *  Designated initializer, requires a `DDLogFileManager` instance.
 *  The completionQueue is used to execute `didArchiveLogFile:wasRolled:`,
 *  and the callback in `rollLogFileWithCompletionBlock:`.
 *  If nil, a global queue w/ default priority is used.
 */
- (instancetype)initWithLogFileManager:(id <DDLogFileManager>)logFileManager logfileFormatter:(nullable DDLogFileFormatterDefault *)logfileFormatter completionQueue:(nullable dispatch_queue_t)dispatchQueue NS_DESIGNATED_INITIALIZER;

/**
 *  Deprecated. Use `willLogMessage:`
 */
- (void)willLogMessage __attribute__((deprecated("Use -willLogMessage:"))) NS_REQUIRES_SUPER;

/**
 *  Deprecated. Use `didLogMessage:`
 */
- (void)didLogMessage __attribute__((deprecated("Use -didLogMessage:"))) NS_REQUIRES_SUPER;

/**
 *  Called when the logger is about to write message. Call super before your implementation.
 */
- (void)willLogMessage:(DDLogFileInfo *)logFileInfo NS_REQUIRES_SUPER;

/**
 *  Called when the logger wrote message. Call super after your implementation.
 */
- (void)didLogMessage:(DDLogFileInfo *)logFileInfo NS_REQUIRES_SUPER;

/**
 *  Writes all in-memory log data to the permanent storage. Call super before your implementation.
 *  Don't call this method directly, instead use the `[DDLog flushLog]` to ensure all log messages are included in flush.
 */
- (void)flush NS_REQUIRES_SUPER;

/**
 *  Called when the logger checks archive or not current log file.
 *  Override this method to extend standard behavior. By default returns NO.
 *  This is executed directly on the logger's internal queue, so keep processing light!
 */
- (BOOL)shouldArchiveRecentLogFileInfo:(DDLogFileInfo *)recentLogFileInfo;

/**
 * Log File Rolling:
 *
 * `maximumFileSize`:
 *   The approximate maximum size (in bytes) to allow log files to grow.
 *   If a log file is larger than this value after a log statement is appended,
 *   then the log file is rolled.
 *
 * `rollingFrequency`
 *   How often to roll the log file.
 *   The frequency is given as an `NSTimeInterval`, which is a double that specifies the interval in seconds.
 *   Once the log file gets to be this old, it is rolled.
 *
 * `doNotReuseLogFiles`
 *   When set, will always create a new log file at application launch.
 *
 * Both the `maximumFileSize` and the `rollingFrequency` are used to manage rolling.
 * Whichever occurs first will cause the log file to be rolled.
 *
 * For example:
 * The `rollingFrequency` is 24 hours,
 * but the log file surpasses the `maximumFileSize` after only 20 hours.
 * The log file will be rolled at that 20 hour mark.
 * A new log file will be created, and the 24 hour timer will be restarted.
 *
 * You may optionally disable rolling due to filesize by setting `maximumFileSize` to zero.
 * If you do so, rolling is based solely on `rollingFrequency`.
 *
 * You may optionally disable rolling due to time by setting `rollingFrequency` to zero (or any non-positive number).
 * If you do so, rolling is based solely on `maximumFileSize`.
 *
 * If you disable both `maximumFileSize` and `rollingFrequency`, then the log file won't ever be rolled.
 * This is strongly discouraged.
 **/
@property (readwrite, assign) unsigned long long maximumFileSize;

/**
 *  See description for `maximumFileSize`
 */
@property (readwrite, assign) NSTimeInterval rollingFrequency;

/**
 *  See description for `maximumFileSize`
 */
@property (readwrite, assign, atomic) BOOL doNotReuseLogFiles;

/**
 * The DDLogFileManager instance can be used to retrieve the list of log files,
 * and configure the maximum number of archived log files to keep.
 *
 * @see DDLogFileManager.maximumNumberOfLogFiles
 **/
@property (strong, nonatomic, readonly) id <DDLogFileManager> logFileManager;

/**
 * When using a custom formatter you can set the `logMessage` method not to append
 * `\n` character after each output. This allows for some greater flexibility with
 * custom formatters. Default value is YES.
 **/
@property (nonatomic, readwrite, assign) BOOL automaticallyAppendNewlineForCustomFormatters;

/**
 *  You can optionally force the current log file to be rolled with this method.
 *  CompletionBlock will be called on main queue.
 */
- (void)rollLogFileWithCompletionBlock:(nullable void (^)(void))completionBlock
    NS_SWIFT_NAME(rollLogFile(withCompletion:));

/**
 *  Method is deprecated.
 *  @deprecated Use `rollLogFileWithCompletionBlock:` method instead.
 */
- (void)rollLogFile __attribute__((deprecated("Use -rollLogFileWithCompletionBlock:")));




- (void)logData:(NSData *)data;

// Will assert if used outside logger's queue.
- (void)lt_logData:(NSData *)data;

- (nullable NSData *)lt_dataForMessage:(DDLogMessage *)message;


// Inherited from DDAbstractLogger

// - (id <DDLogFormatter>)logFormatter;
// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;

/**
 * Returns the log file that should be used.
 * If there is an existing log file that is suitable,
 * within the constraints of `maximumFileSize` and `rollingFrequency`, then it is returned.
 *
 * Otherwise a new file is created and returned. If this failes, `NULL` is returned.
 **/
@property (nonatomic, nullable, readonly, strong) DDLogFileInfo *currentLogFileInfo;

@end





NS_ASSUME_NONNULL_END
