/**@file*/
#ifndef UDPConnection_h_DEFINED
#define UDPConnection_h_DEFINED

#include <ant.h>
#include <IPAddress.h>
#include <OPENR/OSyslog.h>

/** Stati delle connessioni UDP. */
enum ConnectionState {
  CONNECTION_INVALID =0,    /**< Connessione non valida*/
  CONNECTION_CLOSED =1,     /**< Connessione chiusa*/
  CONNECTION_BINDED =2,     /**< Connessione binded, collegata con la relativa porta*/
  CONNECTION_WAITING =3,    /**< Connessione in attesa di spedire*/
  CONNECTION_LISTENING =4,  /**< Connessione in attesa di riecevere*/
  CONNECTION_SENDING =5,    /**< Connessione in spedizione*/
  CONNECTION_RECEIVING =6,  /**< Connessione in ricezione*/
  CONNECTION_CLOSING =7,    /**< Connessione in fase di chiusura*/
  CONNECTION_WAITING_ACK =8 /**< Connessione in attesa di ricevere un Ack*/
};

/**Connessione UDP. Implementa una connessione UDP priva di buffer da
   specializzare attraverso l'ereditarieta'*/
class UDPConnection {
 public:
  /**Costruttore di default. Dopo l'invocazione la connessione sara'
     INVALID.*/
  UDPConnection() {state = CONNECTION_INVALID;};
  /**Costruttore di base. Costruisce una connessione impostando lo
     stato a CLOSED. @param ipStack riferimento allo stack TCP/IP
     dell'Aibo.*/
  UDPConnection(antStackRef ipStack) {ipstackRef=ipStack; state = CONNECTION_CLOSED;  };

  /**Distruttore di default.*/
  virtual ~UDPConnection() {};

  /** Enpoint della connessione. Restituisce l'Endpoint della
      connessione UDP. @return endpoint della connessione.*/
  inline antModuleRef& getEndpoint() {return endpoint;};
  /** Modifica lo stato della connessione. @param st nuovo stato della
      connessione.*/
  inline void setState(ConnectionState st) {state = st;};
  /** Restituisce lo stato corrente della connessione. @return stato
      corrente*/
  inline ConnectionState getState() {return state;};
  
  /** Inizializza la connessione. Da implementare. Ha il compito di
      inizializzare i buffer, creare l'endpoint e fare il bind della
      connessione. @return oSUCCESS se ha avuto successo; oFAIL
      altrimenti.*/
  virtual OStatus initConnection() = 0;
  /** Blocca la connessione. Da implementare. Chiude la connessione,
      dopo la chiamata a questo metodo la connessione non sara' piu'
      utilizzabile, per riutilizzarla sara' necessario effettuare un
      nuovo initConnection sulla connessione. @return oSUCCESS se ha
      avuto successo; oFAIL altrimenti.*/
  virtual OStatus stop() = 0;  
  
 protected:
  antModuleRef endpoint;      /**< Riferimento all'Endpoint della connessione*/
  antStackRef ipstackRef;     /**< Riferimento allo stack TCP/IP dell'Aibo*/

  ConnectionState state;      /**< Stato della connessione. @see ConnectionState*/
  
};

/**Connessione UDP di Ricezione. Implementa una connessione UDP di
   sola ricezione.*/
class UDPRecvConnection : public UDPConnection { 
 public:
  /** Costruttore di Default*/
  UDPRecvConnection() {};  
  /**Costruttore. Costruisce una connessione UDP di ricezione. @param
     ipStack riferimento allo stack TCP/IP dell'Aibo. @param bs
     dimensione del buffer di ricezione in byte. @param port porta TCP
     di ricezione*/
  UDPRecvConnection(antStackRef ipStack, int bs, Port port); 

  /** Distruttore di default*/
  ~UDPRecvConnection();
  
  /**Inizializza la connessione. Inizializza il buffer di ricezione,
     crea l'endpoint e effettua il bind della connessione. @return
     oSUCCESS se ha avuto successo; oFAIL altrimenti.*/
  OStatus initConnection(); 
  /**Ferma la ricezione. Chiude la connessione, dopo la chiamata a
     questo metodo la connessione non sara' piu' utilizzabile, per
     riutilizzarla sara' necessario chiamare nuovamente
     initConnection. @return oSUCCESS se ha avuto successo; oFAIL
     altrimenti.*/
  OStatus stop();

  /**Restituisce il buffer di ricezione. @return puntatore al buffer
     di ricezione*/
  inline byte* getRecvData() { return recvData;};
  /**Restituisce la dimensione massima del pacchetto
     ricevibile. @return dimensione massima di byte ricevibili.*/
  inline int getRecvSize() { return recvSize;}
  
 private:

  antSharedBuffer recvBuffer; /* Buffer di ricezione*/
  byte* recvData;             /* Puntatore ai dati contenunti nel buffer di ricezione*/
  int recvSize;               /* Dimensione buffer di Ricezione*/

  Port recvPort;              /* Porta di ricezione*/

  OStatus initBuffer();       /* Inizializza il buffer*/	  
  OStatus initUdpEndpoint();  /* Crea l'Endpoint*/		  
  OStatus initBind();         /* Effettua il Bind dell'Endpoint*/
};


/**Connessione UDP di spedizione. Implementa una connessione UDP di
   sola spedizione.*/
class UDPSendConnection : public UDPConnection {
 public:
  /** Costruttore di Default*/
  UDPSendConnection() {}; 
  /**Costruttore. Costruisce una connessione UDP di spedizione. @param
     ipStack riferimento allo stack TCP/IP dell'Aibo. @param bs
     dimensione del buffer di spedizione in byte.*/
  UDPSendConnection(antStackRef ipStack, int bs);

  /** Distruttore*/
  ~UDPSendConnection();

  /**Inizializza la connessione. Inizializza il buffer di spedizione,
     crea l'endpoint e effettua il bind della connessione. @return
     oSUCCESS se ha avuto successo; oFAIL altrimenti.*/
  OStatus initConnection();
  /**Blocca la ricezione. Chiude la connessione, dopo la chiamata a
     questo metodo la connessione non sara' piu' utilizzabile, per
     riutilizzarla sara' necessario chiamare nuovamente
     initConnection. @return oSUCCESS se ha avuto successo; oFAIL
     altrimenti.*/
  OStatus stop();
  
  /**Ritorna buffer di spedizione. Ritorna un puntatore al buffer di
     spedizione della connessione. @return puntatore al buffer di
     spedizione.*/
  byte* getSendData() {return sendData;};
  /**Restituisce la dimensione dei dati. Restituisce la dimensione in
     byte dei dati contenuti nel buffer di spedizione in attesa di
     essere spediti. @return dimensione pacchetto da spedire*/
  inline int getSendSize() { return sendSize;}
  /**Imposta la dimensione dei dati da spedire. Imposta la dimensione
     in byte dei dati da spedire attraverso la connessione. @param
     size dimensione dei dati da spedire.*/
  inline void setSendSize(int size) { sendSize=size;}

 private:

  antSharedBuffer sendBuffer; /* Buffer di spedizione*/
  byte* sendData;             /* Puntatore ai dati contenunti nel buffer di spedizione*/
  int bufferSize;             /* Dimensione del buffer*/
  int sendSize;               /* Dimensione dei dati spediti*/

  OStatus initBuffer();       /*Inizializza il buffer*/	  
  OStatus initUdpEndpoint();  /*Crea l'Endpoint*/		  
  OStatus initBind();	      /*Effettua il Bind dell'Endpoint*/
};

#endif // UDPConnection_h_DEFINED
