//
//  Logging.m
//  MYUtilities
//
//  Created by Jens Alfke on 1/5/08.
//  Copyright 2008 Jens Alfke. All rights reserved.
//

#import "Logging.h"
#import <unistd.h>
#include <fcntl.h>
#include <sys/param.h>


NSString* LOC( NSString *key )     // Localized string lookup
{
    NSString *value = [[NSBundle mainBundle] localizedStringForKey:key value:nil table:nil];
    if( value == key ) {
        Warn(@"No localized string for '%@' in Localizable.strings!",key);
        value = [key uppercaseString];
    }
    return value;
}


int _gShouldLog = -1;
static BOOL sConsole;
static NSMutableSet *sEnabledDomains;


static BOOL isConsole( int fd )
{
    if( isatty(fd) )
        return YES;
    char path[MAXPATHLEN];
    if( fcntl(fd, F_GETPATH, path) == -1 )
        return NO;
    return YES;
}


static void InitLogging()
{
    if( _gShouldLog != -1 )
        return;

    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    _gShouldLog = NO;
    sEnabledDomains = [[NSMutableSet alloc] init];
    NSDictionary *dflts = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
    for( NSString *key in dflts ) {
        if( [key hasPrefix: @"Log"] ) {
            BOOL value = [[NSUserDefaults standardUserDefaults] boolForKey: key];
            if( key.length==3 )
                _gShouldLog = value;
            else if( value )
                [sEnabledDomains addObject: [key substringFromIndex: 3]];
        }
    }
    sConsole = isConsole(STDERR_FILENO);
    
    Log(@"Logging enabled in domains: {%@}", 
        [[[sEnabledDomains allObjects] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)] 
                componentsJoinedByString: @", "]);
    [pool drain];
}


BOOL EnableLog( BOOL enable )
{
    if( _gShouldLog == -1 )
        InitLogging();
    BOOL old = _gShouldLog;
    _gShouldLog = enable;
    return old;
}

BOOL _WillLogTo( NSString *domain )
{
    if( _gShouldLog == -1 )
        InitLogging();
    return _gShouldLog && [sEnabledDomains containsObject: domain];
}

BOOL _EnableLogTo( NSString *domain, BOOL enable )
{
    if( _gShouldLog == -1 )
        InitLogging();
    BOOL old = [sEnabledDomains containsObject: domain];
    if( enable )
        [sEnabledDomains addObject: domain];
    else
        [sEnabledDomains removeObject: domain];
    return old;
}


static void _Logv( NSString *prefix, NSString *msg, va_list args )
{
    if( sConsole ) {
        NSAutoreleasePool *pool = [NSAutoreleasePool new];
        static NSDateFormatter *sTimestampFormat;
        if( ! sTimestampFormat ) {
            sTimestampFormat = [[NSDateFormatter alloc] init];
            sTimestampFormat.dateFormat = @"HH:mm:ss.SSS";
        }
        NSDate *now = [[NSDate alloc] init];
        NSString *timestamp = [sTimestampFormat stringFromDate: now];
        [now release];
        NSString *separator = prefix.length ?@": " :@"";
        msg = [[NSString alloc] initWithFormat: msg arguments: args];
        NSString *finalMsg = [[NSString alloc] initWithFormat: @"%@| %@%@%@\n", 
                              timestamp,prefix,separator,msg];
        fputs([finalMsg UTF8String], stderr);
        [finalMsg release];
        [msg release];
        [pool drain];
    } else
        NSLogv(msg,args);
}


void AlwaysLog( NSString *msg, ... )
{
    va_list args;
    va_start(args,msg);
    _Logv(@"",msg,args);
    va_end(args);
}


void _Log( NSString *msg, ... )
{
    if( _gShouldLog == -1 )
        InitLogging();
    if( _gShouldLog ) {
        va_list args;
        va_start(args,msg);
        _Logv(@"",msg,args);
        va_end(args);
    }
}


void _LogTo( NSString *domain, NSString *msg, ... )
{
    if( _gShouldLog == -1 )
        InitLogging();
    if( _gShouldLog && [sEnabledDomains containsObject: domain] ) {
        va_list args;
        va_start(args,msg);
        _Logv(domain, msg, args);
        va_end(args);
    }
}


void Warn( NSString *msg, ... )
{
    va_list args;
    va_start(args,msg);
    _Logv(@"WARNING*** ",msg,args);
    va_end(args);
}


