/*
* Copyright 2009 Funambol, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "stdafx.h"
#include "Logger/Logger.h"
#include "IOutStream.h"
#include "platform.h"

#include "PortableThread.h"
#include <cstdio>
#include "lock.h"

#ifndef PLATFORM_ANDROID
#include <iostream>
#endif

#include <string>

#include "androidlog.h"
#define LOG_TAG "Logger"


namespace NS_Logging
{

static char const* const categoryStr[] = {"[CRITICAL]", "[ERROR]", "[WARNING]", "[INFO]", "[DEBUG]", "[DUMP]"};

    Logger::Logger(const char* name): m_minimalCategory(e_debug), m_bufSize(4096),
        m_ostream(0), m_enabled(false), m_name(name), m_critSection(0)
    {
    }
    //-------------------------------------------------------------------------------------------

    Logger::~Logger()
    {
    }
    //-------------------------------------------------------------------------------------------

    void Logger::SetMinimalCategory(Category cat)
    {
        m_minimalCategory = long(cat);
    }
    //-------------------------------------------------------------------------------------------

    void Logger::SetMaxMessageSize(size_t size)
    {
        m_bufSize = (long)size;
    }
    //-------------------------------------------------------------------------------------------

    void Logger::Error(char const* format, ...)
    {
        va_list va;
        va_start(va, format);
        log(NS_Logging::e_error, NULL, format, va);
        va_end(va);
    }
    //-------------------------------------------------------------------------------------------

    void Logger::Info(char const* format, ...)
    {
        va_list va;
        va_start(va, format);
        log(NS_Logging::e_info, NULL, format, va);
        va_end(va);
    }
    //-------------------------------------------------------------------------------------------

    void Logger::Debug(char const* format, ...)
    {
        va_list va;
        va_start(va, format);
        log(NS_Logging::e_debug, NULL, format, va);
        va_end(va);
    }
    //-------------------------------------------------------------------------------------------

    void Logger::Warning(char const* format, ...)
    {
        va_list va;
        va_start(va, format);
        log(NS_Logging::e_warning, NULL, format, va);
        va_end(va);
    }
    //-------------------------------------------------------------------------------------------

    void Logger::Log(const char* format, ...)
    {
        va_list va;
        va_start(va, format);
        log(NS_Logging::e_info, NULL, format, va);
        va_end(va);
    }
    //-------------------------------------------------------------------------------------------
    void Logger::log(Category category, char const* functionName, char const* format, va_list va)
    {
        if (!m_enabled || category > m_minimalCategory)
            return;

        NS_DM_Client::NS_Common::Lock lock(*m_critSection);
        // format Log message
        std::string buf;
        buf.resize(m_bufSize, '\0');
        char* curBuf = const_cast<char*>(buf.c_str());
        size_t size = buf.size() - 1; // for trailing \n

        int written;

        if (functionName)
        {
            written = m_ostream->FormatMessage(curBuf, (int)size, pthread_self(), m_name.c_str(),
                categoryStr[category], functionName);
        } 
        else
        {
          written = m_ostream->FormatMessage(curBuf, (int)size, pthread_self(), m_name.c_str(), 
                categoryStr[category]);
        }
        curBuf += written;
        size -= written;
        written = vsnprintf(curBuf, size, format, va);
        if (written != -1 && written < (int)size)
            written += (int)buf.size() - size - 1;
        else
            written = (int)buf.size() - 1;
        const_cast<char*>(buf.c_str())[written] = '\n';
        buf.resize(written + 1);

        if (m_ostream)
        {
            m_ostream->Write(buf.c_str(), (int)buf.size()); // thread safe operation
        }
#ifndef PLATFORM_ANDROID
        std::cout << buf;
#endif
    }
    //-------------------------------------------------------------------------------------------

    void Logger::enable(NS_DM_Client::NS_Common::IOutStream* stream, NS_DM_Client::NS_Common::CritSection& critSection)
    {
        m_enabled = true;
        m_ostream = stream;
        m_critSection = &critSection;
#ifndef PLATFORM_ANDROID
        std::cout << "Logger \"" << m_name << "\" is enabled\n";
#endif
    }
    //-------------------------------------------------------------------------------------------

    void FunctionNameLogHelper::Log(Logger& logger, char const* format, ...)
    {
        va_list va;
        va_start(va, format);
        logger.log(m_category, m_funcName, format, va);
        va_end(va);
    }
    //-------------------------------------------------------------------------------------------

    FunctionNameLogHelper::FunctionNameLogHelper(const char* funcName, Category cat):
        m_funcName(funcName), m_category(cat)
    {
    }

}

