/*
  eventloopinteractor.h
  Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB

  This file is part of GPGME++.

  GPGME++ is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  GPGME++ is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with GPGME++; see the file COPYING.LIB.  If not, write to the
  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

// -*- c++ -*-
#ifndef __GPGMEPP_EVENTLOOPINTERACTOR_H__
#define __GPGMEPP_EVENTLOOPINTERACTOR_H__

#include <gpgme++/gpgme++_export.h>

namespace GpgME {

  class Context;
  class Error;
  class TrustItem;
  class Key;

  /*! \file eventloopinteractor.h
      \brief Abstract base class for gpgme's external event loop support

      This class does most of the work involved with hooking GpgME++
      up with external event loops, such as the GTK or Qt ones.

      It actually provides two interfaces: An interface to the gpgme
      IO Callback handling and one for gpgme events. The IO Callback
      interface consists of the three methods \c actOn(), \c
      registerWatcher() and \c unregisterWatcher(). The event
      interface consists of the three methods \c nextTrustItemEvent(),
      \c nextKeyEvent() and \c operationDoneEvent().

      \sect General Usage

      \c EventLoopInteractor is designed to be used as a
      singleton. However, in order to make any use of it, you have to
      subclass it and reimplement it's pure virtual methods (see
      below). We suggest you keep the constructor protected and
      provide a static \c instance() method that returns the single
      instance. Alternatively, you can create an instance on the
      stack, e.g. in \c main().

      If you want \c EventLoopInteractor to manage a particular \c
      Context, just call \c manage() on the \c Context. OTOH, if you
      want to disable IO callbacks for a \c Context, use \c unmanage().

      \sect IO Callback Interface

      One part of this interface is represented by \c
      registerWatcher() and \c unregisterWatcher(), both of which are
      pure virtual. \c registerWatcher() should do anything necessary
      to hook up watching of file descriptor \c fd for reading (\c dir
      = \c Read) or writing (\c dir = Write) to the event loop you use
      and return a tag identifying that particular watching process
      uniquely. This could be the index into an array of objects you
      use for that purpose or the address of such an object. E.g. in
      Qt, you'd essentially just create a new \c QSocketNotifier:

      \verbatim
      void * registerWatcher( int fd, Direction dir ) {
        return new QSocketNotifier( fd, dir == Read ? QSocketNotifier::Read : QSocketNotifier::Write );
        // misses connecting to the activated() signal...
      }
      \endverbatim

      which uses the address of the created object as unique tag. The
      tag returned by \c registerWatcher is stored by \c
      EventLoopInteractor and passed as argument to \c
      unregisterWatcher(). So, in the picture above, you'd implement \c
      unregisterWatcher() like this:

      \verbatim
      void unregisterWatcher( void * tag ) {
        delete static_cast<QSocketNotifier*>( tag );
      }
      \endverbatim

      The other part of the IO callback interface is \c actOn(), which
      you should call if you receive notification from your event loop
      about activity on file descriptor \c fd in direction \c dir. In
      the picture above, you'd call this from the slot connected to
      the socket notifier's \c activated() signal.

      \note \c registerWatcher() as well as \c unregisterWatcher() may
      be called from within \c actOn(), so be careful with
      e.g. locking in threaded environments and keep in mind that the
      object you used to find the \c fd and \c dir fo the \c actOn()
      call might be deleted when \c actOn() returns!

      \sect Event Handler Interface


  */
  class GPGMEPP_EXPORT EventLoopInteractor {
  protected:
    EventLoopInteractor();
  public:
    virtual ~EventLoopInteractor();

    static EventLoopInteractor * instance() {
        return mSelf;
    }

    void manage( Context * context );
    void unmanage( Context * context );

    enum Direction { Read, Write };
  protected:
    //
    // IO Notification Interface
    //

    /** Call this if your event loop detected activity on file
        descriptor fd, with direction dir */
    void actOn( int fd, Direction dir );

    virtual void * registerWatcher( int fd, Direction dir, bool & ok ) = 0;
    virtual void unregisterWatcher( void * tag ) = 0;

    //
    // Event Handler Interface
    //

    virtual void operationStartEvent( Context * context ) = 0;
    virtual void nextTrustItemEvent( Context * context, const TrustItem & item ) = 0;
    virtual void nextKeyEvent( Context * context, const Key & key ) = 0;
    virtual void operationDoneEvent( Context * context, const Error & e ) = 0;

  private:
    class Private;
    friend class Private;
    Private * const d;
    static EventLoopInteractor * mSelf;
  };

}

#endif // __GPGMEPP_EVENTLOOPINTERACTOR_H__
