//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd 2002-9  (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.
//
//
//  P2PeerCon[nection] definitions and prototypes
//  NOTES: Base class from which all P2PeerCon[nection] objects are
//         derived (P2PeerConWsa, P2PeerConPipe and P2PeerCon232 etc).
//       : FILE type object supported by derived object must be compatible
//         with IO completion ports.
//       : Collections of P2PeerCon objects are managed by P2PeerHub's
//         to implement the asynchronous P2PeerMsg exchanges.
//                      
#pragma once

#ifndef NO_DEBUG_NEW
#define new DEBUG_NEW
#endif

#include "P2Peer.h"
#include "P2Peerio.h"
#include "P2Pevent.h"

///////////////////////////////////////////////////////////////////////
//  P2PeerCon_MAP handler result types
//  NOTES: Used to summarise map handler outcomes. P2PeerCon_MAP
//         handlers must return a result from the following
//
typedef  mapRESULT conRESULT;
const    conRESULT conTINUE   = FALSE; // Not handled continue routing
const    conRESULT conHANDLED = TRUE;  // Handled, discontinue routing
const    conRESULT conDROP    = 3;     // Handled, drop P2PeerCon object
const    conRESULT conSWAP    = 7;     // Swap processing context

//
//  P2PeerCon interface P2PeerID mapping
typedef enum
{
    P2PeerIDmap_NONE          = 0,
    P2PeerIDmap_Normal        = 2,
    P2PeerIDmap_Discontinuous = 3,
    P2PeerIDmap_STATIC        = 4,
    P2PeerIDmap_Recursive     = 5,
    P2PeerIDmap_FRACTAL       = 6,
//} P2PaddrTrans_e;
} P2PeerIDmap_e;

//
//  P2PeerCon mode
//  NOTES: P2PeerCon's are created with and maintain one of the
//         following modes for their complete life cycle
//       : Pumped P2PeerCon objects assume that the assigned 
//         mode is constant
typedef enum
{
    P2PeerCon_Unknown     = 0, 
    P2PeerCon_CLIENT      = 1,         // Active  connection
    P2PeerCon_SERVICE     = 2,         // Passive service
    P2PeerCon_Accept      = 3,         // Neutral accepted
} P2PeerConMode_e;

///////////////////////////////////////////////////////////////////////
//  P2PeerConPlc 
//  NOTES: Optimised for and targeted to self extracting lists
//         of P2PeerCon objects
//       : Manages private interactions between P2PeerHub, P2PeerCon
//         objects and the P2Pmsg pump
class P2PmsgKERNEL_EXT P2PeerConPlc : public CObject
{
    // Constructors and destructor
    public:
        DECLARE_DYNCREATE(P2PeerConPlc)
        P2PeerConPlc ( );
      virtual
       ~P2PeerConPlc ( );
        P2PconID  m_nP2PconID;

    // Life cycle management
    public:
      UINT
        AddRef ( );
      UINT
        Release ( );
      UINT
        Destroy ( );
      bool
        PostDestroyState ( );

    // Troubleshooting
    public:
      void
        AssertValid ( ) const;

    // Properties
    public:
      P3PmsgNode&
        GetP2Props ( );
      P2PconID
        GetP2PconID ( ) const;

    // Attributes
    protected:
      P3PmsgNode *m_pP2Props;
      int         m_cRef;
      bool        m_bDestroy;
};

//
//  Asynchronous control signals
//  NOTES: Refer P2PeerCon::Signal() for implementation details
                                       // P2PeerCon signals
const P2PsigID P2PsigCon_CLOSE   = 1;  //   On_P2PeerCon_CLOSE 
const P2PsigID P2PsigCon_MSG     = 2;  //      P2PeerMsg emulation
const P2PsigID P2PsigCon_DESTROY = 3;  //   On_P2PeerCon_DESTROY
const P2PsigID P2PsigCon_SHUTDOWN= 4;  //   On_P2PeerCon_SHUTDOWN
const P2PsigID P2PsigCon_CLOSEONIDLE=5;// 
const P2PsigID P2PsigCon_RECV    = 6;  //      P2PeerMsg receipt

                                       // P2Peerio signals
const P2PsigID P2PsigIO_ACK      = 7;  //   P2PeerMsg acknowledgement

///////////////////////////////////////////////////////////////////////
//  P2PeerCon[nection] management
//  NOTES: Instances of these objects wholly manage single P2Peer
//         connections.  Collections of P2PeerCon objects are collated
//         and supervised by P2PeerHub's
//
class P2PmsgKERNEL_EXT P2PeerCon : public P2PeerConPlc
{
      friend
        P2Peerio;
      friend P2PmsgKERNEL_EXT DWORD
        PumpP2Pmsg ( DWORD, P2PsigID& );
      void
        RenderThisSafe();

    // Constructors, destructors and factories
    public:
        DECLARE_DYNCREATE(P2PeerCon)
        P2PeerCon ( );
        P2PeerCon ( P2PaddrSTR pThatP2PaddrSTR
                  , P2Peerio   *pP2Peerio = 0 );
        P2PeerCon ( P2Peerio   *pP2Peerio );
      virtual
       ~P2PeerCon ( );
      virtual P2PeerCon*
        AcceptSpawn ( P2PeerCon *pCon );

    // IOCP Integration
    public:
      void
        CreateIOCP ( HANDLE hFile );
      virtual bool
        On_QueuedCompletionStatus ( DWORD dwError
                                  , DWORD dwBytes
                                  , OVERLAPPEDcon *pOVERLAPPEDcon );
      virtual OVERLAPPEDcon*
        MakeOVERLAPPED ( DWORD dwBytesMax = 0 );
      virtual OVERLAPPEDcon*
        DropOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon
                       , bool bNotify = true );
      void
        PostOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon );
      void
        prepareOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon );
      void
        releaseOVERLAPPED ( OVERLAPPEDcon *pOVERLAPPEDcon );
      virtual void
        Signal ( P2PsigID nSigID
               , void *pvData = 0, int iDataSize = 0 );

    // Timers
    public:
      PITimerID
        SetPITimer   ( P2Pmsecs_t uMSecDelay, DWORD dwUserKey = 0 );
      virtual void
        On_PITimer   ( bool bCancel
                     , PITimerID nPITimerID, DWORD dwUserKey );
      virtual void
        Drop ( P2Pevent *pEVENT );

    // P2PeerMsg Management
    public:
      virtual P2PeerMsg*
        PostP2PeerMsg ( P2PeerMsg *pMsg );
      void
        FlushP2PeerMsg ( );
      P2PeerMsg*
        GetP2PeerMsg ( );
      int
        GetP2PeerMsgCount ( );

    // Connection state operations
    // NOTES: Thread safe operations used to manage connection
    //        state.  Reference from P2PeerCon_MAP handlers only
    public:
      virtual P2Pmsecs_t
          Restart  ( P2Pmsecs_t uiMsecDelay = 0 );
      virtual void
        OnStartup  ( );
      virtual bool
          Listen   ( );
      virtual void
        OnListen   ( );
      virtual bool
          Accept   ( );
      virtual P2PeerCon*
        OnAccept   ( );
      virtual void
        OnAccept   ( CP2Paddress oThatP2Paddr );
      virtual bool
          Connect  ( );
      virtual void
        OnConnect  ( );
      virtual void
          Login    ( P2PaddrSTR strThatP2Paddr
                   , const void *pvLoginMsg, P2Psize_t nSize );
      virtual void
          Login_Fractal ( P2PaddrSTR strThisP2Paddr, P2PaddrSTR strThatP2Paddr
                        , const void *pvLoginMsg, P2Psize_t nSize );
      virtual void
        OnLogin    ( const P2Paddr& oP2Paddr );
      virtual BOOL
          LoginAck ( const P2Paddr& oThatP2Paddr
                   , const void *pvLoginAck, P2Psize_t nSize );
      virtual void
        OnLoginAck ( const P2Paddr& oThisP2Paddr
                   , const P2Paddr& oThatP2Paddr );
      virtual void
        OnLoginAck_Static ( const P2Paddr& oThisP2Paddr
                          , const P2Paddr& oThatP2Paddr );
      virtual void
        OnLoginAck_Fractal( const P2Paddr& oThisP2Paddr1
                          , const P2Paddr& oThatP2Paddr1 );
      virtual void
          Close    ( );
      virtual conRESULT
        OnClose    ( );
      virtual void
          Shutdown ( );
      virtual BOOL
        OnShutdown ( );

    // Internals
    protected:
      virtual void
        PerformIFaddrTransform ( BOOL bSoR, P2PeerMsg *pMsg );

    // Troubleshooting
    public:
      void
        AssertValid ( ) const;
      virtual LPCTSTR
        GetVisualRTSummary ( );
      virtual P3PmsgNode
        SetP2PeventFParams ( LPCTSTR lpszVar );
      virtual P3PmsgNode
        Serialise ( LPCTSTR lpszVar );

    // Properties
    public:
      const P2Padomain&
        GetP2Padomain ( ) const;
      const P2Paddr&
        GetP2Paddress ( );
      BOOL
        SetP2Paddr ( P2PaddrSTR strP2Paddress );
      const P2Paddr
        GetP2PaddrHub ( ) const;
      void 
        SetIFaddrTransform ( P2PeerIDmap_e eIFaddrTrans );
      void
        SetP2Peerio ( P2Peerio *pP2Peerio );
      P2Peerio*
        GetP2Peerio ( );
      DWORD
        SetState( DWORD dwAdd, DWORD dwRemove );
      DWORD
        GetState( DWORD dwMask = ~0 );
      bool
        HasState ( DWORD dwMask );
      P2PeerConMode_e
        GetMode ( );
      virtual DWORD
        GetUDState ( );
      P2Pevent*
        SetP2Pevent ( P2PeventSP& spP2Pevent );
      P2Pevent*
        GetP2Pevent ( );

      LPCTSTR
        EncodeP2Pmsg_t ( P2Pmsg_t nMsg );
      virtual bool
        HasDroppedOut ( HRESULT hr );

    // Attributes
    public:
      HANDLE           m_hP2PmsgCon;
      DWORD            m_hCPortP2PumpID;
      HANDLE           m_hCPort;
      P2Pmsecs_t       m_uAutoRestart;
      P2PeerTarget    *m_pP2PeerTarget;
    protected:
      CRITICAL_SECTION m_oCSectMsgQue;
      CListP2PeerMsg   m_oCListMsgQue;
      P2Pevent        *m_pEvent;
      HANDLE           m_hFile;
      HANDLE           m_hFileCPort;
      UINT_PTR         m_dwCompletionKey;
      P2Peerio        *m_pP2Peerio;

      P2PeerMsg       *m_pP2PeerMsgSend;
      P2Pmsecs_t       m_iRecvTimeout;

      OVERLAPPEDcon   *m_pOVERLAPPEDsend;
      OVERLAPPEDcon   *m_pOVERLAPPEDrecv;
      OVERLAPPEDcon   *m_pOVERLAPPEDaccept;
      OVERLAPPEDcon   *m_pOVERLAPPEDconnect;

      DWORD            m_dwState;

      PITimerID        m_uRestartTimerID;
      PITimerID        m_uLoginTimerID;

      P2Padomain       m_oP2Padomain;
      P2Paddr          m_oThisP2Paddr_, m_oThisP2Paddr1;
      P2Paddr          m_oThatP2Paddr, m_oThatP2Paddr1;
      P2PeerIDmap_e    m_eP2PeerIDmap;

      CString         *m_pstrVisualSummary;
      P2PeerConMode_e  m_eP2PeerConMode;
};

///////////////////////////////////////////////////////////////////////
//  Safe P2PeerCon container
//  NOTES: Intended for stack use from P2PeerMsg handlers.  Do not
//         allow object to persist
//       : Useful for dynamic configuration of P2PeerCon objects
//         Example: if ( ConQuery("A.B",oSafeCon) )
//                    oSafeCon -> GetP2Peerio() -> SetIFTrace ( true );
//
class P2PmsgKERNEL_EXT SafeP2PeerCon
{
      void
        RenderThisSafe ( );
 
    // Constructors and destruction
    public:
        SafeP2PeerCon ( );
        SafeP2PeerCon ( P2PeerCon *pCon );
       ~SafeP2PeerCon ( );

    // Operators
    public:
      SafeP2PeerCon&
        operator = ( P2PeerCon *pCon );
      P2PeerCon*
        operator -> ( ) const;

        operator P2PeerCon* ( );

        operator bool ( );

    // Attributes
    private:
        P2PeerCon  *m_pP2PeerCon;
};

//
//  Operational states
//  NOTES: Used to summarise P2PeerCon connection behaviour and
//         states
const DWORD ConState_BCasts      = (1<<0);
const DWORD ConState_UCasts      = (1<<1);
const DWORD ConState_Recv        = (1<<2);
const DWORD ConState_Send        = (1<<3);
const DWORD ConState_Login       = (1<<5);
const DWORD ConState_CloseOnIdle = (1<<6);

const DWORD ConBCasts_OK  = ( ConState_Send
                            | ConState_Login
                            | ConState_BCasts );
const DWORD ConUCasts_OK  = ( ConState_Send
                            | ConState_Login
                            | ConState_UCasts );
const DWORD ON_ConClose   = ( ConState_Send | ConState_Recv
                            | ConState_Login | ConState_CloseOnIdle );
const DWORD ON_ConShutdown= ( ConState_Send | ConState_Recv
                            | ConState_Login | ConState_CloseOnIdle );

                                       // P2P::nMsg alternatives
const short P2P_P2Pmsg     = 0;
const short P2P_Startup    = 10;
const short P2P_Listen     = 1;
const short P2P_Connect    = 2;
const short P2P_Accept     = 3;
//const short P2P_Reject     = 4;
const short P2P_Close      = 5;
const short P2P_Dropout    = 5;
//const short P2P_Mute       = 6;
const short P2P_Login      = 7;
const short P2P_LoginAck   = 8;
const short P2P_Notify     = 9;
const short P2P_IdleNotify = 11;
const short P2P_Destroy    = 12;
const short P2P_PITimer    = 13;
const short P2P_Shutdown   = 14;

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

///////////////////////////////////////////////////////////////////////
//  Reserved connection management P2PmsgID's
//  NOTES: Such P2PmsgID's are reserved and as such issued and
//         intercepted by the underlying framework
//       : Refer P2PeerMsg.h for alternative framework list
//
static
P2PmsgID    P2Pmsg_ALL      = _T("P2Pmsg*");
static
P2PmsgID    P2Pmsg_Login    = _T("P2PmsgLogin");
static
P2PmsgID    P2Pmsg_LoginAck = _T("P2PmsgLoginAck");


