#ifndef _MGEN_FLOW
#define _MGEN_FLOW

#include "mgenEvent.h"
#include "mgenSocketList.h"
#include "gpsPub.h"
#include "protokit.h"
#include <stdio.h>  // for FILE

// Prototype for function to retrieve position/status
// (See gpsPub.h for GPSPosition definition)
typedef bool (MgenPositionFunc)(const void*     clientData,
                                GPSPosition&    gpsPosition);

// protocol SINK may be used as an alternative to socket
// based protocols (e.g. UDP).  In this case, class Mgen
// (and its flows) must be assigned a pointer to an
// instance of class MgenSink which has a "SendMgenMessage()"
// method which is used instead of a socket send() or sendto()

class MgenSink
{
    public:
        MgenSink();
        virtual ~MgenSink();
        virtual bool SendMgenMessage(const char*           txBuffer,
                                     unsigned int          len,
                                     const ProtoAddress&   dstAddr) = 0;
        virtual void StartNotifying(class MgenFlow* theFlow) 
            {notify_flow= theFlow;}
        virtual void StopNotifying()
            {notify_flow= NULL;}
        bool IsNotifying() 
            {return (NULL != notify_flow);}
        
    protected:
        class MgenFlow* notify_flow;
};  // end class MgenSink

class MgenFlow
{
    friend class MgenFlowList;
  
    public:
        MgenFlow(unsigned int       flowId, 
                 ProtoTimerMgr&  timerMgr,
                 MgenSocketList&    socketList,
                 unsigned long      defaultV6Label = 0);
    
        ~MgenFlow();
        
        void SetPositionCallback(MgenPositionFunc*  callback, 
                                 const void*        clientData) 
        {
            get_position = callback;
            get_position_data = clientData;
        }
        
#ifdef HAVE_GPS
        void SetPayloadHandle(GPSHandle payloadHandle) 
            {payload_handle = payloadHandle;}
#endif // HAVE_GPS
        
        void SetSink(MgenSink* theSink) {sink = theSink;}
	    void SetLogFile(FILE* logFile, bool binary, bool logFlush) 
            {log_file = logFile; log_binary = binary; log_flush = logFlush;}
        
        void SetHostAddress(const ProtoAddress hostAddr) 
        {
            host_addr = hostAddr;
            if (socket) host_addr.SetPort(socket->GetPort());
        }
        void ClearHostAddress() {host_addr.Invalidate();}
        
        void EnableChecksums() {checksum_enable = true;}
        bool InsertEvent(MgenEvent* event, bool mgenStarted, double currentTime);
        bool ValidateEvent(const MgenEvent* event);
        bool Start(double offsetTime);
        bool Update(const MgenEvent* event);
        
        bool IsActive() const;
        double GetCurrentOffset() const;
#ifdef HAVE_IPV6
        void SetLabel(UINT32 label) {flow_label = label;}
#endif //HAVE_IPV6
        void Notify() {OnTxTimeout(tx_timer);}
        
    private:
        bool OnTxTimeout(ProtoTimer& theTimer);
        bool OnEventTimeout(ProtoTimer& theTimer);
            
    	FILE*                   log_file;                 
        bool                    log_binary;  
        bool                    log_flush;   
        bool                    checksum_enable;                

        unsigned long           flow_id;                       
        MgenBaseEvent::Protocol protocol;                      
        ProtoAddress            dst_addr;                      
        unsigned short          src_port;    
        ProtoAddress            host_addr;  // src addr concept

        MgenPattern             pattern;                     
        UINT32                  flow_label;                  

        ProtoTimer              tx_timer;  
                          
        MgenSocketList::Item*   socket_item;               
        ProtoSocket*            socket;   
        MgenSink*               sink; // for protocol "SINK"
                         
        unsigned long           seq_num;                     
        double                  last_interval;               

        MgenEventList           event_list;                  
        MgenEvent*              next_event;                  
        ProtoTimer              event_timer;                 
        bool                    started;                     
        
        ProtoTimerMgr&          timer_mgr;                 
        MgenSocketList&         socket_list;               
        
        MgenPositionFunc*       get_position;              
        const void*             get_position_data;         
#ifdef HAVE_GPS
        GPSHandle               payload_handle;              
#endif // HAVE_GPS
        
        MgenFlow*               prev;                        
        MgenFlow*               next;                        
    
};  // end class MgenFlow


class MgenFlowList
{
    public:
        MgenFlowList();
       ~MgenFlowList();

        void Destroy();
        void Append(MgenFlow* theFlow);
	    void SetLogFile(FILE* filePtr, bool binary, bool flush);
        void EnableChecksums();
        void SetSink(MgenSink* theSink);
        void SetHostAddress(const ProtoAddress& hostAddr);
        void ClearHostAddress();
        
        MgenFlow* FindFlowById(unsigned int flowId);
        bool IsEmpty() {return (NULL == head);}

        bool Start(double offsetTime);
        
        double GetCurrentOffset() const;
        bool SaveFlowSequences(FILE* file) const;
        void SetDefaultLabel(UINT32 label);
    private:
        MgenFlow* head; 
        MgenFlow* tail;  
}; // end class MgenFlowList 

#endif  // _MGEN_FLOW


syntax highlighted by Code2HTML, v. 0.9.1