/*
 *  DEBUG code - Contains declarations and macros for include debug support;
 *       Contains null definitions when !_DEBUG
 */

#ifndef _DEBUG_H_
#define _DEBUG_H_

#ifndef RC_INVOKED
#ifdef _DEBUG
#define DBGSTATE " Debug is on"
#else
#define DBGSTATE " Debug is off"
#endif
#endif  /* RC_INVOKED */

#include <ole2dbg.h>

//these are bogus APIs (they do nothing)
STDAPI_(BOOL) ValidateAllObjects( BOOL fSuspicious );
STDAPI_(void) DumpAllObjects( void );

#ifdef _DEBUG
BOOL InstallHooks(void);
BOOL UnInstallHooks(void);

#undef ASSERTDATA
#ifdef _MAC
#ifdef __cplusplus
extern "C" {
#endif
void OutputDebugString(const char *);
#ifdef __cplusplus
}
#endif
#endif

#define ASSERTDATA  static char  _szAssertFile[]= __FILE__;

#undef Assert
// MAC compiler barfs on '(void)0'.
#ifdef _MAC
#define Assert(a) { if (!(a)) FnAssert(#a, NULL, _szAssertFile, __LINE__); }
#undef AssertSz
#define AssertSz(a, b) { if (!(a)) FnAssert(#a, b, _szAssertFile, __LINE__); }
#else
#undef AssertSz
#define AssertSz(a,b) ((a) ? NOERROR : FnAssert(#a, b, _szAssertFile, __LINE__))
#endif
#undef Verify
#define Verify(a)   Assert(a)
#undef Puts
#define Puts(s) OutputDebugString(s)

#define ASSERT(cond, msg)

#else   //  !_DEBUG

#define ASSERTDATA
#define Assert(a)
#define AssertSz(a, b)
#define Verify(a) (a)
#define ASSERT(cond, msg)
#define Puts(s)

#endif  //  _DEBUG

#ifdef __cplusplus

interface IDebugStream;

/*
 *  Class CBool wraps boolean values in such a way that they are
 *  readily distinguishable fron integers by the compiler so we can
 *  overload the stream << operator.
 */

class FAR CBool
{
    BOOL value;
public:
    CBool (BOOL& b) {value = b;}
    operator BOOL( void ) { return value; }
};


/*
 *  Class CHwnd wraps HWND values in such a way that they are
 *  readily distinguishable from UINTS by the compiler so we can
 *  overload the stream << operator
 */

class FAR CHwnd
{
	HWND m_hwnd;
	public:
		CHwnd (HWND hwnd) {m_hwnd = hwnd; }
		operator HWND( void ) {return m_hwnd;}
};

/*
 * Class CAtom wraps ATOM values in such a way that they are
 *  readily distinguishable from UINTS by the compiler so we can
 *  overload the stream << operator
 */

class FAR CAtom
{
	ATOM m_atom;
	public:
		CAtom (ATOM atom) {m_atom = atom; }
		operator ATOM( void ) {return m_atom; }
};

/*
 *  IDebugStream is a stream to be used for debug output.  One
 *  implementation uses the OutputDebugString function of Windows.
 *
 *  The style is modeled on that of AT&T streams, and so uses
 *  overloaded operators.  You can write to a stream in the
 *  following ways:
 *
 *    *pdbstm << pUnk;  // calls the IDebug::Dump function to
 *                      display the object, if IDebug is supported.
 *    int n;
 *    *pdbstm << n;     // writes n in decimal
 *
 *    LPSTR sz;
 *    *pdbstm << sz;    // writes a string
 *
 *    CBool b(TRUE);
 *    *pdbstm << b;     // writes True or False
 *
 *    void FAR * pv;
 *    *pdbstm << pv;    // writes the address pv in hex
 *
 *    char ch;
 *    *pdbstm << ch;    // writes the character
 *
 *    ATOM atom;
 *    *pdbstm << CAtom(atom);	// writes the string extracted from the atom
 *
 *    HWND hwnd;
 *    *pdbstm << CHwnd(hwnd);  // writes the info about a window handle
 *
 *  These can be chained together, as such (somewhat artificial
 *  example):
 *
 *    REFCLSID rclsid;
 *    pUnk->GetClass(&rclsid);
 *    *pdbstm << rclsid << " at " << (void FAR *)pUnk <<':' << pUnk;
 *
 *  This produces something like:
 *
 *    CFoo at A7360008: <description of object>
 *
 *  The other useful feature is the Indent and UnIndent functions
 *  which allow an object to print some information, indent, print
 *  the info on its member objects, and unindent.  This gives
 *  nicely formatted output.
 *
 *  WARNING:  do not (while implementing Dump) write
 *
 *    *pdbstm << pUnkOuter
 *
 *  since this will do a QueryInterface for IDebug, and start
 *  recursing!  It is acceptable to write
 *
 *    *pdbstm << (VOID FAR *)pUnkOuter
 *
 *  as this will simply write the address of pUnkOuter.
 *
 */


interface IDebugStream : public IUnknown
{
    STDMETHOD_(IDebugStream&, operator << ) ( IUnknown FAR * pDebug ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( REFCLSID rclsid ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( int n ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( long l ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( ULONG l ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( LPSTR sz ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( char ch ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( void FAR * pv ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( CBool b ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( CHwnd hwnd ) = 0;
    STDMETHOD_(IDebugStream&, operator << ) ( CAtom atom ) = 0;
    STDMETHOD_(IDebugStream&, Tab )( void ) = 0;
    STDMETHOD_(IDebugStream&, Indent )( void ) = 0;
    STDMETHOD_(IDebugStream&, UnIndent )( void ) = 0;
    STDMETHOD_(IDebugStream&, Return )( void ) = 0;
    STDMETHOD_(IDebugStream&, LF )( void ) = 0;
};

STDAPI_(IDebugStream FAR*) MakeDebugStream( short margin=70, short tabsize=4, BOOL fHeader=1);


interface IDebug
{
    STDMETHOD_(void, Dump )( IDebugStream FAR * pdbstm ) = 0;
    STDMETHOD_(BOOL, IsValid )( BOOL fSuspicious = FALSE ) = 0;

#ifdef NEVER
    __export IDebug(void);
    __export ~IDebug(void);
private:

#if _DEBUG
    IDebug FAR * pIDPrev;
    IDebug FAR * pIDNext;

    friend void STDAPICALLTYPE DumpAllObjects( void );
    friend BOOL STDAPICALLTYPE ValidateAllObjects( BOOL fSuspicious );
#endif
#endif
};


#ifdef _MAC
typedef short HFILE;
#endif


/*************************************************************************
** The following functions can be used to log debug messages to a file
**    and simutaneously write them to the dbwin debug window.
**    The CDebugStream implementation automatically writes to a debug
**    log file called "debug.log" in the current working directory.
**    NOTE: The functions are only intended for C programmers. C++
**    programmers should use the "MakeDebugStream" instead.
*************************************************************************/

// Open a log file.
STDAPI_(HFILE) DbgLogOpen(LPSTR lpszFile, LPSTR lpszMode);

// Close the log file.
STDAPI_(void) DbgLogClose(HFILE fh);

// Write to debug log and debug window (used with cvw.exe or dbwin.exe).
STDAPI_(void) DbgLogOutputDebugString(HFILE fh, LPSTR lpsz);

// Write to debug log only.
STDAPI_(void) DbgLogWrite(HFILE fh, LPSTR lpsz);

// Write the current Date and Time to the log file.
STDAPI_(void) DbgLogTimeStamp(HFILE fh, LPSTR lpsz);

// Write a banner separater to the log to separate sections.
STDAPI_(void) DbgLogWriteBanner(HFILE fh, LPSTR lpsz);




/*
 *  STDDEBDECL macro - helper for debug declaration
 *
 */

#ifdef _DEBUG

    #ifdef _MAC

        //#define STDDEBDECL(cclassname,classname)

        //#if 0
        #define STDDEBDECL(cclassname,classname) NESTED_CLASS(cclassname, CDebug):IDebug { public: \
            NC1(cclassname,CDebug)( cclassname FAR * p##classname ) { m_p##classname = p##classname;} \
            ~##NC1(cclassname,CDebug)(void){} \
            STDMETHOD_(void, Dump)(THIS_ IDebugStream FAR * pdbstm ); \
            STDMETHOD_(BOOL, IsValid)(THIS_ BOOL fSuspicious ); \
            private: cclassname FAR* m_p##classname; }; \
            DECLARE_NC2(cclassname, CDebug) \
            NC(cclassname, CDebug) m_Debug;
        //#endif

        #else  // _MAC

        #define STDDEBDECL(ignore, classname ) implement CDebug:public IDebug { public: \
            CDebug( C##classname FAR * p##classname ) { m_p##classname = p##classname;} \
            ~CDebug(void) {} \
            STDMETHOD_(void, Dump)(IDebugStream FAR * pdbstm ); \
            STDMETHOD_(BOOL, IsValid)(BOOL fSuspicious ); \
            private: C##classname FAR* m_p##classname; }; \
            DECLARE_NC(C##classname, CDebug) \
            CDebug m_Debug;
    #endif

    //#ifdef _MAC
    //#define CONSTRUCT_DEBUG
    //#else
    #define CONSTRUCT_DEBUG m_Debug(this),
    //#endif

#else //        _DEBUG

//      no debugging
#define STDDEBDECL(cclassname,classname)
#define CONSTRUCT_DEBUG

#endif  //      _DEBUG

#endif __cplusplus

#endif !_DEBUG_H_