/*
 * Copyright(C) 2010 Крипто-Про, ООО
 *
 * Этот файл содержит информацию, являющуюся
 * собственностью компании Крипто-Про.
 *
 * Любая часть этого файла не может быть скопирована,
 * исправлена, переведена на другие языки,
 * локализована или модифицирована любым способом,
 * откомпилирована, передана по сети с или на
 * любую компьютерную систему без предварительного
 * заключения соглашения с компанией Крипто-Про.
 */

/*!
 * \file $RCSfile$
 * \version $Revision: 133081 $
 * \date $Date:: 2016-01-19 13:05:06 +0300#$
 * \author $Author: dim $
 *
 * \brief Простое протоколирование на интерфейсе POSIX syslog().
 *        Параметры протоколирования задаются в рамках одного
 *        файла C (или, возможно, одного объекта C++). 
 *        Предназначено для ситуаций, когда нет возможности
 *        воспользоваться имитатором реестра.
 *        Например, ubi_mutex.c, suid2.cpp, sup_lib.c или win32.not/sr*.c.
 *
 */

#ifndef sup_syslog_h_
#define sup_syslog_h_

#ifdef UNIX
    #include <pthread.h>
    #include <syslog.h>
    #include <sys/time.h>
    #include <time.h>
    #include <unistd.h>
#else
    // TODO:XX
    #error Unimplemented
#endif

#ifdef ANDROID
#include <android/log.h>
#define  syslog(pp, ...) __android_log_print(pp, "cprocsp", __VA_ARGS__)
#endif

enum {
	// facility
    SUPPORT_LOG_KERN = LOG_KERN,
    SUPPORT_LOG_USER = LOG_USER,
    SUPPORT_LOG_MAIL = LOG_MAIL,
    SUPPORT_LOG_NEWS = LOG_NEWS,
    SUPPORT_LOG_UUCP = LOG_UUCP,
    SUPPORT_LOG_DAEMON = LOG_DAEMON,
#ifndef ANDROID    /* TODO: facility for Android до конца не разобрался*/
    SUPPORT_LOG_AUTH = LOG_AUTH,
#else
    SUPPORT_LOG_AUTH = 0,
#endif    
    SUPPORT_LOG_CRON = LOG_CRON,
    SUPPORT_LOG_LPR = LOG_LPR,
    SUPPORT_LOG_LOCAL0 = LOG_LOCAL0,
    SUPPORT_LOG_LOCAL1 = LOG_LOCAL1,
    SUPPORT_LOG_LOCAL2 = LOG_LOCAL2,
    SUPPORT_LOG_LOCAL3 = LOG_LOCAL3,
    SUPPORT_LOG_LOCAL4 = LOG_LOCAL4,
    SUPPORT_LOG_LOCAL5 = LOG_LOCAL5,
    SUPPORT_LOG_LOCAL6 = LOG_LOCAL6,
    SUPPORT_LOG_LOCAL7 = LOG_LOCAL7,
	// priority,
#ifndef ANDROID   
    SUPPORT_LOG_EMERG = LOG_EMERG,
    SUPPORT_LOG_ALERT = LOG_ALERT,
    SUPPORT_LOG_CRIT = LOG_CRIT,
    SUPPORT_LOG_ERR = LOG_ERR,
    SUPPORT_LOG_WARNING = LOG_WARNING,
    SUPPORT_LOG_NOTICE = LOG_NOTICE,
    SUPPORT_LOG_INFO = LOG_INFO,
    SUPPORT_LOG_DEBUG = LOG_DEBUG
#else
    SUPPORT_LOG_EMERG = ANDROID_LOG_FATAL,
    SUPPORT_LOG_ALERT = 0,
    SUPPORT_LOG_CRIT = ANDROID_LOG_FATAL,
    SUPPORT_LOG_ERR = ANDROID_LOG_ERROR,
    SUPPORT_LOG_WARNING = ANDROID_LOG_WARN,
    SUPPORT_LOG_NOTICE = ANDROID_LOG_VERBOSE,
    SUPPORT_LOG_INFO = ANDROID_LOG_INFO,
    SUPPORT_LOG_DEBUG = ANDROID_LOG_DEBUG
#endif
};

#define SUPPORT_LOG_MASK(pri)	LOG_MASK(pri)

static const int support_pris_ =
	SUPPORT_LOG_MASK(SUPPORT_LOG_EMERG)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_CRIT)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_ERR)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_WARNING)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_NOTICE)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_INFO)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_DEBUG);

static int support_logmask_ = 
	SUPPORT_LOG_MASK(SUPPORT_LOG_EMERG)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_CRIT)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_ERR)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_WARNING)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_NOTICE)|
	SUPPORT_LOG_MASK(SUPPORT_LOG_INFO);

static int support_logfac_ = SUPPORT_LOG_AUTH;

static const char *support_ident_ = NULL; // TODO: Нужен массив

static SUP_INLINE void
support_openlog(const char *ident, int logopt, int facility)
{
    if (ident) {
	support_ident_ = ident;	// TODO: Надо делать strcpy_s()
    }
    UNUSED(logopt);
    if (facility) {
	support_logfac_ = facility;
    }
}

static SUP_INLINE void *
support_gettid_()
{
    return ((void *)(intptr_t)pthread_self);
}

#define support_syslog_(p, m, ...) { \
                if (support_logmask_&SUPPORT_LOG_MASK((p)&~support_pris_)) { \
		    int pp = (p); \
                    struct timeval  tv; \
                    struct tm       tm; \
                    char            ts[16]; \
                    \
		    if (0 == (pp&~support_pris_)) { \
			pp |= support_logfac_; \
		    } \
                    gettimeofday(&tv, NULL); \
                    localtime_r(&tv.tv_sec, &tm); \
                    strftime(ts, sizeof(ts), "%T", &tm); \
                    syslog(pp, "%s%s%s.%06ld %s:%d p:%d t:0x%p " m "%s", \
				(support_ident_ ? support_ident_ : ""), \
				(support_ident_ ? " " : ""), \
                                ts, (long)tv.tv_usec,  \
                                __func__, __LINE__, \
                                getpid(), support_gettid_(), \
                                __VA_ARGS__); \
                } \
            }
#define support_syslog(...)     {support_syslog_(__VA_ARGS__, "")}

// TODO:XXX Дубль с reader/dprint.h
#ifndef SFUNC
    #if defined( _MSC_VER )
	#define __STR2WSTR(str) L##str
	#define _STR2WSTR(str)  __STR2WSTR(str)

	# if defined UNICODE
	#   define SFUNC _STR2WSTR(__FUNCTION__)
	# else
	#   define SFUNC __FUNCTION__
	# endif
    #elif defined(__GNUC__)
	# if (__GNUC__ == 2)
	#   define SFUNC __FUNCTION__
	# else /*(__GNUC__ == 2)*/
	#   define SFUNC __func__
	# endif  /*(__GNUC__ == 2)*/
    #else /*defined( _MSC_VER ) */
	#   define SFUNC __func__
    #endif /*defined( _MSC_VER ) */
#endif

#endif /* sup_syslog_h_ */
