/**
 * @file LoggerTest.h
 * @author Bartosz Janiak
 * 
 * @brief
 *
 * Copyright © 2009 NVIDIA Corporation. All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property and proprietary
 * rights in and to this software, related documentation and any modifications thereto. Any
 * use, reproduction, disclosure or distribution of this software and related documentation
 * without express license agreement from NVIDIA Corporation is strictly prohibited.
 */

#pragma once
#include "MockWinApi.h"
#include "cxxtest/TestSuite.h"
#include "TestObjects.h"
#include <Logging.h>
#include <Logger.h>
#include <boost/assign/std/set.hpp>

namespace Nvidia {
namespace Logging {
namespace Test {

using namespace boost::assign; // bring 'operator+=()' into scope

class LoggerTest : public CxxTest::TestSuite
{
public:
    DEFINE_LOGGER(_T("testClassLogger"));

    TestLogManager m_testLogManager;
    std::vector<GenericLogPrinter<std::tstring>* > m_logPrintersToCleanup;

    void setUp()
    {
        Logger& logger = Logger::GetLogger();
        TS_ASSERT_EQUALS(logger.m_filtersAndPrinters.size(), 3);
        
        for ( int i = 0 ; i < 3 ; i++ )
        {
            GenericLogPrinter<std::tstring>* logPrinter = dynamic_cast<GenericLogPrinter<std::tstring>*>(logger.m_filtersAndPrinters[i].second);
            TS_ASSERT(logPrinter);
            m_logPrintersToCleanup.push_back(logPrinter);
            logPrinter->AddLogManager(&m_testLogManager);
        }
    }

    void TestLogging()
    {
        TestLoggable testLoggable;
        GenericSimpleLoggable<double> loggable(3.14);
        std::vector<int> vector;
        std::vector<std::tstring> lineNumberVector;
        vector += 2, 5, 8;

        LOG(Critical, 42 + testLoggable + vector + loggable + _T("string")); lineNumberVector += boost::lexical_cast<std::tstring>(__LINE__);
        LOG(Error,    42 + testLoggable + vector + loggable + _T("string")); lineNumberVector += boost::lexical_cast<std::tstring>(__LINE__);
        LOG(Warning,  42 + testLoggable + vector + loggable + _T("string")); lineNumberVector += boost::lexical_cast<std::tstring>(__LINE__);
        LOG(Debug,    42 + testLoggable + vector + loggable + _T("string")); lineNumberVector += boost::lexical_cast<std::tstring>(__LINE__);
        LOG(Info,     42 + testLoggable + vector + loggable + _T("string")); lineNumberVector += boost::lexical_cast<std::tstring>(__LINE__);
        
        std::tstring baseExpectedMessage;
        baseExpectedMessage += _T(" |_LOGLEVEL_: [testClassLogger] _LINE_@Nvidia::Logging::Test::LoggerTest::TestLogging : 42 ");
        baseExpectedMessage += _T("TestLoggable123 vector<int> 3.1400000000000001 string. ");
        baseExpectedMessage += _T("TestLoggable( id=\"123\" someField1=\"154\" someField2=TestLoggable2( id=\"abc\" doubleField=\"9.8699999999999992\" ) ");
        baseExpectedMessage += _T("vectorField=vector( \"firstString\" \"secondString\" ) ) vector( \"2\" \"5\" \"8\" ) ");

#if defined UNICODE || defined _UNICODE
        boost::algorithm::replace_all(baseExpectedMessage, _T("_CHAR_"), _T("wchar_t"));  
#else
        boost::algorithm::replace_all(baseExpectedMessage, _T("_CHAR_"), _T("char"));
#endif

        std::vector<std::tstring> expectedMessages, messages;

        //Critical & Error pass through all 3 filters
        for ( int i = 0 ; i < 3 ; i++ )
            expectedMessages += boost::algorithm::replace_all_copy(
                boost::algorithm::replace_all_copy(baseExpectedMessage, _T("_LOGLEVEL_"), _T(" CRITICAL")),
                                                                        _T("_LINE_"),     lineNumberVector[0]);
        
        for ( int i = 0 ; i < 3 ; i++ )
            expectedMessages += boost::algorithm::replace_all_copy(
                boost::algorithm::replace_all_copy(baseExpectedMessage, _T("_LOGLEVEL_"), _T("    ERROR")),
                                                                        _T("_LINE_"),     lineNumberVector[1]);
        
        //Warning, Debug & Info are filtered by MyFilter2
        for ( int i = 0 ; i < 2 ; i++ )
            expectedMessages += boost::algorithm::replace_all_copy(
                boost::algorithm::replace_all_copy(baseExpectedMessage, _T("_LOGLEVEL_"), _T("  WARNING")),
                                                                        _T("_LINE_"),     lineNumberVector[2]);
        
        for ( int i = 0 ; i < 2 ; i++ )
            expectedMessages += boost::algorithm::replace_all_copy(
                boost::algorithm::replace_all_copy(baseExpectedMessage, _T("_LOGLEVEL_"), _T("    DEBUG")),
                                                                        _T("_LINE_"),     lineNumberVector[3]);
        
        for ( int i = 0 ; i < 2 ; i++ )
            expectedMessages += boost::algorithm::replace_all_copy(
                boost::algorithm::replace_all_copy(baseExpectedMessage, _T("_LOGLEVEL_"), _T("     INFO")),
                                                                        _T("_LINE_"),     lineNumberVector[4]);
        
        BOOST_FOREACH(std::tstring message, m_testLogManager.GetMessages())
        {
            messages += boost::algorithm::erase_head_copy(message, 11);
        }

        TS_ASSERT_EQUALS(expectedMessages, messages);
    }

    void tearDown()
    {
        BOOST_FOREACH(GenericLogPrinter<std::tstring>* logPrinter, m_logPrintersToCleanup)
        {
            logPrinter->m_LogManagers.pop_back();
        }
    }
};

}
}
}

using namespace Nvidia::Logging::Test;