/* -*- C++ -*- */
// $Id: Module.h,v 4.19 1999/01/20 20:46:59 levine Exp $

// ============================================================================
//
// = LIBRARY
//    ace
//
// = FILENAME
//    Module.h
//
// = AUTHOR
//    Doug Schmidt
//
// ============================================================================

#ifndef ACE_MODULE_H
#define ACE_MODULE_H

#include "ace/ACE.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#include "ace/Task_T.h"

class ACE_Export ACE_Module_Base
{
  // = TITLE
  //   Workaround HP/C++ compiler bug with enums in templates.
  //
  // = DESCRIPTION
  //   Certain C++ compilers, e.g., the HP/UX 10.x and 9.x compilers,
  //   seem to fail if enums are defined inside a template, hence we
  //   have to move them into a base class.
public:
  enum
  {
    M_DELETE_NONE = 0,
    // Indicates that close() should not delete any Tasks.

    M_DELETE_READER = 1,
    // Indicates that close() should delete the writer Task.

    M_DELETE_WRITER = 2,
    // Indicates that close() should delete the reader Task.

    M_DELETE = 3
    // Indicates that close() deletes the Tasks.  Don't change this
    // value without updating the same enum in class ACE_Stream...
    // The <M_DELETE_READER> and <M_DELETE_WRITER> flags may be or'ed
    // together.
  };
};

template <ACE_SYNCH_DECL>
class ACE_Module : public ACE_Module_Base
{
  // = TITLE
  //     An abstraction for managing a bi-directional flow of messages.
  //
  // = DESCRIPTION
  //     This is based on the Module concept in System V Streams,
  //     which contains a pair of Tasks, one for handling upstream
  //     processing, one for handling downstream processing.  In
  //     general, you shouldn't subclass from this class, but instead
  //     subclass from the <ACE_Task>.
public:
  friend class ACE_Shutup_GPlusPlus;  // Turn off g++ warning

  // = Initialization and termination methods.
  ACE_Module (void);
  // Create an empty Module.

  ~ACE_Module (void);
  // Shutdown the Module.

  ACE_Module (const ASYS_TCHAR *module_name,
              ACE_Task<ACE_SYNCH_USE> *writer = 0,
              ACE_Task<ACE_SYNCH_USE> *reader = 0,
              void *args = 0,
              int flags = M_DELETE);
  // Create an initialized module with <module_name> as its identity
  // and <reader> and <writer> as its tasks.

  int open (const ASYS_TCHAR *module_name,
            ACE_Task<ACE_SYNCH_USE> *writer = 0,
            ACE_Task<ACE_SYNCH_USE> *reader = 0,
            void *a = 0,
            int flags = M_DELETE);
  // Create an initialized module with <module_name> as its identity
  // and <reader> and <writer> as its tasks.  Previously register
  // reader or writers or closed down and deleted according to the
  // value of flags_.  Should not be called from within
  // ACE_Task::module_closed().

  int close (int flags = M_DELETE_NONE);
  // Close down the Module and its Tasks.  The flags argument can be
  // used to override the default behaviour, which depends on previous
  // <flags> values in calls to c'tor(), open(), reader() and
  // writer().  A previous value M_DELETE[_XXX] can not be overridden.
  // Should not be called from within ACE_Task::module_closed().

  // = ACE_Task manipulation routines
  ACE_Task<ACE_SYNCH_USE> *writer (void);
  // Get the writer task.

  void writer (ACE_Task<ACE_SYNCH_USE> *q, int flags = M_DELETE_WRITER);
  // Set the writer task. <flags> can be used to indicate that the
  // module should delete the writer during a call to close or to the
  // destructor. If a previous writer exists, it is closed.  It may
  // also be deleted, depending on the old flags_ value.  Should not
  // be called from within ACE_Task::module_closed().

  ACE_Task<ACE_SYNCH_USE> *reader (void);
  // Get the reader task.

  void reader (ACE_Task<ACE_SYNCH_USE> *q, int flags = M_DELETE_READER);
  // Set the reader task. <flags> can be used to indicate that the
  // module should delete the reader during a call to close or to the
  // destructor. If a previous reader exists, it is closed.  It may
  // also be deleted, depending on the old flags_ value.  Should not
  // be called from within ACE_Task::module_closed()

  ACE_Task<ACE_SYNCH_USE> *sibling (ACE_Task<ACE_SYNCH_USE> *orig);
  // Set and get pointer to sibling <ACE_Task> in an <ACE_Module>

  // = Identify the module
  const ASYS_TCHAR *name (void) const;
  // Get the module name.
  void name (const ASYS_TCHAR *);
  // Set the module name.

  // = Argument to the Tasks.
  void *arg (void) const;
  // Get the argument passed to the tasks.

  void arg (void *);
  // Set the argument passed to the tasks.

  void link (ACE_Module<ACE_SYNCH_USE> *m);
  // Link to other modules in the ustream stack

  ACE_Module<ACE_SYNCH_USE> *next (void);
  // Get the next pointer to the module above in the stream.

  void next (ACE_Module<ACE_SYNCH_USE> *m);
  // Set the next pointer to the module above in the stream.

  void dump (void) const;
  // Dump the state of an object.

  ACE_ALLOC_HOOK_DECLARE;
  // Declare the dynamic allocation hooks.

private:
  int close_i (int which, int flags);
  // Implements the close operation for either the reader or the
  // writer task (depending on <which>).

  ACE_Task<ACE_SYNCH_USE> *q_pair_[2];
  // Pair of Tasks that form the "read-side" and "write-side" of the
  // ACE_Module partitioning.

  ASYS_TCHAR name_[MAXNAMLEN + 1];
  // Name of the ACE_Module.

  ACE_Module<ACE_SYNCH_USE> *next_;
  // Next ACE_Module in the stack.

  void *arg_;
  // Argument passed through to the reader and writer task when they
  // are opened.

  int flags_;
  // Holds flags which are used to determine if the reader and writer
  // task have to be deleted on exit
};

#if defined (__ACE_INLINE__)
#include "ace/Module.i"
#endif /* __ACE_INLINE__ */

#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
#include "ace/Module.cpp"
#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */

#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
#pragma implementation ("Module.cpp")
#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */

#endif /* ACE_MODULE_H */
