#ifndef COSY_MTcpIpIO
#define COSY_MTcpIpIO

#ifndef COSY_MsgQueue
#include "msgqueue.h"
#endif
#ifndef MARS_MTime
#include "MTime.h"
#endif
#ifndef ROOT_TMutex
#include <TMutex.h>
#endif


class TString;
class TSocket;
class TServerSocket;

// A generalized class for receiving over tcp/ip
class MTcpIpI : public MThread
{
protected:
    TSocket *fRxSocket;
    TMutex   fRxMutex;

private:
    Int_t  fPortRx;     // Port on which to listen for connections
    Int_t  fTimeout;    // [ms] Timeout to listen for data to be received

    Bool_t fConnectionEstablished;

    MTime  fLast;

    Bool_t WaitForData(TSocket &sock);
    void   WaitForConnection(TServerSocket &server);

    Int_t Thread();

    virtual Bool_t ReadSocket(TSocket &rx) = 0;

public:
    MTcpIpI(Int_t rx, UInt_t timeout=5000) : MThread(Form("MTcpIpI::%d", rx)), fRxSocket(0), fPortRx(rx), fTimeout(timeout), fConnectionEstablished(kFALSE) { /*RunThread();*/ }
    ~MTcpIpI() { CancelThread(); }

    Bool_t IsConnectionEstablished() const { return fConnectionEstablished; }
};


// A generalized class for sending over tcp/ip
class MTcpIpO : public MThread
{
protected:
    TSocket *fTxSocket;
    TMutex   fMutex;

    Int_t fPortTx;

    Int_t Thread();

public:
    MTcpIpO(const char *addr, Int_t tx);
    ~MTcpIpO();

    static TString GetSocketAddress(const TSocket &s);
    static bool    SendFrame(TSocket &tx, const char *msg, int len);
    static bool    SendFrame(const char *addr, int port, const char *msg, int len);

    bool Send(const char *msg, int len);
};

class MTcpIpCC : public MTcpIpI
{
private:
    Bool_t ReadSocket(TSocket &rx);

public:
    MTcpIpCC(Int_t rx, UInt_t timeout=5000);

    virtual bool InterpreteStr(TString str);
};

// This class es espcially meant to receive and send ascii messages
class MTcpIpIO : public MTcpIpCC, public MTcpIpO
{

public:
    MTcpIpIO(const char *addr, Int_t tx, Int_t rx, UInt_t timeout=5000);
};

class MTcpIpOI : public MTcpIpO
{
private:
    Int_t Thread();
    virtual Bool_t ReadSocket(TSocket &rx) = 0;

    Bool_t fConnectionEstablished;
    Int_t  fTimeout;    // [ms] Timeout to listen for data to be received
public:
    MTcpIpOI(const char *addr, Int_t tx, UInt_t timeout=5000) : MTcpIpO(addr, tx), fConnectionEstablished(kFALSE), fTimeout(timeout) { }

    Bool_t IsConnectionEstablished() const { return fConnectionEstablished; }
};

class MTcpIpFact : public MTcpIpCC
{
private:

public:
    MTcpIpFact(const char *dumm1, Int_t dummy2, Int_t rx, UInt_t timeout) : MTcpIpCC(rx, timeout)
    {
    }

    bool Send(const char *msg, int len);
};


#endif
