/**
 * @file LoggerConstructorTest.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 GenerateRegistry : public CxxTest::GlobalFixture
{
public:
    virtual bool setUpWorld()
    {
        BYTE buf[1] = {0};
        RegistryKey logging(HKEY_LOCAL_MACHINE, _T("Software\\NVIDIA Corporation\\Logging"), KEY_WRITE | KEY_READ, true);
        RegistryKey definitions = logging.CreateSubKey(_T("Definitions"));
        RegistryKey logChannels = definitions.CreateSubKey(_T("LogChannels"));

        RegistryKey testChannel = logChannels.CreateSubKey(_T("TestChannel"));
        testChannel.SetStringValue(_T("LogFilter"), _T("MyFilter"));
        testChannel.SetStringValue(_T("LogPrinter"), _T("TestPrinter"));
        RegistryKey logManagers1 = testChannel.CreateSubKey(_T("LogManagers"));
        logManagers1.SetBinaryValue(_T("MyManager"), buf, 0);
        logManagers1.SetBinaryValue(_T("MyManager2"), buf, 0);
        RegistryKey testChannel2 = logChannels.CreateSubKey(_T("TestChannel2"));
        testChannel2.SetStringValue(_T("LogFilter"), _T("MyFilter2"));
        testChannel2.SetStringValue(_T("LogPrinter"), _T("TestPrinter"));
        RegistryKey logManagers2 = testChannel2.CreateSubKey(_T("LogManagers"));
        logManagers2.SetBinaryValue(_T("MyManager"), buf, 0);
        logManagers2.SetBinaryValue(_T("MyManager2"), buf, 0);
        RegistryKey testChannel3 = logChannels.CreateSubKey(_T("TestChannel3"));
        testChannel3.SetStringValue(_T("LogFilter"), _T("MyFilter"));
        testChannel3.SetStringValue(_T("LogPrinter"), _T("TestPrinter2"));
        RegistryKey logManagers3 = testChannel3.CreateSubKey(_T("LogManagers"));
        logManagers3.SetBinaryValue(_T("MyManager"), buf, 0);
        logManagers3.SetBinaryValue(_T("MyManager2"), buf, 0);
        RegistryKey testChannel4 = logChannels.CreateSubKey(_T("TestChannel4"));
        testChannel4.SetStringValue(_T("LogFilter"), _T("MyFilter"));
        testChannel4.SetStringValue(_T("LogPrinter"), _T("NoSuchPrinter"));
        RegistryKey logManagers4 = testChannel4.CreateSubKey(_T("LogManagers"));
        logManagers4.SetBinaryValue(_T("MyManager"), buf, 0);
        logManagers4.SetBinaryValue(_T("MyManager2"), buf, 0);
        RegistryKey testChannel5 = logChannels.CreateSubKey(_T("TestChannel5"));
        testChannel5.SetStringValue(_T("LogFilter"), _T("NoSuchFilter"));
        testChannel5.SetStringValue(_T("LogPrinter"), _T("TestPrinter"));
        RegistryKey logManagers5 = testChannel5.CreateSubKey(_T("LogManagers"));
        logManagers5.SetBinaryValue(_T("MyManager"), buf, 0);
        logManagers5.SetBinaryValue(_T("MyManager2"), buf, 0);
        RegistryKey testChannel6 = logChannels.CreateSubKey(_T("TestChannel6"));
        testChannel6.SetStringValue(_T("LogFilter"), _T("MyFilter"));
        testChannel6.SetStringValue(_T("LogPrinter"), _T("TestPrinter"));
        RegistryKey logManagers6 = testChannel6.CreateSubKey(_T("LogManagers"));
        logManagers6.SetBinaryValue(_T("NoSuchManager"), buf, 0);

        RegistryKey logFilters = definitions.CreateSubKey(_T("LogFilters"));
        RegistryKey testFilter = logFilters.CreateSubKey(_T("TestFilter"));
        testFilter.SetDWORDValue(_T("DefaultLogLevel"), 0x00000001);
        RegistryKey originRules = testFilter.CreateSubKey(_T("OriginRules"));
        originRules.SetDWORDValue(_T("One"), 0x00000004);
        originRules.SetDWORDValue(_T("Two"), 0x00000006);
        originRules.SetDWORDValue(_T("Two.B"), 0x00000003);
        originRules.SetDWORDValue(_T("Three"), 0x00000002);
        originRules.SetDWORDValue(_T("Three.C"), 0x00000005);
        originRules.SetDWORDValue(_T("Four.D.1234.!@#$%^&*()-+"), 0x00000005);

        RegistryKey myFilter = logFilters.CreateSubKey(_T("MyFilter"));
        myFilter.SetDWORDValue(_T("DefaultLogLevel"), 0x00000006);
        RegistryKey originRules2 = myFilter.CreateSubKey(_T("OriginRules"));
        RegistryKey myFilter2 = logFilters.CreateSubKey(_T("MyFilter2"));
        myFilter2.SetDWORDValue(_T("DefaultLogLevel"), 0x00000003);
        RegistryKey originRules3 = myFilter2.CreateSubKey(_T("OriginRules"));

        RegistryKey logManagers = definitions.CreateSubKey(_T("LogManagers"));
        RegistryKey myManager1 = logManagers.CreateSubKey(_T("MyManager"));
        myManager1.SetStringValue(_T("ClassName"), _T("DebugOutputLogManager"));
        RegistryKey myManager2 = logManagers.CreateSubKey(_T("MyManager2"));
        myManager2.SetStringValue(_T("ClassName"), _T("NoSuchManagerClass"));
        RegistryKey myManager3 = logManagers.CreateSubKey(_T("MyManager3"));
        myManager3.SetStringValue(_T("ClassName"), _T("FileLogManager"));
        myManager3.SetStringValue(_T("PathPrefix"), _T("c:\\testLogging\\moreTest\\test"));
        myManager3.SetDWORDValue(_T("AppendProcessNameToPathPrefix"), 0x00000001);
        myManager3.SetDWORDValue(_T("MaxFileCount"), 0x00000003);
        myManager3.SetDWORDValue(_T("MaxFileSize"), 0x00001000);

        RegistryKey logPrinters = definitions.CreateSubKey(_T("LogPrinters"));
        RegistryKey testPrinter1 = logPrinters.CreateSubKey(_T("TestPrinter"));
        RegistryKey testPrinter2 = logPrinters.CreateSubKey(_T("TestPrinter2"));
        RegistryKey testPrinter3 = logPrinters.CreateSubKey(_T("TestPrinter3"));
        testPrinter1.SetStringValue(_T("ClassName"), _T("SimpleTextLogPrinter"));
        testPrinter2.SetStringValue(_T("ClassName"), _T("NoSuchPrinterClass"));
        testPrinter3.SetStringValue(_T("ClassName"), _T("XMLLogPrinter"));
        testPrinter3.SetDWORDValue(_T("MaxPrintingDepth"), 0x00000005);

        RegistryKey processes = logging.CreateSubKey(_T("Processes"));
        RegistryKey loggingTest = processes.CreateSubKey(_T("LoggingTest.exe"));
        RegistryKey loggingTestChannels = loggingTest.CreateSubKey(_T("LogChannels"));
        loggingTestChannels.SetBinaryValue(_T("TestChannel"), buf, 0);
        loggingTestChannels.SetBinaryValue(_T("TestChannel2"), buf, 0);
        loggingTestChannels.SetBinaryValue(_T("TestChannel3"), buf, 0);
        loggingTestChannels.SetBinaryValue(_T("TestChannel4"), buf, 0);
        loggingTestChannels.SetBinaryValue(_T("TestChannel5"), buf, 0);
        loggingTestChannels.SetBinaryValue(_T("TestChannel6"), buf, 0);
        loggingTestChannels.SetBinaryValue(_T("NoSuchChannel"), buf, 0);

        RegistryKey testRegistry(HKEY_LOCAL_MACHINE, _T("Software\\NVIDIA Corporation\\TestRegistryKey"), KEY_WRITE | KEY_READ, true);
        testRegistry.SetStringValue(_T("StringValue"), _T("abcDEF"));
        testRegistry.SetStringValue(_T("StringValue2"), _T("foobarFOOBARfoobar"));
        testRegistry.SetDWORDValue(_T( "DwordValue"), 0x0F008AF0);
        testRegistry.SetDWORDValue(_T("DwordValue2"), 0xF0F00F0F);
        testRegistry.SetBinaryValue(_T("BinaryValue"), buf, 0);
        testRegistry.SetStringValue(_T("OneByteStringValue"), _T("P"));

        RegistryKey subkeyShort(HKEY_LOCAL_MACHINE, _T("Software\\NVIDIA Corporation\\TestRegistryKey\\SubKeyShort"), KEY_READ | KEY_WRITE, true);
        RegistryKey subkeyLong(HKEY_LOCAL_MACHINE, _T("Software\\NVIDIA Corporation\\TestRegistryKey\\SubKeyLoooooooooooooooooooooooooooooooooong"), KEY_READ | KEY_WRITE, true);
        RegistryKey subkeyShort2(HKEY_LOCAL_MACHINE, _T("Software\\NVIDIA Corporation\\TestRegistryKey\\SubKeyShort2"), KEY_READ | KEY_WRITE, true);
        return true;
    }
};

static GenerateRegistry RegistryGenerator;

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

    void TestConstructor()
    {
        Logger& logger = Logger::GetLogger();
        TS_ASSERT_EQUALS(logger.m_filtersAndPrinters.size(), 3);
        
        SimpleTextLogPrinter* printers[3];
        std::multiset<size_t> expectedManagerCounts, managerCounts;
        std::vector<DebugOutputLogManager*> managers;
        expectedManagerCounts += 1, 1, 0;        

        for ( int i = 0 ; i < 3 ; i++ )
        {
            printers[i] = dynamic_cast<SimpleTextLogPrinter*>(logger.m_filtersAndPrinters[i].second);
            TS_ASSERT(printers[i]);
            managerCounts += printers[i]->m_LogManagers.size();
            if ( printers[i]->m_LogManagers.size() == 1 )
            {
                DebugOutputLogManager* manager = dynamic_cast<DebugOutputLogManager*>(printers[i]->m_LogManagers[0]);
                TS_ASSERT(manager);
                managers.push_back(manager);
            }
        }

        TS_ASSERT_EQUALS(expectedManagerCounts, managerCounts);
        TS_ASSERT_EQUALS(managers[0], managers[1]);

        std::multiset<LogLevel> expectedMaxLogLevels, maxLogLevels;
        expectedMaxLogLevels += LogLevel_Info, LogLevel_Info, LogLevel_Error;

        maxLogLevels += logger.m_filtersAndPrinters[0].first->GetMaximumLogLevel(_T(""));
        maxLogLevels += logger.m_filtersAndPrinters[1].first->GetMaximumLogLevel(_T(""));
        maxLogLevels += logger.m_filtersAndPrinters[2].first->GetMaximumLogLevel(_T(""));

        TS_ASSERT_EQUALS(maxLogLevels, expectedMaxLogLevels);
    }

};

}
}
}

using namespace Nvidia::Logging::Test;