/**
 * @file ILogContentsPrinter.h
 * @author Bartosz Janiak
 * 
 * @brief Contains the definition of LogContentsPrinter abstract class.
 *
 * 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 "Loggable.h"
#include "CompositeLoggable.h"
#include "GenericSimpleLoggable.h"
#include "VectorLoggable.h"
#include "LoggableTraits.h"

#include "TStd.h"
#include <vector>

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>

namespace Nvidia {
namespace Logging {

/**
 * @brief Base class for objects responsible for formatting separate Loggable%s.
 *
 * Implementations of this abstract class are be responsible for formatting separate
 * Loggables (as opposed to printing and formatting the whole log message contained
 * in ChainLoggable, which is the responsibility of ILogPrinter).
 */
class LogContentsPrinter
{
public:
    /**
    * @brief Logs the value with provided name on this LogContentsPrinter.
    *
    * This should be called for all CompositeLoggable components in
    * CompositeLoggable::LogContentsOn().
    * @param name Name of the value. This should represent the role that the value has
    * for the caller, for example it should be the name of the field when called from CompositeLoggable
    * implementation, or an index when called from VectorLoggable.
    * @param value The value which should be logged.
    */
    template<typename T>
    void LogContent(const TCHAR* name, T value)
    {
        LogContentInternal(std::tstring(name), value);
    }

    /**
    * @brief Logs the value with provided name on this LogContentsPrinter.
    *
    * This should be called for all CompositeLoggable components in
    * CompositeLoggable::LogContentsOn().
    * @param name Name of the value. This should represent the role that the value has
    * for the caller, for example it should be the name of the field when called from CompositeLoggable
    * implementation, or an index when called from VectorLoggable.
    * @param value The value which should be logged.
    */
    template<typename T>
    void LogContent(const std::tstring& name, T value)
    {
        LogContentInternal(name, value);
    }

protected:
    /**
     * @brief Implementation of this method should save the result of formatting this SimpleLoggable
     * into the LogContentsPrinter state.
     */
    virtual void LogContentInternal(const std::tstring& name, const SimpleLoggable& loggable) = 0;

    /**
     * @brief Implementation of this method should save the result of formatting this CompositeLoggable
     * into the LogContentsPrinter state.
     */
    virtual void LogContentInternal(const std::tstring& name, const CompositeLoggable& loggable) = 0;

    /// @brief Helper method to convert simple types into GenericSimpleLoggable on the fly.
    template<typename T>
    void LogContentInternal(const std::tstring& name, T value,
        typename boost::disable_if_c<boost::is_base_of<Loggable, T>::value, T>::type* = 0)
    {
        typename LoggableTraits<T>::LoggableType loggable(value);
        LogContentInternal(name, loggable);
    }

    /// @brief Helper method to convert std::vector into VectorLoggable on the fly.
    template<typename T>
    void LogContentInternal(const std::tstring& name, const std::vector<T>& value)
    {
        LogContentInternal(name, MakeVectorLoggable(value.begin(), value.end()));
    }
};

}
}