//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd 2002-11  (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.
//
//
//  P2PeerMsg definitions and prototypes
//  NOTES: Container that facilitates the asychronous exchange of
//         messages between P2PeerHub's and subsequent routing through
//         the registered hierachies of derivered P2PeerTarget's
//       : These object's are not designed to be thread or context
//         safe and as such reference MUST be isolated
//
#pragma once

#include "P2Peer.h"
#include "P2Pevent.h"
#include "P2PTL.h"
#include "P2PmsgBSTR.h"

//
//  P2PeerMsg associated definitions and limits
//  NOTES: Must be common across any given P2Peer network
#define MAX_P2PeerMsg_Index 16
const   P2Psize_t MAX_P2Psize = 2048;  // Maximum P2PeerMsg size

//
//  Description: Priority definitions
//               NOTES: General commands are issued at the 
//                      MscsPriNormal priority.
//                    : The flush priority is reserved exclusively
//                      for cleaning out pending control sequences.
//                    : The high priority is reserved for activities
//                      of greater importance.
//                    : The low priority is reserved for activities
//                      of less importance.
//
//                    : Stick to normal priority order wise 
//                      implementation order creates secondary
//                      effects.
//
const   UCHAR P2PeerPriFlush =  0;
const   UCHAR P2PeerPriNormal=  7;
const   UCHAR P2PeerPriHigh  = P2PeerPriNormal - 5;
const   UCHAR P2PeerPriLow   = P2PeerPriNormal + 5;

//
//  P2PeerMsg parameters
//  NOTES: Persists within the P2PeerMsgHdr::ucState item
//
const   P2Pmsg_t P2P_Reflected       (1<<(sizeof(P2Pmsg_t)*8-1));

const   UCHAR P2PeerMsgState_Normal    =     0;
const   UCHAR P2PeerMsgState_Reflected = (1<<0);
const   UCHAR P2PeerMsgState_Ack       = (1<<1);
const   UCHAR P2PeerMsgState_Exception = (1<<2);
const   UCHAR P2PeerMsgState_Posted    = (1<<3);

//
//  P2PeerMsg control options
//  NOTES: Persist within P2PeerMsgHdr::uiCtrl item
const   UINT08 P2PeerMsgCtrl_NONE      =     0;
const   UINT08 P2PeerMsgCtrl_EXCEPTIONS= (1<<0); // Generate routing exceptions

const   UINT08 P2PeerMsgCtrl_DEFAULT   =  P2PeerMsgCtrl_EXCEPTIONS;

//
//  P2PeerMsgPrefix details
//  NOTES: P2PeerMsg prefix structure.  Contains private P2PeerMsg
//         address independant context information.
//       : Contained within P2PmsgData area of the primary P2PmsgNode
#pragma pack(push,1)
typedef struct P2PeerMsgPrefix
{
    UCHAR          eType;              //   P2PmsgVT_P2Pmsg
    DWORD          nSourceID;          // Source  P2PeerHub ID
    DWORD          dwAddrTag_;          // Source  P2PeerTarget tag
    DWORD          nDestinID;          // Destin  P2PeerHub ID
    //P2PeerID       nConmapID_;
    P2Pmsg_t       nMsg;               // TODO be deleted Xover only

    UINT08         uiCtrl;
    UINT08         ucPriority;
    UINT16         uiState;
    UINT08         uiP2Pexpump;
} P2PeerMsgPrefix;
#pragma pack(pop)

//
//  Common P2PeerMsg internal names and labels
#define TMsg_Src _T("Src")
#define TMsg_Dst _T("Dst")
#define TMsg_Tag _T("Tag")

//
//
//  P2PeerMsg object
//  NOTES: P2Peer data wrapper.  
// 
class P2PmsgKERNEL_EXT P2PeerMsg : public P3PmsgBSTR
{
      void
        RenderThisSafe ( );
      void
        ResetThisObject ( );

    // Constructors and destructor
    public:
        P2PeerMsg ( );

        P2PeerMsg ( const P2PeerMsg& rhs );

        P2PeerMsg ( P2PmsgHANDLE hVBList );

        P2PeerMsg ( const VBListIOmage& oIOmage );

        P2PeerMsg ( VBListIOmage *pIOmage );

        P2PeerMsg ( P2PmsgID pszMsgID );

        P2PeerMsg ( P2PaddrSTR oSourceSTR, P2PaddrSTR oDestinSTR
                  , P2PmsgID pszMsg
                  , const void *pvMsgData, P2Psize_t iMsgDataSize );
        P2PeerMsg ( const P3PmsgField& oSource, const P3PmsgField& oDestin
                  , P2PmsgID pszMsg
                  , const void *pvMsgData, P2Psize_t iMsgDataSize );
        P2PeerMsg ( P2PaddrSTR oSourceSTR, P2PaddrSTR oDestinSTR
                  , P2PmsgID pszMsg
                  , LPCTSTR lpszMsgData, ... );
        P2PeerMsg ( const P3PmsgField& oSource, const P3PmsgField& oDestin
                  , P2PmsgID pszMsg
                  , LPCTSTR lpszMsgData, ... );
        //P2PeerMsg ( P2PaddrSTR oSourceSTR, P2PaddrSTR oDestinSTR
        //          , const P2Pevent& oP2Pevent );
      virtual
       ~P2PeerMsg ();

    // Overloaded operators
    public:
      P2PeerMsg&
        operator  = ( const P2PeerMsg& rhs );
      P2PeerMsg&
        operator [] ( int nIdx );

    // Factories
    public:
      P2PeerMsg*
        ResponseFactory ( P2PmsgID pszMsg
                        , const void *pvMsgData, P2Psize_t iMsgDataSize );
      P2PeerMsg*
        WrappedResponseFactory ( P2PmsgID pszMsg
                               , const void *pvMsgData, P2Psize_t iMsgSize );
      P2PeerMsg*
        ReflectFactory ( ) const;
      P2PeerMsg*
        LoopbackFactory( ) const;
      P2PeerMsg*
        ExceptionFactory ( P2Pevent *pEVT );
      P2PeerMsg*
        WrapFactory ( P2PmsgID pszMsg
                    , const void *pvMsgData, P2Psize_t iMsgDataSize );
      void
        WrapAttach ( P2PeerMsg *pP2Pmsg );
      //P2PeerMsg*
      //  ErrorResponseFactory ( P2Pevent *pP2Pevent );
      P2PeerMsg*
        RedirectFactory ( P2PaddrSTR oDestinSTR );
      P2PeerMsg*
        RedirectFactory ( P2PaddrSTR oDestinSTR
                        , P2PmsgID sMsg
                        , const void *pvMsgData, P2Psize_t iMsgDataSize );
      P2PeerMsg*
        UnwrapFactory ( );

    // P2Pevents
    public:
      void
        AttachP2Pevent ( const P2Pevent *pEvent
                       , LPCTSTR lpszFieldName = 0 );
      P2Pevent*
        ExtractP2Pevent( LPCTSTR lpszFieldName = 0 );

    // Utilities
    private:
      bool
        CheckSum ( );

    // P2PeerMsg_MAP routing
    // NOTES: Used for P2PeerMsg routing and handler assignment
    public:
      bool
        Map_MatchState( USHORT uiMsgStateWildbits );
      bool
        Map_MatchName ( const char *pszMapWildcard ) const;

    // Troubleshooting
    public:
      virtual void
        AssertValid ( ) const;
      virtual void
        Print ( FILE *fd );
      virtual LPCTSTR
        GetVisualRTSummary ( );
      virtual const P3PmsgNode&
        SetP2PeventFParams ( LPCTSTR lpszVar );

    // Property management
    public:
      P2PaddrSTR
        GetSource ( ) const;
      P2PaddrSTR
        SetSource ( P2PaddrSTR strSource );
      P3PmsgField&
        SetSource ( const P3PmsgField& oSource );
      P2PaddrSTR
        GetDestin ( ) const;
      P2PaddrSTR
        SetDestin ( P2PaddrSTR strDestin );
      P3PmsgField&
        SetDestin ( const P3PmsgField& oDestin );
      P2PaddrSTR
        GetConmap ( );
      P2PaddrSTR
        SetConmap ( P2PaddrSTR strConmap );
      char*
        Data ( ) const;
      short
        DataSize ( );
      P2Psize_t
        SetData ( P2PmsgID pszMsg
                , const void *pvMsgData, P2Psize_t iMsgDataSize );
      UCHAR
        Priority ( );
      UCHAR
        SetPriority ( UCHAR iPriority );
      DWORD
        AddrTag    ( );
      DWORD
        SetAddrTag ( const void *pvUserTag, P2Psize_t iSize );
      bool
        IsWrapped ( );
      bool
        IsReflected ( );
      virtual P2Psize_t
        Sizeof ( ) const;
      virtual int
        GetDepth ( ) const;
      bool&
        Exceptions ( );
      bool
        Exceptions ( ) const;

    // Property exposure
    public:
      LPCTSTR
        c_name ( ) const;
      P3PmsgField&
        r_Source ( ) const;
      P3PmsgField&
        r_Destin ( ) const;

    // Attributes
    private:
      P2PeerMsg    *m_pP2PmsgWrap;
      char          m_szVisualHdr[128];
      CString      *m_pstrVisualSummary;
      P2PeerMsg    *m_pP2PmsgParent;
    protected:
      friend class P2PeerTarget;
      friend class P2PeerPump;
      friend class P2PeerMsgQue;
};
typedef P2PSafePtr<P2PeerMsg> P2PeerMsgSP;
typedef CList<P2PeerMsg*, P2PeerMsg*> CListP2PeerMsg;
extern  P2PmsgKERNEL_EXT UINT g_P2PeerMsgInstances;

//
//  P2Pevent::FParam ( const P2PmsgNode& oNode ) helpers
//  NOTES: Appends P2PmsgNode details to P2Pevent
//       : Usage
//         EVERR->MODULE
//              ->AFP(nPumpID)->AFPmsg(pMsg)->AFPyourObj(pYourObj)
//              ->Message("This is an event associated message")
//       : P2PmsgNode containing P2PeerMsg details is appended beneath
//         the P2Pevent module node.  It should be assumed that any
//         appended parameters will have global exposure
#define AFPmsg(arg) FParam(#arg,arg->SetP2PeventFParams(#arg))

///////////////////////////////////////////////////////////////////////
//  Reserved framework management P2PeerMsg's
//  NOTES: These P2PmsgID's are reserved and as such intercepted and
//         interpreted by the underlying framework
//

//
//  P2Pmsg_3rdParty definition
//  NOTES: Generic P2PeerMsg used to flag a raw message transmitter
//         without header details.
//       : Facilitates transparent P2Peer interaction with
//         3rd Party interfaces.
//
static
const P2PmsgID P2Pmsg_3rdParty = _T("P2Pmsg_3rdParty");
static
const P2PmsgID P2Pmsg_3rdPartyi= _T("P2Pmsg_3rdPartyi");
static
const P2PmsgID P2Pmsg_3rdPartyo= _T("P2Pmsg_3rdPartyo");

//
//  P2Pmsg_Stop
//  NOTES: Terminate P2PeerHub processing
static
const TCHAR    *P2Pmsg_Stop = _T("P2PmsgStop");

//
//  P2Pmsg_Error
static
const P2PmsgID P2Pmsg_Error = _T("P2PmsgError");

//
//  P2Pmsg_Undeliverable definition
static
P2PmsgID P2Pmsg_Undeliv = _T("P2PmsgUndeliv");

//
//  P2Pmsg_Poll
//  NOTES: Poll remote P2PeerHub
#pragma pack(push,1)
typedef struct
{
    DWORD      dwUserData;
    DWORD      dwMillisecs;
} Msg_P2PeerPoll;
#pragma pack(pop)
static
P2PmsgID P2Pmsg_Poll = _T("P2PmsgPoll");

//
//  P2Pmsg_Ping
//  NOTES: Used to ping remote P2PeerHub.
//       : Designed measure turn around tarnsit times etc.
#pragma pack(push,1)
typedef struct
{
    DWORD      dwUserData;
    DWORD      dwCounter;
    DWORD      dwMillisecs;
} Msg_P2PeerPing;
#pragma pack(pop)
static
P2PmsgID P2Pmsg_Ping = _T("P2PmsgPing");

//
//  P2Pmsg_BCast
//  NOTES: Broadcast wrapped data down through the heirachical network
//         of P2PeerHub's
//       : P2PeerCon's must enable broadcast propagation
static
P2PmsgID P2Pmsg_BCast = _T("P2PmsgBCast");

//
//  P2Pmsg_Sync
//  NOTES: Exchange synchronisation request between P2PeerHub's
static
P2PmsgID P2Pmsg_Sync = _T("P2PmsgSync");

//
//  P2Pmsg_Eventails
static
P2PmsgID P2Pmsg_Eventails = _T("P2PmsgEventails");

//
//  P2Pmsg_Exception
//  NOTES: Used to throw and route P2PeerMsg exceptions between
//         P2PeerHub's
const   DWORD P2PeerException_Undeliv = 1;
const   DWORD P2PeerException_Unknown = 2;
const   DWORD P2PeerException_Version = 3;
#pragma pack(push,1)
typedef struct
{
    DWORD       dwExcepType;
    char        cEVTag;
} Msg_Exception;
#pragma pack(pop)
static
P2PmsgID P2Pmsg_Exception = _T("P2PmsgException");

//
//  P2Pmsg_Timer
#pragma pack(push,1)
typedef struct
{
    DWORD      dwUserKey;
} Msg_P2PeerTimer;
#pragma pack(pop)
static
P2PmsgID P2Pmsg_Timer = _T("P2PmsgTimer");

///////////////////////////////////////////////////////////////////////
//  P2PeerID networking and addressing

//
//  P2PeerMsg locking and unlocking
//P2PmsgKERNEL_EXT P2PeerMsg*
//P2PeerMsg_P2PmsgLock ( P2PeerMsg *pMsg, bool bEoD );
//P2PmsgKERNEL_EXT P2PeerMsg*
//P2PeerMsg_P2PeerConLock ( P2PeerMsg *pMsg, bool bEoD );

//
//  Manage P2PeerID addressing hierachy and routing
//  NOTES: IsP2PeerChild() is used to confirm nChildID
//         of nParentID
//       : IsP2PeerRable() is used to confirm nMsgID
//         routable down through strP2Paddr
P2PmsgKERNEL_EXT P2PeerMsg*
P2PeerMsg_SetReflected ( P2PeerMsg *pMsg, bool bReflected );
P2PmsgKERNEL_EXT P2PeerMsg*
P2PeerMsg_DstSwapSrc ( P2PeerMsg *pMsg );
P2PmsgKERNEL_EXT bool
Wildcard ( P2PmsgID strWildcard, P2PmsgID strMsgName );

//
//  State summary etc
P2PmsgKERNEL_EXT BOOL
P2PeerMsg_IsPosted ( const P2PeerMsg *pMsg );
