#ifndef DuplexSocket_HH
#define DuplexSocket_HH

#include <iostream>

#include "Socket.hh"
#include "ListenerSocket.hh"


class DuplexSocket : public Socket {

public:

  DuplexSocket() {
  }

  DuplexSocket(const ListenerSocket& listener) {
    initialise(listener);
  }

  DuplexSocket(int port, bool singleSocket=true) {
    ListenerSocket listener(port);
    initialise(listener);
    // MULTIPLE SOCKETS FROM LISTENER???
  }

  void initialise(const ListenerSocket& listener) {
    if ( ! Socket::accept ( listener ) )
      {
	throw SocketException ( "DuplexSocket could not accept socket.");
      }
  }

  DuplexSocket ( std::string host, int port, int tries = 0 ) {
    initialise(host,port,tries);
  }

  void initialise ( std::string host, int port, int tries = 0 ) {
    if ( ! Socket::create() )
      {
        throw SocketException ( "DuplexSocket could not create client socket." );
      }    
    if ( ! Socket::connect ( host, port ) )
      {
	int n(0);
	for(n=0;n<tries;n++) {
	  sleep(1);
	  std::cout << "DuplexSocket connect failed; retry " 
		    << n << "/" << tries << std::endl;
	  if ( Socket::connect ( host, port ) ) n=tries+1;
	}
        if(n==tries) throw SocketException ( "DuplexSocket could not bind to port." );
      }
  }

  virtual ~DuplexSocket() {
  }

  //  const DuplexSocket& operator << ( const std::string& ) const;
  //  const DuplexSocket& operator >> ( std::string& ) const;

//  const DuplexSocket& operator << ( int ) const;
//  const DuplexSocket& operator >> ( int& ) const;


  //template<class T> bool DuplexSocket::send( const T* t, int n = 1 ) {
  template<class T> bool send( const T* t, int n = 1 ) {
    if ( ! Socket::send(t,n) )
      {
	//throw SocketException ( "DuplexSocket could not write to socket.");
	std::cerr << "DuplexSocket could not write to socket." << std::endl;
	return false;
      }
    return true;
  }

  //template<class T> int DuplexSocket::recv( T* t, int m = 1) {
  template<class T> int recv( T* t, int m = 1) {
    int n=Socket::recv(t,m);
    if (n <= 0)
      {
        throw SocketException ( "DuplexSocket could not read from socket.");
      }
    return n;
  }

  //template<class T> bool DuplexSocket::send( const T& t ) const {
  template<class T> bool send( const T& t ) const {
    //    if ( ! Socket::send(t) )
    //      {
    //	throw SocketException ( "DuplexSocket could not write to socket.");
    //      }
    //    return true;
    return send(&t,1);
  }

  //template<class T> int DuplexSocket::recv( T& t ) const {
  template<class T> int recv( T& t ) const {
    //    if ( ! Socket::recv(t) )
    //      {
    //	throw SocketException ( "DuplexSocket could not read from socket.");
    //      }
    //    return true;
    return recv(&t,1);
  }

  void print(std::ostream &o) const {
    Socket::print(o);
  }
};

#endif
