#if _MSC_VER > 1000
  #pragma once
#endif // _MSC_VER > 1000

#ifndef __TraceScope_h__
#define __TraceScope_h__


/////////////////////////////////////////////////////////////////////////////
//
class TCTraceScope
{
// Group=Construction / Destruction
public:
  TCTraceScope(LPCSTR pszClass, LPCSTR pszMethod, LPCSTR pszFmt = NULL, ...);

#ifdef _DEBUG
  ~TCTraceScope();

  // Group=Implementation
  protected:
    static DWORD TlsIndex();

  // Group=Data Members
  protected:
    LPCSTR m_pszClass;
    LPCSTR m_pszMethod;
#endif
};


#ifdef _DEBUG

  ///////////////////////////////////////////////////////////////////////////
  // Group=Construction / Destruction

  inline TCTraceScope::TCTraceScope(LPCSTR pszClass, LPCSTR pszMethod,
    LPCSTR pszFmt, ...) : m_pszClass(pszClass), m_pszMethod(pszMethod)
  {
    assert(pszMethod);

    // Get the indent level and increment it
    int nIndent = (int)(::TlsGetValue(TlsIndex()));
    ::TlsSetValue(TlsIndex(), LPVOID(nIndent + 1));

    // Create the formatting string
    char szFmt[_MAX_PATH] = "";
    for (int i = 0; i < nIndent; ++i)
      strcat(szFmt, "  ");
    if (m_pszClass)
    {
      strcat(szFmt, m_pszClass);
      strcat(szFmt, "::");
    }
    strcat(szFmt, m_pszMethod);
    strcat(szFmt, "()");
    if (pszFmt && strlen(pszFmt))
    {
      strcat(szFmt, ": ");
      strcat(szFmt, pszFmt);
    }
    strcat(szFmt, "\n");
    for (i = 0; i < nIndent; ++i)
      strcat(szFmt, "  ");
    strcat(szFmt, "{\n");

    // Format the message string
    va_list vaArgs;
    va_start(vaArgs, pszFmt);
    char szMsg[_MAX_PATH];
    _vsnprintf(szMsg, sizeofArray(szMsg), szFmt, vaArgs);
    va_end(vaArgs);

    // Output the message string
    OutputDebugStringA(szMsg);
  }

  inline TCTraceScope::~TCTraceScope()
  {
    // Get the indent level and decrement it
    int nIndent = (int)(::TlsGetValue(TlsIndex()));
    ::TlsSetValue(TlsIndex(), LPVOID(--nIndent));

    // Create the indent string
    int cchIndent = nIndent * 2;
    LPSTR pszIndent = (LPSTR)_alloca(cchIndent + 1);
    memset(pszIndent, ' ', cchIndent);
    pszIndent[cchIndent] = '\0';

    // Create the message string
    char szMsg[_MAX_PATH] = "";
    if (m_pszClass)
      _snprintf(szMsg, sizeofArray(szMsg), "%hs} // %hs::%hs\n", pszIndent,
        m_pszClass, m_pszMethod);
    else
      _snprintf(szMsg, sizeofArray(szMsg), "%hs} // %hs\n", pszIndent,
        m_pszMethod);

    // Output the message string
    OutputDebugStringA(szMsg);
  }

  ///////////////////////////////////////////////////////////////////////////
  // Group=Implementation

  inline DWORD TCTraceScope::TlsIndex()
  {
    static DWORD dwTlsIndex = ::TlsAlloc();
    return dwTlsIndex;
  }

#else // _DEBUG

  inline TCTraceScope::TCTraceScope(LPCSTR, LPCSTR, LPCSTR, ...)
  {
  }

#endif // _DEBUG


/////////////////////////////////////////////////////////////////////////////
// Macros

#ifdef _DEBUG

  #define _TSCOPE(cls, fn, msg) \
    TCTraceScope mctscope(#cls, #fn, msg);

  #define _TSCOPE0(cls, fn) \
    TCTraceScope mctscope(#cls, #fn);

  #define _TSCOPE1(cls, fn, msg, p1) \
    TCTraceScope mctscope(#cls, #fn, msg, p1);

  #define _TSCOPE2(cls, fn, msg, p1, p2) \
    TCTraceScope mctscope(#cls, #fn, msg, p1, p2);

  #define _TSCOPE3(cls, fn, msg, p1, p2, p3) \
    TCTraceScope mctscope(#cls, #fn, msg, p1, p2, p3);

  #define _TSCOPE4(cls, fn, msg, p1, p2, p3, p4) \
    TCTraceScope mctscope(#cls, #fn, msg, p1, p2, p3, p4);

  #define _TSCOPE5(cls, fn, msg, p1, p2, p3, p4, p5) \
    TCTraceScope mctscope(#cls, #fn, msg, p1, p2, p3, p4, p5);

#else // _DEBUG

  #define _TSCOPE(cls, fn, msg)
  #define _TSCOPE0(cls, fn)
  #define _TSCOPE1(cls, fn, msg, p1)
  #define _TSCOPE2(cls, fn, msg, p1, p2)
  #define _TSCOPE3(cls, fn, msg, p1, p2, p3)
  #define _TSCOPE4(cls, fn, msg, p1, p2, p3, p4)
  #define _TSCOPE5(cls, fn, msg, p1, p2, p3, p4, p5)

#endif // _DEBUG



/////////////////////////////////////////////////////////////////////////////

#endif // !__TraceScope_h__