/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         https://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef itkEventObject_h
#define itkEventObject_h

#include "itkMacro.h"
#include "itkIndent.h"

namespace itk
{
/** \class EventObject
 * \brief Abstraction of the Events used to communicating among filters
    and with GUIs.
 *
 * EventObject provides a standard coding for sending and receiving messages
 * indicating things like the initiation of processes, end of processes,
 * modification of filters.
 *
 * EventObjects form a hierarchy similar to the itk::ExceptionObject allowing
 * to factorize common events in a tree-like structure. Higher detail can
 * be assigned by users by subclassing existing itk::EventObjects.
 *
 * EventObjects are used by itk::Command and itk::Object for implementing the
 * Observer/Subject design pattern. Observers register their interest in
 * particular kinds of events produced by a specific itk::Object. This
 * mechanism decouples classes among them.
 *
 * As opposed to itk::Exception, itk::EventObject does not represent error
 * states, but simply flow of information allowing to trigger actions
 * as a consequence of changes occurring in state on some itk::Objects.
 *
 * itk::EventObject carries information in its own type, it relies on the
 * appropriate use of the RTTI (Run Time Type Information).
 *
 * A set of standard EventObjects is defined near the end of itkEventObject.h.
 *
 * \sa itk::Command
 * \sa itk::ExceptionObject
 *
 * \ingroup ITKSystemObjects
 * \ingroup ITKCommon
 */
class ITKCommon_EXPORT EventObject
{
public:
  /** Constructor and copy constructor.  Note that these functions will be
   * called when children are instantiated. */
  EventObject() = default;

  EventObject(const EventObject &) = default;

  EventObject &
  operator=(const EventObject &) = delete;

  /** Virtual destructor needed  */
  virtual ~EventObject() = default;

  /**  Create an Event of this type This method work as a Factory for
   *  creating events of each particular type. */
  [[nodiscard]] virtual EventObject *
  MakeObject() const = 0;

  /** Print Event information.  This method can be overridden by
   * specific Event subtypes.  The default is to print out the type of
   * the event. */
  virtual void
  Print(std::ostream & os) const;

  /** Return the StringName associated with the event. */
  [[nodiscard]] virtual const char *
  GetEventName() const = 0;

  /** Check if given event matches or derives from this event. */
  virtual bool
  CheckEvent(const EventObject *) const = 0;

protected:
  /** Methods invoked by Print() to print information about the object
   * including superclasses. Typically not called by the user (use Print()
   * instead) but used in the hierarchical print process to combine the
   * output of several classes.  */
  virtual void
  PrintSelf(std::ostream & os, Indent indent) const;

  virtual void
  PrintHeader(std::ostream & os, Indent indent) const;

  virtual void
  PrintTrailer(std::ostream & os, Indent indent) const;
};

/** Generic inserter operator for EventObject and its subclasses. */
inline std::ostream &
operator<<(std::ostream & os, const EventObject & e)
{
  e.Print(os);
  return os;
}


#define ITKEvent_EXPORT ITKCommon_EXPORT

/**
 *  Macros for creating new Events
 */

#define itkEventMacroDeclaration(classname, super)         \
  /** \class classname */                                  \
  class ITKEvent_EXPORT classname : public super           \
  {                                                        \
  public:                                                  \
    using Self = classname;                                \
    using Superclass = super;                              \
    classname() = default;                                 \
    classname(const Self & s);                             \
    virtual ~classname() override;                         \
    virtual const char *                                   \
    GetEventName() const override;                         \
    virtual bool                                           \
    CheckEvent(const itk::EventObject * e) const override; \
    virtual itk::EventObject *                             \
    MakeObject() const override;                           \
                                                           \
  private:                                                 \
    void                                                   \
    operator=(const Self &);                               \
  };                                                       \
  ITK_MACROEND_NOOP_STATEMENT

#define itkEventMacroDefinition(classname, super)                            \
  classname::classname(const classname & s)                                  \
    : super(s)                                                               \
  {}                                                                         \
  classname::~classname() {}                                                 \
  const char * classname::GetEventName() const { return #classname; }        \
  bool         classname::CheckEvent(const itk::EventObject * e) const       \
  {                                                                          \
    return dynamic_cast<const classname *>(e) != nullptr;                    \
  }                                                                          \
  itk::EventObject * classname::MakeObject() const { return new classname; } \
  ITK_MACROEND_NOOP_STATEMENT

#if !defined(ITK_LEGACY_REMOVE)
// Support Pre 2015 code bases

// This macro duplicates some of the declaration and definition
// macro code. The purpose is to provide a backward compatibility API
// for ITK applications.
// NOTE: New applications should use itkEventMacroDeclaration (in a
// .h file) and itkEventMacroDefinition (in a compiled .cxx
// file). This new approach guarantees that only one copy of the
// implementation will be present.
//
#  define itkEventMacro(classname, super)                \
    /** \class classname */                              \
    class ITKEvent_EXPORT classname : public super       \
    {                                                    \
    public:                                              \
      using Self = classname;                            \
      using Superclass = super;                          \
      classname() {}                                     \
      virtual ~classname() {}                            \
      virtual const char *                               \
      GetEventName() const                               \
      {                                                  \
        return #classname;                               \
      }                                                  \
      virtual bool                                       \
      CheckEvent(const itk::EventObject * e) const       \
      {                                                  \
        return dynamic_cast<const Self *>(e) != nullptr; \
      }                                                  \
      virtual itk::EventObject *                         \
      MakeObject() const                                 \
      {                                                  \
        return new Self;                                 \
      }                                                  \
      classname(const Self & s)                          \
        : super(s) {};                                   \
                                                         \
    private:                                             \
      void                                               \
      operator=(const Self &);                           \
    };
#endif
/**
 *      Declare some common ITK events
 */
/** @ITKStartGrouping */
itkEventMacroDeclaration(NoEvent, EventObject);
itkEventMacroDeclaration(AnyEvent, EventObject);
itkEventMacroDeclaration(DeleteEvent, AnyEvent);
itkEventMacroDeclaration(StartEvent, AnyEvent);
itkEventMacroDeclaration(EndEvent, AnyEvent);
itkEventMacroDeclaration(ProgressEvent, AnyEvent);
itkEventMacroDeclaration(ExitEvent, AnyEvent);
itkEventMacroDeclaration(AbortEvent, AnyEvent);
itkEventMacroDeclaration(ModifiedEvent, AnyEvent);
itkEventMacroDeclaration(InitializeEvent, AnyEvent);
itkEventMacroDeclaration(IterationEvent, AnyEvent);
itkEventMacroDeclaration(MultiResolutionIterationEvent, IterationEvent);
itkEventMacroDeclaration(PickEvent, AnyEvent);
itkEventMacroDeclaration(StartPickEvent, PickEvent);
itkEventMacroDeclaration(EndPickEvent, PickEvent);
itkEventMacroDeclaration(AbortCheckEvent, PickEvent);
itkEventMacroDeclaration(FunctionEvaluationIterationEvent, IterationEvent);
itkEventMacroDeclaration(GradientEvaluationIterationEvent, IterationEvent);
itkEventMacroDeclaration(FunctionAndGradientEvaluationIterationEvent, IterationEvent);
itkEventMacroDeclaration(UserEvent, AnyEvent);
/** @ITKEndGrouping */
#undef ITKEvent_EXPORT
#define ITKEvent_EXPORT ITK_ABI_EXPORT

} // end namespace itk

#endif
