    // @(#)root/net:$Name:  $:$Id: TMonitor.cxx,v 1.5 2002/10/03 17:59:23 rdm Exp $
    // Author: Fons Rademakers   09/01/97

    /*************************************************************************
     * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TMonitor                                                             //
    //                                                                      //
    // This class monitors activity on a number of network sockets.         //
    // The actual monitoring is done by TSystem::DispatchOneEvent().        //
    // Typical usage: create a TMonitor object. Register a number of        //
    // TSocket objects and call TMonitor::Select(). Select() returns the    //
    // socket object which has data waiting. TSocket objects can be added,  //
    // removed, (temporary) enabled or disabled.                            //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #include "TMonitor.h"
    #include "TSocket.h"
    #include "TList.h"
    #include "TSystem.h"
    #include "TSysEvtHandler.h"
    #include "TTimer.h"
    #include "TError.h"

    //---- Socket event handler ----------------------------------------------------
    //
    // This utility class is only used by TMonitor.
    //

    class TSocketHandler : public TFileHandler {
    private:
       TMonitor  *fMonitor;   //monitor to which this handler belongs
       TSocket   *fSocket;    //socket being handled

    public:
       TSocketHandler(TMonitor *m, TSocket *s, Int_t interest);
       Bool_t   Notify();
       Bool_t   ReadNotify() { return Notify(); }
       Bool_t   WriteNotify() { return Notify(); }
       TSocket *GetSocket() const { return fSocket; }
    };

    TSocketHandler::TSocketHandler(TMonitor *m, TSocket *s, Int_t interest)
                   : TFileHandler(s->GetDescriptor(), interest)
    {
       fMonitor = m;
       fSocket  = s;

       Add();
    }

    Bool_t TSocketHandler::Notify()
    {
       fMonitor->SetReady(fSocket);
       return kTRUE;
    }

    //---- Timeout timer -----------------------------------------------------------
    //
    // This utility class is only used via TMonitor::Select(Int_t timeout)
    //

    class TTimeOutTimer : public TTimer {
    private:
       TMonitor   *fMonitor;   //monitor to which this timer belongs

    public:
       TTimeOutTimer(TMonitor *m, Long_t ms);
       Bool_t  Notify();
    };

    TTimeOutTimer::TTimeOutTimer(TMonitor *m, Long_t ms)
                  : TTimer(ms, kTRUE)
    {
       fMonitor = m;
       gSystem->AddTimer(this);
    }

    Bool_t TTimeOutTimer::Notify()
    {
       fMonitor->SetReady((TSocket *)-1);
       Remove();       // one shot only
       return kTRUE;
    }
    //------------------------------------------------------------------------------

    ClassImp(TMonitor)

    //______________________________________________________________________________
     TMonitor::TMonitor()
    {
       // Create a monitor object.

       Assert(gSystem);

       fActive   = new TList;
       fDeActive = new TList;
    }

    //______________________________________________________________________________
     TMonitor::~TMonitor()
    {
       // Cleanup the monitor object. Does not delete socket being monitored.

       fActive->Delete();
       SafeDelete(fActive);

       fDeActive->Delete();
       SafeDelete(fDeActive);
    }

    //______________________________________________________________________________
     void TMonitor::Add(TSocket *sock, EInterest interest)
    {
       // Add socket to the monitor's active list. If interest=kRead then we
       // want to monitor the socket for read readiness, if interest=kWrite
       // then we monitor the socket for write readiness, if interest=kRead|kWrite
       // then we monitor both read and write readiness.

       fActive->Add(new TSocketHandler(this, sock, (Int_t)interest));
    }

    //______________________________________________________________________________
     void TMonitor::Remove(TSocket *sock)
    {
       // Remove a socket from the monitor.

       TIter next(fActive);
       TSocketHandler *s;

       while ((s = (TSocketHandler *) next())) {
          if (sock == s->GetSocket()) {
             fActive->Remove(s);
             delete s;
             return;
          }
       }

       TIter next1(fDeActive);

       while ((s = (TSocketHandler *) next1())) {
          if (sock == s->GetSocket()) {
             fDeActive->Remove(s);
             delete s;
             return;
          }
       }
    }

    //______________________________________________________________________________
     void TMonitor::RemoveAll()
    {
       // Remove all sockets from the monitor.

       fActive->Delete();
       fDeActive->Delete();
    }

    //______________________________________________________________________________
     void TMonitor::Activate(TSocket *sock)
    {
       // Activate a de-activated socket.

       TIter next(fDeActive);
       TSocketHandler *s;

       while ((s = (TSocketHandler *) next())) {
          if (sock == s->GetSocket()) {
             fDeActive->Remove(s);
             fActive->Add(s);
             s->Add();
             return;
          }
       }
    }

    //______________________________________________________________________________
     void TMonitor::ActivateAll()
    {
       // Activate all de-activated sockets.

       TIter next(fDeActive);
       TSocketHandler *s;

       while ((s = (TSocketHandler *) next())) {
          fActive->Add(s);
          s->Add();
       }
       fDeActive->Clear();
    }

    //______________________________________________________________________________
     void TMonitor::DeActivate(TSocket *sock)
    {
       // De-activate a socket.

       TIter next(fActive);
       TSocketHandler *s;

       while ((s = (TSocketHandler *) next())) {
          if (sock == s->GetSocket()) {
             fActive->Remove(s);
             fDeActive->Add(s);
             s->Remove();
             return;
          }
       }
    }

    //______________________________________________________________________________
     void TMonitor::DeActivateAll()
    {
       // De-activate all activated sockets.

       TIter next(fActive);
       TSocketHandler *s;

       while ((s = (TSocketHandler *) next())) {
          fDeActive->Add(s);
          s->Remove();
       }
       fActive->Clear();
    }

    //______________________________________________________________________________
     TSocket *TMonitor::Select()
    {
       // Return pointer to socket for which an event is waiting.

       fReady = 0;

       while (!fReady)
          gSystem->InnerLoop();

       return fReady;
    }

    //______________________________________________________________________________
     TSocket *TMonitor::Select(Long_t timeout)
    {
       // Return pointer to socket for which an event is waiting. Wait a maximum
       // of timeout milliseconds. If return is due to timeout it returns
       // (TSocket *)-1.

       fReady = 0;

       TTimeOutTimer t(this, timeout);

       while (!fReady)
          gSystem->InnerLoop();

       return fReady;
    }

    //______________________________________________________________________________
     void TMonitor::SetReady(TSocket *sock)
    {
       // Called by TSocketHandler::Notify() to signal which socket is ready
       // to be read. User should not call this routine. The ready socket will
       // be returned via the Select() user function.

       fReady = sock;
    }

    //______________________________________________________________________________
     Int_t TMonitor::GetActive() const
    {
       // Return number of sockets in the active list.

       return fActive->GetSize();
    }

    //______________________________________________________________________________
     Int_t TMonitor::GetDeActive() const
    {
       // Return number of sockets in the de-active list.

       return fDeActive->GetSize();
    }

    //______________________________________________________________________________
     TList *TMonitor::GetListOfActives() const
    {
       // Returns a list with all active sockets. This list must be deleted
       // by the user. DO NOT call Delete() on this list as it will delete
       // the sockets that are still being used by the monitor.

       TList *list = new TList;

       TIter next(fActive);

       while (TSocketHandler *h = (TSocketHandler*) next())
          list->Add(h->GetSocket());

       return list;
    }

    //______________________________________________________________________________
     TList *TMonitor::GetListOfDeActives() const
    {
       // Returns a list with all de-active sockets. This list must be deleted
       // by the user. DO NOT call Delete() on this list as it will delete
       // the sockets that are still being used by the monitor.

       TList *list = new TList;

       TIter next(fDeActive);

       while (TSocketHandler *h = (TSocketHandler*) next())
          list->Add(h->GetSocket());

       return list;
    }