#ifndef RcdIo2Skt_HH
#define RcdIo2Skt_HH

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <iostream>

#include "RcdWriter.hh"
#include "DuplexSocket.hh"

class RcdIo2Skt : public RcdIoBase {

public:
  RcdIo2Skt() {
  }

  virtual ~RcdIo2Skt() {
    close();
  }

  bool open(unsigned skt, std::string host, unsigned port, unsigned tries) {
    assert(skt<2);
    _fileName[skt]=host;
    _socket[skt]=new DuplexSocket(host,port,tries);
    return open2(skt);
  }

  bool open(unsigned skt, unsigned port) {
    assert(skt<2);
    _fileName[skt]="listener";
    _socket[skt]=new DuplexSocket(port);
    return open2(skt);
  }

  bool open2(unsigned skt) {
    _readNumberOfBytes=0;
    _writeNumberOfBytes=0;

    if(_socket[skt]==0) {
      std::cerr << "RcdIo2Skt::open()   Error opening socket "
		<< _fileName[skt] << std::endl;
      return false;
    }

    std::cout << "RcdIo2Skt::open()   Opened socket "
	      << _fileName[skt] << std::endl;
    return true;
  }

  bool read(RcdRecord &r) {
    bool result(true);

    RcdRecord *p[2];
    p[0]=&r;
    p[1]=new RcdArena;

    for(unsigned skt(0);skt<2;skt++) {
      if(_socket[skt]==0) {
	result=false;
      } else {

	int n(0);
 
	n=_socket[skt]->recv((char*)p[skt],sizeof(RcdRecord));
	if(n<=0) {
	  std::cout << "RcdIo2Skt::read()   Expected end-of-file" << std::endl;
	  return false;
	}
	_readNumberOfBytes+=sizeof(RcdRecord);

	if(r.numberOfWords()>0) {
	  n=_socket[skt]->recv((char*)(p[skt]+1),4*r.numberOfWords());
	  if(n<=0) {
	    std::cerr << "RcdIo2Skt::read()   Unexpected end-of-file ";
	    perror(0);
	    return false;
	  }
	  _readNumberOfBytes+=4*r.numberOfWords();
	}
      }
    }

    assert(*((RcdHeader*)p[0])==*((RcdHeader*)p[1]));

    delete p[1];
    return result;
  }

  bool write(const RcdRecord &r) {
    bool result(true);

    for(unsigned skt(0);skt<2;skt++) {
      if(_socket[skt]==0) {
	result=false;
      } else {

	int n(r.totalNumberOfBytes());
	if(!_socket[skt]->send((const char*)(&r),n)) {
	  std::cerr << "RcdIo2Skt::write()  Error writing to file; number of bytes written < "
		    << n << std::endl;
	  perror(0);
	  //_numberOfBytes+=n;
	  result=false;
	}

	_writeNumberOfBytes+=r.totalNumberOfBytes();
      }
    }

    return result;
  }

  bool close() {
    std::cout << "RcdIo2Skt::close()  Closed socket "

    bool result(true);

    for(unsigned skt(0);skt<2;skt++) {
      if(_socket[skt]==0) {
	result=false;
      } else {
	delete _socket[skt];
	std::cout << _fileName[skt] << ", ";
	_socket[skt]=0;
      }
    }

    std::cout << " after reading, writing "
	      << _readNumberOfBytes << ", " << _writeNumberOfBytes
	      << " bytes" << std::endl;
    _writeNumberOfBytes=0;
    _readNumberOfBytes=0;

    return result;
  }

  unsigned numberOfBytes(bool w=true) const {
    if(w) return _writeNumberOfBytes;
    else  return _readNumberOfBytes;
  }


private:
  DuplexSocket *_socket[2];
  std::string _fileName[2];
  unsigned _readNumberOfBytes;
  unsigned _writeNumberOfBytes;
};

#endif
