#include "packet.h"
#include "flow.h"
#include "generator.h"
#include "popt.h"
#include "unixtime.h"
#include "sink.h"
#include "otr_application.h"

#define MAXBUFLENGTH 10000

#ifndef GATE_H
#define GATE_H

#define MAX_STREAM_NUM_PER_GATE 16
#define DEFAULT_RECV_PORT 4000


// changes in Sep, 2005 removal of flow in OTR design


/** 
 * Gate is an abstract class for the interface to receive a packet, whether UDP, TCP Socket, or LIBMAC inteface.
 * The common funcitons for a port are defiend here:
 * - Receive Packet
 *
 * Genereally, the OTR architrecture assume  one OTR could have more than one gates. Each gate is bound to only one port.
 * Thus, if there are multiple ports used to receive packets, there are multiple gates. 
 * There is only one thread associated with each gate. One gate, one thread. The gate could have multiple flows,
 * but unlike Port, "Gate" is in charge of reception, and flow is passive, associated with sender address and a sink.  
 */

class Gate
{
public:
   Gate();
   virtual ~Gate(){}
   /**
    * Function to initialize the port
    * @param app: OrbitApp object associate with this gate.
    * @param sin: the default traffic sink used for this Gate, could be NULL
    */
   virtual void init()=0;
   /**
    *  Function to start an endless receiving loop
    *  This Marks the beginning of an independent receiving thread
    */
   virtual void startReceive()=0;
   /**
    * Function to receive a packet. Support receiving multiple streams for UDP or TCP.
    * For UDP, the default sockfd wlll be used for call recvfrom() whatever sender it is.
    * For TCP, the default sockfd will be used for listen new connectiongs.
    * and a new file descriptor has to be created dynamicalluy for call recv()
    * param fd: the file descriptor to call recv or recvfrom function
    */
   virtual bool receivePacket(int fd)=0;
   /**
    * Function to close a port
    */
   virtual void closeGate()=0;
   /**
    * Function to get Command line Options
    *
    */
   virtual const struct poptOption* getOptions()=0; 
     
   void configGate(OrbitApp* app, Sink* sin, int clockref=-1);
   Flow* createFlow(int recvfd);
   //Flow* createFlow(int recvfd, Sink * sin);
   Flow* addFlow(int flowid, Address *src);
   bool deleteFlow(Flow *strm);
   Flow *searchFlowbyFd (int fd);
   Flow *searchFlowbyAddress (Address *addr);
   int getFlowNum();
   void inboundPacket();
   Flow* demultiplex(Address* addr);
protected:
  
   /**This pointer points to the packet.
    * This packet is just received in OTR
    */
   Packet *pkt_;    
   Flow* rlhead_;   ///<  This points to the head of Incoming flow List
   Flow* rltail_;   ///<  This points to the tail of incoming flow List
   Flow* rlcurr_;  ///< This points to the incoming flow whose packet buffer is receving packet now...
   Address myaddr_;  ///< The default address of mine 
   Address itsaddr_; ///< This variable could be used to store the source address of incoming packet
   UnixTime gateclock_;
   int flownum_;
   Sink *sin_;
   OrbitApp *app_;

};

#endif


