//
//  Copyright © 2001 - 2002, RESON Inc. All Rights Reserved.
//
//  No part of this file may be reproduced or transmitted in any form or by
//  any means, electronic or mechanical, including photocopy, recording, or
//  information storage or retrieval system, without permission in writing
//  from RESON Inc.
//
//  Filename:   C7kSocketProtocol.h
//
//  Project:    6046.
//
//  Author(s):  W. Arcus
//
//  Purpose:    Class definition file for the socket protocol.
//
//  Notes:
//

#if !defined(AFX_7KSOCKETPROTOCOL_H__865CE377_0B57_412C_8568_5BCDD94C2019__INCLUDED_)
#define AFX_7KSOCKETPROTOCOL_H__865CE377_0B57_412C_8568_5BCDD94C2019__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "DynamicBuffer.h"

#pragma warning( push, 3 )                  // Microsoft's STL vector implementation is dirty at warning level 4.
#pragma warning( disable: 4018 )
#include <vector>
#pragma warning( default: 4018 )
#pragma warning( pop )

const unsigned short unDefault7kProtocolVersion_c = 1;

#pragma pack( push, SOCKETPROTOCOL_H_PACK, 1 )

typedef struct tagNETWORKFRAMEHEADER
{
    unsigned short  m_unVersion;            // Version of this frame (e.g.: 1, 2, …)
    unsigned short  m_unOffset;             // Offset, in bytes, to the start of data from the start of this packet.
    unsigned long   m_ulTotalPackets;       // Number of network packets for set of records transmitted
    unsigned long   m_ulPacketSize;         // Size in bytes of this packet including the header and appended data.
    unsigned long   m_ulSequenceNumber;     // Sequential packet number; allows correct ordering during reconstruction. Range: 0 (zero) to N - 1 packets.

    tagNETWORKFRAMEHEADER(  unsigned long   ulTotalPackets      = 1UL,
                            unsigned long   ulPacketSize        = 0UL,
                            unsigned long   ulSequenceNumber    = 0UL,
                            unsigned short  unVersion           = unDefault7kProtocolVersion_c )
    {
        Reset();

        m_ulTotalPackets   = ulTotalPackets;
        m_ulPacketSize     = ulPacketSize;
        m_ulSequenceNumber = ulSequenceNumber;
        m_unVersion        = unVersion;
    }

    static unsigned short Size( void )
    {
        return sizeof( struct tagNETWORKFRAMEHEADER );
    }

    void Reset( void )
    {
        memset( this, 0x00, Size() );

        m_unVersion        = unDefault7kProtocolVersion_c;
        m_unOffset         = Size();
    }

    bool IsValid( void ) const
    {
        const unsigned long ulSize = Size();

        return ( ( m_ulPacketSize >= ulSize ) &&
                 ( m_unOffset     >= ulSize ) &&
                 ( m_unVersion    >= 1 ) );
    }

}
NETWORKFRAMEHEADER, *PNETWORKFRAMEHEADER;

#pragma pack( pop,  SOCKETPROTOCOL_H_PACK )

class EXPORT_DLL C7kSocketProtocol
{
public:

    // Construction and destruction.

                            C7kSocketProtocol         (   void );
    virtual                ~C7kSocketProtocol         (   void );

    // Services for decoding.

    // Decoding.

    unsigned long           BytesFollowingHeader        (   void ) const;

    bool                    IsRecordComplete            (   void ) const;

    bool                    ResetDecoder                (   void );

    bool                    Add                         (   const BYTE          *pbyStream,
                                                            const unsigned long &rulBytes,
                                                            const bool          &rbIsHeader );

    BYTE *                  DecodedRecord               (   void );

    unsigned long           DecodedRecordBytes          (   void );

    static bool             IsValidHeader               (   const BYTE          *pbyStream,
                                                            const unsigned long &rulNumBytes );

    static unsigned long    GetHeaderSize               (   void );

    // Encoding.
                                                    
    bool                    EncodePackets               (   BYTE               *pbyStream,
                                                            unsigned long       ulNumBytes );
                                                    
    unsigned long           GetNumberOfPackets          (   void );
                                                    
    BYTE *                  GetNextPacket               (   unsigned long      &rulBytesInPacket );
 
private:

    ///////////////
    // Defintions.

    class CEncode : public CDynamicBuffer<BYTE>
    {
    private:

        typedef struct tagPACKETINDEX
        {
            unsigned long   ulPacketSizeInBytes;
            BYTE           *pbyStartOfPacketInFifo;

            tagPACKETINDEX( unsigned long   ulPacketSize = 0UL,
                            BYTE *          pbyPacket    = NULL )
            {
                ulPacketSizeInBytes     = ulPacketSize;
                pbyStartOfPacketInFifo  = pbyPacket;
            }
        }
        PACKETINDEX;

        typedef std::vector<PACKETINDEX>    PacketIndex_t;
        typedef PacketIndex_t::iterator     PacketIndexIterator_t;

        const unsigned long                 m_ulMaxPacketSize;
     
        unsigned long                       m_ulNumberOfPackets;

        PacketIndex_t                       m_PacketIndex;
        PacketIndexIterator_t               m_pLastRetrievedPacket;

        NETWORKFRAMEHEADER                  m_sPacketHeader;

        void                    ResetEncoder        (   void );

        bool                    EncodeNextPacket    (   BYTE          **ppbyPacket,
                                                        unsigned long  *pulBytesLeft,
                                                        unsigned long   ulPacket,
                                                        unsigned long   ulMaxPacketSize,
                                                        unsigned short  unProtocolVersion );


    public:
                                CEncode             (   void );
        virtual                ~CEncode             (   void );

        bool                    EncodePackets       (   BYTE           *pbyStream,
                                                        unsigned long   ulNumBytes,
                                                        unsigned long   ulMaxPacketDataSize,
                                                        unsigned short  unProtocolVersion );

        unsigned long           NumberOfPackets     (   void ) const;

        BYTE *                  GetNextPacket       (   unsigned long  &rulBytesInPacket );

    };

    class CDecode : public CDynamicBuffer<BYTE>
    {
    public:                 
                                CDecode                 (   void );
        virtual                ~CDecode                 (   void );

        bool                    ProcessFrame            (   const BYTE          *pbyFrame,
                                                            const unsigned long &rulBytes,
                                                            const bool          &rbIsHeader );

        unsigned long           DynamicBytesThisFrame   (   void ) const;

        bool                    IsRecordComplete        (   void ) const;

        void                    Reset                   (   void );

    private:

        typedef enum tagSTATE                                               // States of the packet sequencer (state machine).
        {
            stateIdle,
            stateAccumulate,
            stateDone,
            stateReset
        }
        ESTATE;

        bool                    m_bRecordIsReady;
        ESTATE                  m_eState;
        unsigned long           m_ulLastSequenceNumber;
        unsigned long           m_ulDynamicBytesThisFrame;

    };

    ///////////////
    // Attributes.

    const unsigned long         m_ulMaxPacketSize;
    const unsigned long         m_ulHeaderSize;
    const unsigned short        m_unProtocolVersion;

    std::auto_ptr<CEncode>      m_pEncoder;
    std::auto_ptr<CDecode>      m_pDecoder;

    ///////////////
    // Services.

};

#endif // !defined(AFX_7KSOCKETPROTOCOL_H__865CE377_0B57_412C_8568_5BCDD94C2019__INCLUDED_)
