/*
* Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:   Interface of debugging utilities.
*
*/



#ifndef RUBYDEBUG_H
#define RUBYDEBUG_H

#include "rubydebugcfg.h"

//  INCLUDES
#include <e32svr.h> // For RDebug

#ifndef RUBY_DISABLE_FUNCTION_NAMES
    // No sense to store function name longer, than can be printed
    // 0x100 is the internal RDebug limit
    const TInt __K_RUBY_FUNCTION_NAME_LENGTH = 0x50;    

    // Prepares function name for printing
    #define __RUBY_PREPARE_FUNCTION_NAME \
    TBuf<__K_RUBY_FUNCTION_NAME_LENGTH> __ruby_function_name__;\
    __ruby_function_name__.Copy( TPtrC8( (TText8*)&__PRETTY_FUNCTION__ ).Left( __K_RUBY_FUNCTION_NAME_LENGTH ) ); \

    // Token to paste the function name into
    #define __K_RUBY_FUNCTION_NAME_TOKEN "%S "
    
    // Comma and function name
    #define __RUBY_FUNCTION_NAME __ruby_function_name__
    
    // A wrapper that prepares and supplies the function name as __ruby_function_name__
    #define __RUBY_FUNCTION_NAMED( text ) \
	    {\
	    __RUBY_PREPARE_FUNCTION_NAME;\
	    text;\
	    }
	    
	#define __RUBY_FUNCTION_NAME_POINTER8 (TText8*)&__PRETTY_FUNCTION__
    

#else  // RUBY_DISABLE_FUNCTION_NAMES

    #define __RUBY_PREPARE_FUNCTION_NAME
    
    // Don't print the function name
    #define __K_RUBY_FUNCTION_NAME_TOKEN ""
    
    // exclude the whole token, with the comma
    #define __RUBY_FUNCTION_NAME KNullDesC
    
    // no wrapping
    #define __RUBY_FUNCTION_NAMED( text ) text
    
    #define __RUBY_FUNCTION_NAME_POINTER8 NULL

#endif // RUBY_DISABLE_FUNCTION_NAMES

// Macro for printing filename both in unicode and non-unicode builds


#ifdef _UNICODE
	#define __RUBY_WIDEN2(x) L ## x
	#define __RUBY_WIDEN(x) __RUBY_WIDEN2(x)
	#define __RUBY_DBG_FILE__ __RUBY_WIDEN(__FILE__)
#else
	#define __RUBY_DBG_FILE__ __FILE__
#endif//_UNICODE



// Debugging is enabled only in _DEBUG builds
//#ifdef _DEBUG 

// Select the debug output method
#ifndef __RUBY_DEBUG_TRACES_TO_FILE
#define RUBY_DEBUG_METHOD RDebug::Print
#else
#define RUBY_DEBUG_METHOD RRubyDebug::PrintToFile
#endif // __RUBY_DEBUG_TRACES_TO_FILE

//#endif // _DEBUG

#if defined(_DEBUG) && !defined(__RUBY_DEBUG_DISABLED)

//	#define RUBY_DEBUG_BLOCK(text) \
//  	RRubyDebug trace_trace( _S(text), _S("" ## __RUBY_DBG_FILE__) , __LINE__, EFalse ); \
//  	CleanupReleasePushL( trace_trace )
  	
//  	#define RUBY_DEBUG_BLOCKL(text) \
//  	RRubyDebug trace_trace( _S(text), _S("" ## __RUBY_DBG_FILE__), __LINE__, ETrue ); \
//  	CleanupReleasePushL( trace_trace )
// A temporary fix to cope with builds on RVCT 530. It didn't compile with _RUBY_DBG_FILE
	#define RUBY_DEBUG_BLOCK(text) \
  	RRubyDebug trace_trace( _S(text), _S("") , __LINE__, EFalse, __RUBY_FUNCTION_NAME_POINTER8 ); \
  	CleanupReleasePushL( trace_trace )

  	#define RUBY_DEBUG_BLOCKL(text) \
  	RRubyDebug trace_trace( _S(text), _S(""), __LINE__, ETrue, __RUBY_FUNCTION_NAME_POINTER8 ); \
  	CleanupReleasePushL( trace_trace )

	#define RUBY_DEBUG0(text) \
        __RUBY_FUNCTION_NAMED( RUBY_DEBUG_METHOD( _L("%S %S "L##text L## " [L:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, __LINE__ ) )

    #define RUBY_DEBUG1(text, p1) \
        __RUBY_FUNCTION_NAMED( RUBY_DEBUG_METHOD( _L("%S %S "L##text L## " [L:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, p1, __LINE__ ) )

    #define RUBY_DEBUG2(text, p1, p2) \
        __RUBY_FUNCTION_NAMED( RUBY_DEBUG_METHOD( _L("%S %S "L##text L## " [L:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, p1, p2, __LINE__ ) )

    #define RUBY_DEBUG3(text, p1, p2, p3) \
        __RUBY_FUNCTION_NAMED( RUBY_DEBUG_METHOD( _L("%S %S "L##text L## " [L:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, p1, p2, p3, __LINE__ ) )


#else // Debugging disabled

	// Macros expand to nothing:
	#define RUBY_DEBUG_BLOCK(text)
	#define RUBY_DEBUG0(text)    
	#define RUBY_DEBUG1(text, p1)
	#define RUBY_DEBUG2(text, p1, p2)
    #define RUBY_DEBUG3(text, p1, p2, p3)
	#define RUBY_DEBUG_BLOCKL(text)

#endif // defined(_DEBUG) && !defined(__RUBY_DEBUG_DISABLED)

#if !defined(RUBY_DISABLE_ERRORS) || defined(_DEBUG)
	// if error messages are allowed (even for UREL)
	#define RUBY_ERROR0(text) \
	__RUBY_FUNCTION_NAMED( \
	    RUBY_DEBUG_METHOD( _L("%S[Error!] %S "L##text L## " [F:%s][L:%d][TId:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, __RUBY_DBG_FILE__, __LINE__, TUint(RThread().Id()) )\
	)

	#define RUBY_ERROR1(text, p1) \
	__RUBY_FUNCTION_NAMED( \
	RUBY_DEBUG_METHOD( _L("%S[Error!] %S "L##text L## " [F:%s][L:%d][TId:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, p1, __RUBY_DBG_FILE__, __LINE__, TUint(RThread().Id()) )\
	)

	#define RUBY_ERROR2(text, p1, p2) \
	__RUBY_FUNCTION_NAMED( \
	RUBY_DEBUG_METHOD( _L("%S[Error!] %S "L##text L## " [F:%s][L:%d][TId:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, p1, p2, __RUBY_DBG_FILE__, __LINE__, TUint(RThread().Id()) )\
	)
#else
	// error reporting disabled
	// Macros expand to nothing:
	#define RUBY_ERROR_BLOCK(text)
	#define RUBY_ERROR0(text)    
	#define RUBY_ERROR1(text, p1)
	#define RUBY_ERROR2(text, p1, p2)
#endif  // !defined(RUBY_DISABLE_ERRORS)

#if !defined(RUBY_DISABLE_ASSERT_DEBUG) || defined(_DEBUG)
	#define RUBY_ASSERT_DEBUG(condition, action) \
	  __RUBY_FUNCTION_NAMED(\
		__ASSERT_ALWAYS( condition, RUBY_DEBUG_METHOD(  _L("%S[Error!] %S [Assert failed!] "L###condition L## " [F:%s][L:%d][TId:%d]"), &__K_RUBY_HEADER, &__RUBY_FUNCTION_NAME, __RUBY_DBG_FILE__, __LINE__, TUint(RThread().Id())) ); \
		__ASSERT_DEBUG( (condition), (action) )\
	  );
#else
	// Macro expands to default:
	#define RUBY_ASSERT_DEBUG(condition, action) __ASSERT_DEBUG(condition,action)
#endif

// Same as TRAP_IGNORE, but in case of leave, prints the leave code via RUBY_ERROR
// Can be disabled by RUBY_DISABLE_TRAP_IGNORE or RUBY_DISABLE_ERRORS
// If disabled, is equivalent to TRAP_IGNORE
// @see rubydebugcfg.h
#ifndef RUBY_DISABLE_TRAP_IGNORE 
    #define RUBY_TRAP_IGNORE( s ) \
        {\
        TRAPD( err, s );\
        if( err != KErrNone )\
            {\
            RUBY_ERROR1( "RUBY_TRAP_IGNORE leaves with [%d]", err );\
            }\
        }
#else  // RUBY_DISABLE_TRAP_IGNORE 
    #define RUBY_TRAP_IGNORE( s ) TRAP_IGNORE( s )
#endif  // RUBY_DISABLE_TRAP_IGNORE 

// DATA TYPES

// FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// CLASS DECLARATION

/**
*  Debug class for printing START, EXIT and LEAVE messages to RDebug in every 
*  code block. Must be placed in the very beginning of a code block and the
*  code block cannot leave items in the cleanup stack (like NewLC). 
*
*  @since Series 60 2.8
*
*  @note If this object is not the topmost item when a code block is exited, 
*        E32USER-CBase 90 panic is raised (@see CleanupStack::Pop( TAny* )).
*/
class RRubyDebug
    {
    public:
        /**
        * C++ constructor.
        * @since Series 60 2.8
        * @param aMsg Debug message.
        * @param aCalledFromL ETrue if called from RUBY_DEBUG_BLOCK_L
        */
        inline RRubyDebug( const TText* aMsg, const TText* aFileName, const TInt aLine, TBool aCalledFromL,
                           const TText8* aFunctionName = NULL );

        /**
        * Destructor.
        */
        inline ~RRubyDebug();

        /**
        * Destructor for Cleanup support. Called when a method leaves.
        */
        inline void Release();

        /**
        * Support for writing traces to file.
        */
        static void PrintToFile( TRefByValue<const TDesC> aFmt, ... );

    private:
        /**
        *  Class for truncating debug messages if they are too long.
        *  @since Series 60 2.8
        */
        class TTruncateOverflow : public TDesOverflow
            {
            public: // Methods from TDesOverflow

                inline void Overflow( TDes& aDes );
            };

    private:
        // A pointer to the debug message
        TPtrC iMsg;
        
        // A pointer to the filename where RUBY_DEBUG_BLOCK is written
        TPtrC iFileName;
        
        // Number of the line where RUBY_DEBUG_BLOCK is written
        TInt iLine;

		// ETrue if we are called from RUBY_DEBUG_BLOCKL
        TBool iCalledFromL;

        // Flag that is set when a leave occurs
        TBool iLeave;

	#ifndef RUBY_DISABLE_FUNCTION_NAMES        
        // Used only if aFunctionName is defined in constructor
        HBufC* iFunctionName;
   	#endif  // RUBY_DISABLE_FUNCTION_NAMES
        
    };

#include "rubydebug.inl"

#endif      // RUBYDEBUG_H
            
// End of File
