/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM 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 General Public 
 * License for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */


#ifndef NMM_THREADED_NET_HANDLER_LINUX_HPP
#define NMM_THREADED_NET_HANDLER_LINUX_HPP NMM_THREADED_NET_HANDLER_LINUX_HPP

#include "nmm/nmm_prefix.hpp"

#include "DispatchedNetHandler.hpp"

#include "nmm/utils/thread/ThreadMutex.hpp"
#include "nmm/utils/thread/ThreadCondition.hpp"

#include "nmm/utils/thread/TTask.hpp"

#include <vector>

#include "visibility.hpp"

namespace NMM {

  class NetReactor;

  /** Threaded Network Event Handler.
   *
   * This network handler applies the Leader-Followers Design Pattern to concurrently handle
   * events on a single socket using multiple threads allocated from a thread pool. The first
   * (primary) thread is invoked directly by the reactor and is initially the leader thread.
   * This thread may request a new (secondary) leader thread which performs socket I/O while
   * the first thread is doing other processing.
   *
   * The leader thread is responsible for rechecking for new events on the socket. Furthermore,
   * subclasses of this class may override a method which checks if data is already available
   * for reading. In this case, the leader thread does not wait for socket events but invokes
   * the event handler of the subclass directly.
   *
   * Every thread is in one of the following states: CHECK_FOR_EVENTS, HANDLE_EVENTS, IDLE
   * and PROCESSING. The primary thread is initially in state HANDLE_EVENTS and all secondary
   * threads are initially in state CHECK_FOR_EVENTS. In HANDLE_EVENTS the actual handling
   * method is invoked. It may optionally request a new leader thread, which causes the thread
   * to transition to state PROCESSING. In this case, the handler method has to return @c VOID.
   * If the thread should remain the leader (i.e. it has not requested a new leader thread),
   * the handling method must return @c RECHECK.
   *
   * In CHECK_FOR_EVENTS, the leader thread waits for a certain time for new events to occur.
   * If no events occurred, the leader thread transitions to state IDLE, and the socket is
   * registered at the reactor again. Follower threads always transition to IDLE after
   * PROCESSING and always return @c VOID.
   *
   * @see NetReactor ThreadPool WorkerThread
   */
  class DLLEXPORT ThreadedNetHandler : public DispatchedNetHandler {
  public:
    /** @name Constructor and Destructor
     */
    //@{
    ThreadedNetHandler();
    virtual ~ThreadedNetHandler();
    //@}

    /** Get the NetReactor where this handler is registered.
     */
    NetReactor& getNetReactor() const {
      return __net_reactor;
    }

    /** This method is called by the NetReactor and must be implement by all sub classes
     * \param socket The socket on which an event occurs.
     * \param events The events which have been registered.
     * \param revents The events which have been occured on the socket
     * \return VOID if nothing should be done with the socket, RECHECK if the socket should be checked for new events, 
     *         or REMOVE if the Socket should be no longer handled
     */
    virtual NetResult receiveEvent(SocketHandle socket, short events, short revents);

     /** This method returns true, if the NetHandler requires an own thread.
      * \return true it the NetHandler requires an own thread, otherwise false
      */
    virtual bool requireThread() const;

  protected:
    /** Disable notification for this handler.
     *
     * This method must be called by subclasses before this object is destroyed. It will block until
     * all threads have finished. If the leader thread is in state CHECK_FOR_EVENTS, it will be
     * interrupted to complete immediately. All threads which are in state HANDLE_EVENTS or PROCESSING
     * must finish themselves because they can not be interrupted.
     */
    void disableNotification();

    /** Request new leader thread.
     *
     * This method requests a new leader thread which is initially in state CHECK_FOR_EVENTS. This
     * method may only be called by the leader thread while in state HANDLE_EVENTS. The former leader
     * thread becomes a follower thread and transitions to state PROCESSING.
     */
    void requestLeaderThread();

    /** Check if more data is already available.
     *
     * This method is invoked by the leader thread before checking for I/O events. If it returns
     * @c false, then the leader thread checks for events on the socket. Otherwise, @c receiveEvent
     * is called directly with the same arguments
     */
    virtual bool isDataAvailable();

  private:
    enum InitialState { HANDLE_EVENTS, CHECK_FOR_EVENTS, IDLE };

    /** This method is called by the worker threads.
     */
    void doCheckForEvents();

    /** Main event handling method.
     *
     * This method checks for new I/O events on the socket. If events are available within a certain
     * time, then run is called with the curren thread as the leader thread. Otherwise, the method
     * returns and the thread becomes idle.
     *
     * @param state Next state the current thread is in
     */
    NetResult run(InitialState state);

  private:
    NetReactor&       __net_reactor;                ///< NetReactor where this handler is registered
    bool              __notification;               ///< Flag which controls whether this handler should be notified

    /* manage number of concurrent handlers */
    unsigned int      __thread_count;               ///< Number of threads currently running
    ThreadMutex       __event_mutex;                ///< Mutex used for waiting for event handlers to finish
    ThreadCondition   __event_condition;            ///< Condition use for waiting for event handlers to finish

    /* arguments of current invocation */
    SocketHandle      __socket;                     ///< The socket handle
    short             __events;                     ///< The requested events
    short             __revents;                    ///< The events that actually occurred
    TTask<ThreadedNetHandler> __task;               ///< The task for reinvoking this handler

    /* internal pipe for interrupting reckeck */
    // platform-specific(Linux)
    std::vector<int>  __pipe_socket;                ///< sockets for the pipe
    static char       __internal_char;              ///< Character which is written to pipe
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
