//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd 2000-10  (all rights reserved)
//               MELBOURNE, VICTORIA, AUSTRALIA, 3130
//
//  Provided no fee is charged (either by the distributer or user)
//  permission to use, copy, modify, and distribute this software and
//  its documentation for any purpose and without fee is hereby granted,
//  provided that the above copyright notice appear in all copies and
//  that both that copyright notice and this permission notice appear
//  in supporting documentation.
//
//  No waranty or suitablity for purpose is implied.
//
//
//  P2Pevent prototypes and definitions.
//
#pragma once

#include "P2PmsgKERNEL.h"
#include "P2Pmsg.h"

//
//  P2Pevent classes 
//  NOTES: Form the basis upon which all P2Pevent's are displayed
//         and notifications performed for registered sinks
// 
typedef unsigned int  P2PeventSinkID;    // Event sink identification
typedef DWORD         P2PevotnMask;      // Event notification mask

typedef enum
{
    P2Pevent_UNDEF     =  0,
    P2Pevent_ERROR     =  1,
    P2Pevent_WARNING   =  2,
    P2Pevent_INFO      =  3,
    P2Pevent_DEBUG     =  4,
    P2Pevent_TRACE     =  5,
    P2Pevent_LOG       =  6,
    P2Pevent_REPORT    =  7,
    P2Pevent_RESERVED8 =  8,
    P2Pevent_RESERVED9 =  9,

    P2Pevent_USER0     = 16,
    P2Pevent_USER1     = 17,
    P2Pevent_USER3     = 18,
} P2Pevent_e;

//
//  P2Pevent display and registered sink notification masks
//  NOTES: Refer Display() for presentation of P2Pevent's in the
//         context of application
//       : Refer Notify() for performing P2Pevent notifications in
//         the context of registered P2Pevent sinks
// 
const DWORD P2Pevotn_ERROR =  (1<<P2Pevent_ERROR);
const DWORD P2Pevotn_DEBUG =  (1<<P2Pevent_DEBUG);
const DWORD P2Pevotn_TRACE =  (1<<P2Pevent_TRACE);
const DWORD P2Pevotn_LOG   =  (1<<P2Pevent_LOG);
const DWORD P2Pevotn_REPORT=  (1<<P2Pevent_REPORT);
const DWORD P2Pevotn_INFO  =  (1<<P2Pevent_INFO);

const DWORD P2Pevotn_USER0 =  (1<<P2Pevent_USER0);

const DWORD P2Pevotn_MISC  = ~( P2Pevotn_ERROR
                              | P2Pevotn_DEBUG
                              | P2Pevotn_TRACE
                              | P2Pevotn_LOG
                              | P2Pevotn_REPORT )
                                & ~(1<<31);       // Top bit reserved
const DWORD P2Pevotn_FULL  = ~0 & ~(1<<31);  // Top bit reserved

#define TEvent__Adv _T("Adv")
#define TEvent__Dsc _T("Dsc")
#define TEvent__Fnc _T("Fnc")
#define TEvent__Grp _T("Grp")
#define TEvent__Hub _T("Hub")
#define TEvent__Obj _T("Obj")
#define TEvent__Pmp _T("Pmp")
#define TEvent__Sys _T("Sys")
#define TEvent__Svc _T("Svc")

//
//  P2Pevent implementation
//  NOTES: P2Peer events container
//
class P2PmsgKERNEL_EXT P2Pevent : public P3PmsgNode
{
      void
        RenderEventSafe ( );

    // Constructors and destructor
    public:
        P2Pevent ( );
        P2Pevent ( const P2Pevent& rhs );
        P2Pevent ( const P3PmsgNode& rhs );
      virtual
       ~P2Pevent ( );
      P2Pevent*
        Cancel  ( bool bNotify = true );

    typedef enum
    {
      ADDMASK,
      REMMASK,
      SETMASK,
      GETMASK,
    } ReportCmd_e;

    // Factories
    public:
      static P2Pevent*
        MakeEvent( P2Pevent_e eClass = P2Pevent_ERROR );
      P2Pevent*
        InitEvent( P2Pevent_e eClass );

    // Overloaded operators
    public:
      P2Pevent&
        operator = ( const P2Pevent& rhs );

    // Chained operations
    public:
      P2Pevent*
        Module  ( LPCTSTR lpszModuleName, ... );
      P2Pevent*
        Module_ ( LPCTSTR lpszModuleName );
      P2Pevent*
        FParam  ( LPCTSTR lpszFParamName, const P3PmsgData& oData );
      P2Pevent*
        FParam  ( P2Pevent *pEvent );
      P2Pevent*
        FParam  ( LPCTSTR lpszFParamName, const P3PmsgNode& oNode );
      P2Pevent*
        HResult ( HRESULT hr, LPCTSTR lpszhr = 0 );
      P2Pevent*
        Message ( LPCTSTR lpszFormat, ... );
      P2Pevent*
        Advice  ( LPCTSTR lpszFormat, ... );
      P2Pevent*
        Group   ( LPCTSTR lpszGroup, ... );
      P2Pevent*
        Time    ( DWORD dwEpochTime );
      P2Pevent*
        Display ( HWND hWnd = 0 );
      P2Pevent*
        Print ( FILE *fd = stdout );
      P2Pevent*
        Notify  ( );
      P2Pevent*
        SetLast ( );
      P2Pevent*
        Isolate ( );
      void
        Throw   ( bool bSetLastEvent = true );

    // Configuration
    // NOTES: Manage P2Pevent default and reporting
    public:
      static LPCTSTR
        Service ( LPCTSTR lpszServiceFormat, ... );
      static DWORD
        Configure ( ReportCmd_e eCmd, DWORD dwCmdArg );

    // Troubleshooting
    public:
      virtual void
        AssertValid ( ) const;
      P2Pevent*
        Break ( ) const;
      P2Pevent*
        SetTInst ( ) volatile;
      static P2Pevent*
        GetTInst ( );

    // Properties
    public:
      P2Pevent_e
        GetClass ( );
      LPCTSTR
        GetClassText ( );
      LPCTSTR
        GetService ( );
      LPCTSTR
        GetModule ( );
      BOOL
        EmptyModule ( );
      const CString&
        GetMessage ( );
      const CString&
        GetAdvice ( );
      LPCTSTR
        GetGroup ( );
      HRESULT
        GetHRESULT ( );
      LPCTSTR
        GetHRESULText ( );
      time_t
        GetTime ( );
      DWORD
        GetEvent ( );

    // Attributes
    private:
        bool            m_bDisplayed;

        CString         m_csDescription;
        CString         m_csAdvice;
};
typedef P2PSafePtr<P2Pevent> P2PeventSP;

//
//  P2Pevent object instanciation shortcuts
#define EVERR  P2Pevent::MakeEvent(P2Pevent_ERROR) 
#define EVWRN (P2Pevent::MakeEvent(P2Pevent_WARN))
#define EVINF (P2Pevent::MakeEvent(P2Pevent_INFO))
#define EVDBG (P2Pevent::MakeEvent(P2Pevent_DEBUG))
#define EVTRC (P2Pevent::MakeEvent(P2Pevent_TRACE))
#define EVLOG (P2Pevent::MakeEvent(P2Pevent_LOG))
#define EVRPT (P2Pevent::MakeEvent(P2Pevent_REPORT))

#define EVAPP (P2Pevent::MakeEvent(P2Pevent_USER0))

#define T__FUNCTION__ _T(__FUNCTION__)
#define MODULE  Module_(T__FUNCTION__)
#define Message_T(str) Message(_T(str))
#define Advice_T(str)  Advice(_T(str))

//
//  Catch block interceptions
//  NOTES: Utilised in catch handlers to translate exception object
//         into P2Pevent object.  Usually extracts Message() and
//         HResult() from message/environment
//       : Example
//         catch ( CException *pEx )
//         {
//           P2Pevent *pEVT = P2Pevent_catch ( pEx, true )
//                          -> Module ( __FUNCTION__ )
//                          -> etc;
//         }
P2PmsgKERNEL_EXT P2Pevent*
P2Pevent_catch ( CException *pEx, bool bDeleteEx = true );

#define catch_pP2Pevent_Cancel \
    catch ( P2Pevent *pEVT ) \
    { \
      pEVT -> Cancel(); \
    } \

#define catch_ALL_Cancel \
    catch ( ... ) \
    { \
      EVERR-> MODULE \
           -> Message ( _T("Unknown exception") ) \
           -> Cancel(); \
    } \

#define catch_pCException_Cancel \
    catch ( CException *pEx ) \
    { \
      P2Pevent *pEVT = P2Pevent_catch(pEx); \
      pEVT -> MODULE \
           -> Cancel(); \
    } \

#define catch_pCException_SetLast \
    catch ( CException *pEx ) \
    { \
      P2Pevent *pEVT = P2Pevent_catch(pEx); \
      pEVT -> MODULE \
           -> SetLast(); \
    } \

//
//  P2Pevent content helpers
//  NOTES: Used to summarise content of P2Pevent objects
#define EVT_EmptyGroup(pEVT) (strlen(pEVT->GetGroup())>0)
#define EVT_EmptyModule(pEVT) (strlen(pEVT->GetModule())>0)

//
//  FParam ( ) helpers
//  NOTES: A[ppend] FP[aram's] work for the standard 'C' types
//         supported by the P2PmsgData() constructor set
//       : Add your own variants for 3rd Party structs and objects
//         with P2PeerMsg and P2PeerCon providing a suitable
//         patterns to follow
//       : Usage
//         EVERR->Module(__FUNCTION__)
//              ->AFP(nPumpID)->AFPmsg(pMsg)->AFPyourObj(pObj)
//              ->Message("This is an event associated message")
//       : Such parameters are appended beneath the P2Pevent function
//         node.  It should be assumed that any appended parameters
//         will have global exposure
#define AFP(arg) FParam(_T(#arg),P3PmsgData(arg))
#define AFP_f(arg,fmt) FParam(#arg,P3PmsgData(arg).c_printf(fmt))

//
//  FObject ( ) helpers
//  NOTES: 
//       : Usage
//         EVERR->Module(__FUNCTION__)
//              ->Object(this)

//
//  P2Pevent callback definitions (default set)
//  NOTES: Used to manage registered P2PeventSink notifications
//       : Call backs will be performed for each filtered event, 
//         other options include thread and window notifications
//       : Remember to cancel the notification prior to allowing
//         the implementation code to go out of scope
typedef void (WINAPI *P2PeventCBFnc)
         ( P2PeventSinkID  nSinkID,    // Sink identification code
           DWORD          dwCBKey,     // User definied callback key
           const P2Pevent& oEvent );   // Notification event

P2PmsgKERNEL_EXT void WINAPI           // Posts P2Pevent to HWND
P2PeventCB_HWND ( P2PeventSinkID nSinkID, DWORD dwCBKey
                , const P2Pevent& oEvent ); 
extern P2PmsgKERNEL_EXT
UINT WM_P2PeventNOTN;                  // Notification identification

P2PmsgKERNEL_EXT void WINAPI           // Performs modal display
P2PeventCB_Modal( P2PeventSinkID nSinkID, DWORD dwCBKey
                , const P2Pevent& oEvent ); 

//
//  P2Pevent Display() helpers
P2PmsgKERNEL_EXT int
P2PeventMBox ( P2Pevent *pP2Pevent, UINT nType = MB_OK );

//
//  P2Pevent sink management 
//  NOTES: Manage the creation, operation and life cycle of
//         P2PeventSink's.  Clients may register for P2Pevent
//         notifications
//       : Thread isolation of P2Pevent's
P2PmsgKERNEL_EXT BOOL
StartupP2Pevent ( );
P2PmsgKERNEL_EXT void
CleanupP2Pevent ( );
P2PmsgKERNEL_EXT BOOL
CloseP2PeventSink ( P2PeventSinkID nSinkID );
P2PmsgKERNEL_EXT P2PeventSinkID
CreateP2PeventSink ( DWORD dwCBKey
                   , P2PeventCBFnc pCBFnc
                   , bool bReg4all = true );
P2PmsgKERNEL_EXT BOOL
EnumP2PeventSink ( P2PeventSinkID& nSinkID );
P2PmsgKERNEL_EXT P2Pevent*
GetP2Pevent ( );
P2PmsgKERNEL_EXT P2Pevent*
IsolateP2Pevent ( );
P2PmsgKERNEL_EXT int
PerformP2PeventNotn ( P2Pevent *pEvent = 0 );

const DWORD P2Pevent_AddMask    = 1;
const DWORD P2Pevent_RemMask    = 2;
const DWORD P2Pevent_GetMask    = 3;
const DWORD P2Pevent_SetMask    = 4;
const DWORD P2Pevent_AddContext = 5;
const DWORD P2Pevent_RemContext = 6;
const DWORD P2Pevent_RstContext = 7;
P2PmsgKERNEL_EXT DWORD
RegP2PeventCmd ( P2PeventSinkID nSinkID
               , DWORD dwCmd
               , DWORD dwCmdArg );
P2PmsgKERNEL_EXT DWORD
IsP2PeventReg ( DWORD dwP2PeventMask );
#define IsEVDBG (IsP2PeventReg(1<<P2Pevent_DEBUG)?true:false)
#define IsEVTRC (IsP2PeventReg(1<<P2Pevent_TRACE)?true:false)
#define IsEVLOG (IsP2PeventReg(1<<P2Pevent_LOG)?true:false)

P2PmsgKERNEL_EXT void
SetP2Pevent ( P2Pevent *pEvent = 0 );
P2PmsgKERNEL_EXT void
ThrowP2Pevent ( );


