/*!
 * @file libharkio3_log.c
 *
 * @author Takeshi Mizumoto
 * @version 0.1
 * @brief  harkio_Log の API群。 エラーやデバッグメッセージを表示する。
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>

#include "libharkio3.h"
#include "libharkio3_macros.h"

#ifndef HARKIO_LOG_INITIAL_LEVEL
/*! @brief ログ出力レベルの初期設定 */
#define HARKIO_LOG_INITIAL_LEVEL harkio_Log_Debug
#endif

/**
 * 環境変数からログレベルを取得
 */
enum harkio_Log_logLevel getLogLevelFromEnv() {
    char* levelEnv = getenv(HARKIO_LOGLEVEL_ENV_NAME);
    enum harkio_Log_logLevel level = HARKIO_LOG_INITIAL_LEVEL;
    if (levelEnv) {
        char levelStr[strlen(levelEnv) + 1];
        strcpy(levelStr, levelEnv);
        // 小文字に統一
        for (char* p = levelStr; *p; p++)
            *p = tolower(*p);

        if (strcmp(levelStr, "error") == 0 || strcmp(levelStr, "e") == 0) {
            level = harkio_Log_Error;
        } else if (strcmp(levelStr, "warning") == 0 || strcmp(levelStr, "warn") == 0 || strcmp(levelStr, "w") == 0) {
            level = harkio_Log_Warning;
        } else if (strcmp(levelStr, "info") == 0 || strcmp(levelStr, "i") == 0) {
            level = harkio_Log_Info;
        } else if (strcmp(levelStr, "debug") == 0 || strcmp(levelStr, "d") == 0) {
            level = harkio_Log_Debug;
        } else if (strcmp(levelStr, "trace") == 0 || strcmp(levelStr, "t") == 0) {
            level = harkio_Log_Trace;
        }
    }
    return level;
}

// LogLevelには、メッセージのログレベルをセットする
// PrintLevelには、コマンド引数で設定されたログレベルをセットする
void harkio_Log_printf_(enum harkio_Log_logLevel LogLevel, char *message, int PrintLevel, const char *func, int line,
        ...) {
    static int level = -1; // initial value means undefined

    //harkio_Log_setLevel only
    if (LogLevel == -1) {
        level = PrintLevel;
        return;
    }

    // set log level from environment variable, when it's undefined
    if (level < 0)
        level = getLogLevelFromEnv();

    va_list args;
    va_start(args, line);
    switch (level) {
    case harkio_Log_Trace:
        if (LogLevel == harkio_Log_Trace) {
            LIBHARKIO_LOGT("[T] [");
            LIBHARKIO_LOGVT(message, args);
            LIBHARKIO_LOGT("] [%s] [%d]\n", func, line);
        }
        /* no break */
    case harkio_Log_Debug:
        if (LogLevel == harkio_Log_Debug) {
            LIBHARKIO_LOGD("[D] [");
            LIBHARKIO_LOGVD(message, args);
            LIBHARKIO_LOGD("] [%s] [%d]\n", func, line);
        }
        /* no break */
    case harkio_Log_Info:
        if (LogLevel == harkio_Log_Info) {
            LIBHARKIO_LOGI("[I] [");
            LIBHARKIO_LOGVI(message, args);
            LIBHARKIO_LOGI("] [%s] [%d]\n", func, line);
        }
        /* no break */
    case harkio_Log_Warning:
        if (LogLevel == harkio_Log_Warning) {
            LIBHARKIO_LOGW("[W] [");
            LIBHARKIO_LOGVW(message, args);
            LIBHARKIO_LOGW("] [%s] [%d]\n", func, line);
        }
        /* no break */
    default:
        if (LogLevel == harkio_Log_Error) {
            LIBHARKIO_LOGE("[E] [");
            LIBHARKIO_LOGVE(message, args);
            LIBHARKIO_LOGE("] [%s] [%d]\n", func, line);
        }
        break;
    }
    va_end(args);

}

// supporting functions
void harkio_Log_FileOpenFailed(char *filename) {
    // for file open failed
    char *constmsg = " File open failed: ";

    harkio_Log_printf(harkio_Log_Error, "%s%s", constmsg, filename);
}

void harkio_Log_WrongValue(char *valuename, char *reason) {
    // for wrong value
    char *constmsg = " has a wrong value: ";

    harkio_Log_printf(harkio_Log_Error, "%s%s%s", valuename, constmsg, reason);
}

void harkio_Log_NullPointer(char *valuename) {
    // for null pointers
    char *constmsg = " is NULL";

    harkio_Log_printf(harkio_Log_Error, "%s%s", valuename, constmsg);
}

