//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd  2002-2009
//               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.
//
//
//  Description: P2PeerioDmx base class implementation
//  NOTES: Performs in-process P2PeerMsg image exchanges with direct
//         use of the IO Completion Port
//

#include "StdAfx.h"
#include "Kernel32_Ext.h"
#include "P2PeerioDmx.h"
#include "P2PeerConDmx.h"

extern
CRITICAL_SECTION  g_oCSectP2PeerConDmx;

///////////////////////////////////////////////////////////////////////
//  Constructors and destructor

P2PeerioDmx::P2PeerioDmx ( )
{
    // Firstly
    RenderThisSafe();
}

P2PeerioDmx::~P2PeerioDmx ( )
{  }

void
P2PeerioDmx::RenderThisSafe()
{
    // Attributes
    m_pOVERLAPPEDrecv = 0;
    m_pOVERLAPPEDsend = 0;
}

P2Peerio*
P2PeerioDmx::Clone ( )
{   return new P2PeerioDmx ( ); }

///////////////////////////////////////////////////////////////////////
//  IO
//  NOTES: Completion Port transmission and receipt
//       : BSTR protocol implementation
//

//
//  Sends P2PeerMsg
//  NOTES: Override this method to customise a protocol
//
//
//  Parameters:  HANDLE hFile
//               Send P2PeerMsg file handle
//
//               P2PeerMsg *pMsg
//               Message to be sent
//
//               OVERLAPPEDcon *pOVERLAPPEDsend
//               Pointer to an OVERLAPPEDcon send buffer
//
DWORD
P2PeerioDmx::SendP2PeerMsg ( HANDLE hFile
                           , P2PeerMsg *pMsg
                           , OVERLAPPEDcon *pOVERLAPPEDsend )
{
    // Isolation
    P2PsafeCS    oSafeCS = g_oCSectP2PeerConDmx;
    P2PeerioDmx *pThis   =                 this;
    P2PeerioDmx *pThat   = (P2PeerioDmx *)hFile;

    // To be sure, to be sure
    // NOTES: Confirm nothing is already loaded
    if ( pThis->m_pOVERLAPPEDsend )
      EVERR->MODULE
           ->Message("Previous SendP2PeerMsg outstanding\n"
                     "ADVICE\t: Bug(SNHappen)" )
           ->Throw();

    // To be sure, to be sure
    // NOTES: Confirm interface is operational.  Specialisation is
    //        thread safe mechanism to monitor other side.  Must be
    //        protected by above critical section
    if ( m_pCon->GetUDState() == 0 )
    {
      pOVERLAPPEDsend -> hr = ERROR_OPERATION_ABORTED;
      m_pCon -> PostOVERLAPPED ( pOVERLAPPEDsend );
      return 0;
    }

    // Setup send
    // NOTES: Receiver does the copy.  The buffer effectively sits idle
    //        locally until the receiver becomes available.
    if ( pMsg )
    {
      pMsg -> PrepareIOmage  ( GetIFmask() );      // Mandatory
                 pOVERLAPPEDsend -> pBuffer = (char *)pMsg->IOmage ();
                 pOVERLAPPEDsend -> dwBytes =         pMsg->IOmageSize ();
                 pOVERLAPPEDsend -> dwBytesMax = 0;
      //pThis -> m_pCon -> prepareOVERLAPPED ( pOVERLAPPEDsend );
      pThis -> m_pOVERLAPPEDsend = pOVERLAPPEDsend;
      SetLastError ( ERROR_IO_PENDING );
    }

    // Notification
    // NOTES: Handle that P2PeerCon waiting for buffer to be received
    OVERLAPPEDcon *pOVERLAPPEDrecv = pThat -> m_pOVERLAPPEDrecv;
    if (  pOVERLAPPEDrecv          &&
         !pOVERLAPPEDrecv->bQueued    )
    {
      // Notification
      // NOTES: That side suspended for send completion
      //pThat -> m_pCon -> releaseOVERLAPPED ( pOVERLAPPEDrecv );
      pThat -> m_pOVERLAPPEDrecv = 0;
      pThat -> m_pCon -> PostOVERLAPPED ( pOVERLAPPEDrecv );
    }

    // Tidy up and
    return 0;
}

//
//  Receives next P2PeerMsg
//  NOTES: Handles receipt of following message types P2PeerMsg images,
//         including headers BSTR images, headers manufactured
//       : Override for other message formats
//
//
//  Parameters: HANDLE hFile
//              Receive P2PeerMsg file handle
//
//              OVERLAPPEDcon *pOVERLAPPEDrecv
//              Pointer to an OVERLAPPEDcon receive buffer
//
//  Returns:    P2PeerMsg*
//              Received P2PeerMsg.  Client assumes control over
//              life cycle
//                0.. Incomplete, queued IO completion port receive
//
P2PeerMsg*
P2PeerioDmx::RecvP2PeerMsg ( HANDLE hFile
                           , OVERLAPPEDcon *pOVERLAPPEDrecv )
{
    // Isolation
    // NOTES: This is mandatory whilst we work across the address space
    //        of multiple threads
    P2PsafeCS    oSafeCS = g_oCSectP2PeerConDmx;
    P2PeerioDmx *pThis   =                 this;
    P2PeerioDmx *pThat   = (P2PeerioDmx *)hFile;
    P2PeerMsg   *pMsg    = 0;

    // To be sure, to be sure
    if ( pThis->m_pOVERLAPPEDrecv                    &&
         pThis->m_pOVERLAPPEDrecv != pOVERLAPPEDrecv    )  //TODO:LJM added to qualify previous line 27/12/2010
      EVERR->MODULE
           ->Message("Previous RecvP2PeerMsg outstanding" )
           ->Advice ("Bug(SNHappen)" )
           ->Throw();

    // To be sure, to be sure
    // NOTES: Confirm interface is operational.  Specialisation is
    //        thread safe mechanism to monitor other side.  Must be
    //        protected by above critical section
    if ( m_pCon->GetUDState() == 0 )
    {
      pOVERLAPPEDrecv -> hr = ERROR_OPERATION_ABORTED;
      m_pCon -> PostOVERLAPPED ( pOVERLAPPEDrecv );
      return 0;
    }

    // Data exists
    // NOTES: Handle that P2PeerCon waiting for buffer to be received
    OVERLAPPEDcon *pOVERLAPPEDsend = pThat -> m_pOVERLAPPEDsend;
                                     pThis -> m_pOVERLAPPEDrecv = 0;
    if ( pOVERLAPPEDsend          /*&&
         pOVERLAPPEDsend->bQueued*/    )
    {
      // To be sure, to be sure
      DWORD dwBytes = pOVERLAPPEDsend -> dwBytes;
      if ( dwBytes )
      {
        pThat -> m_pOVERLAPPEDsend = 0;
        VBListIOmage *pIOmage = (VBListIOmage *)pOVERLAPPEDsend -> pBuffer;
                                                pOVERLAPPEDsend -> pBuffer = 0;
                                                pOVERLAPPEDsend -> dwBytes = 0;
        if ( pIOmage->oSync.uiSync1+pIOmage->oSync.uiSync2 != ~0 )
          EVERR->MODULE
              ->Message("Corrupted VBListIOmage header (%x + %x) compliment"
                        , pIOmage->oSync.uiSync1, pIOmage->oSync.uiSync2 )
              ->Advice ("Bug(SNHappen)" )
              ->Throw();
        if ( (pIOmage->oSync.uiSync1&0x00FFFFFF)+sizeof(pIOmage->oSync) > dwBytes )
          EVERR->MODULE
              ->Message("Corrupted VBListIOmage byte (%x vs %x) byte count"
                        , pIOmage->oSync.uiSync1, dwBytes )
              ->Advice ("Bug(SNHappen)" )
              ->Throw();

        // P2PeerMsg receipt
        // NOTES: Image copy only, mandatory sender retains ownership for
        //        re-use etc
        pMsg = new P2PeerMsg ( *pIOmage );
      }

      // Notification
      // NOTES: That side suspended for send completion
      //pThat -> m_pCon -> releaseOVERLAPPED ( pOVERLAPPEDsend );
      pThat -> m_pCon -> PostOVERLAPPED ( pOVERLAPPEDsend );
    }

    // Nothing waiting
    // NOTES: Flag ourselves as being queued and passively wait.  Set
    //        internal to indicate such.
    if ( !pMsg )
    {
      //pThis -> m_pCon -> prepareOVERLAPPED ( pOVERLAPPEDrecv );
      pThis -> m_pOVERLAPPEDrecv = pOVERLAPPEDrecv;
      SetLastError ( ERROR_IO_PENDING );
    }

    // Tidy up and
    return pMsg;
}

//
//  Resets internals
//  NOTES: Intention is for object to be left in a re-usable state
//
void
P2PeerioDmx::Reset ( )
{
    // Delegate
  __super::Reset ( );

    // Attributes
    //if ( m_pOVERLAPPEDsend && m_pCon )
    //  m_pCon -> releaseOVERLAPPED ( m_pOVERLAPPEDsend );
    m_pOVERLAPPEDsend = 0;
    //if ( m_pOVERLAPPEDrecv && m_pCon )
    //  m_pCon -> releaseOVERLAPPED ( m_pOVERLAPPEDrecv );
    m_pOVERLAPPEDrecv = 0;
}

///////////////////////////////////////////////////////////////////////
//  Troubleshooting

void
P2PeerioDmx::AssertValid ( ) const
{
    // Firstly delegate
    __super::AssertValid ( );

    // TODO: Additional validation
}
