/*
 * Copyright (c) 2014-2026 Enrico M. Crisostomo
 *
 * This program 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; either version 3, or (at your option) any later version.
 *
 * This program 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
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @file
 * @brief Header of the fsw::event class.
 *
 * @copyright Copyright (c) 2014-2026 Enrico M. Crisostomo
 * @license GNU General Public License v. 3.0
 * @author Enrico M. Crisostomo
 * @version 1.18.0
 */

#ifndef FSW_EVENT_H
#  define FSW_EVENT_H

#  include <string>
#  include <ctime>
#  include <vector>
#  include <iostream>
#  include <optional>
#  include "../c/cevent.h"

namespace fsw
{
  enum class process_id_kind
  {
    none = 0,
    pid,
    tid
  };

  struct process_metadata
  {
    process_id_kind kind = process_id_kind::none;
    long long id = 0;
    int pidfd = -1;
    bool has_pidfd = false;
  };

  /**
   * @brief Type representing a file change event.
   *
   * This class represents a file change event in the `libfswatch` API.  An
   * event contains:
   *
   *   - The path.
   *   - The time the event was raised.
   *   - A vector of flags specifying the type of the event.
   *   - The correlation id of the event, if supported by the monitor, otherwise 0.
   */
  class event
  {
  public:
    /**
     * @brief Constructs an event.
     *
     * @param path The path the event refers to.
     * @param evt_time The time the event was raised.
     * @param flags The vector of flags specifying the type of the event.
     */
    event(std::string path, time_t evt_time, std::vector<fsw_event_flag> flags);

    /**
     * @brief Constructs an event.
     *
     * @param path The path the event refers to.
     * @param evt_time The time the event was raised.
     * @param flags The vector of flags specifying the type of the event.
     * @param correlation_id The correlation_id of the file the event refers to.
     */
    event(std::string path, time_t evt_time, std::vector<fsw_event_flag> flags, unsigned long correlation_id);

    /**
     * @brief Constructs an event with optional process metadata.
     *
     * @param path The path the event refers to.
     * @param evt_time The time the event was raised.
     * @param flags The vector of flags specifying the type of the event.
     * @param correlation_id The correlation_id of the file the event refers to.
     * @param process The optional process metadata associated with the event.
     */
    event(std::string path,
          time_t evt_time,
          std::vector<fsw_event_flag> flags,
          unsigned long correlation_id,
          process_metadata process);

    /**
     * @brief Destructs an event.
     *
     * This is a virtual destructor that performs no operations.
     */
    virtual ~event();

    /**
     * @brief Returns the path of the event.
     *
     * @return The path of the event.
     */
    std::string get_path() const;

    /**
     * @brief Returns the time of the event.
     *
     * @return The time of the event.
     */
    time_t get_time() const;

    /**
     * @brief Returns the flags of the event.
     *
     * @return The flags of the event.
     */
    std::vector<fsw_event_flag> get_flags() const;

    /**
     * @brief Returns the correlation_id of the file of the event.
     * @return The correlation_id of the file of the event.
     */
    unsigned long get_correlation_id() const;

    /**
     * @brief Returns true if the event has process attribution metadata.
     */
    bool has_process_id() const;

    /**
     * @brief Returns the process or thread identifier associated with this event.
     *
     * Returns 0 when no process attribution metadata is available.
     */
    long long get_process_id() const;

    /**
     * @brief Returns the process identifier kind.
     */
    process_id_kind get_process_id_kind() const;

    /**
     * @brief Returns true if the event has a process file descriptor.
     */
    bool has_process_pidfd() const;

    /**
     * @brief Returns the process file descriptor associated with this event.
     *
     * Returns -1 when no process file descriptor is available.  The descriptor
     * is owned by the event producer and is only valid during callback
     * processing.
     */
    int get_process_pidfd() const;

    /**
     * @brief Get the display name of a process identifier kind.
     */
    static std::string get_process_id_kind_name(process_id_kind kind);

    /**
     * @brief Get event flag by name.
     *
     * @param name The name of the event flag to look for.
     * @return The event flag whose name is @p name, otherwise
     * @exception libfsw_exception if no event flag is found.
     */
    static fsw_event_flag get_event_flag_by_name(const std::string& name);

    /**
     * @brief Get the name of an event flag.
     *
     * @param flag The event flag.
     * @return The name of @p flag.
     * @exception libfsw_exception if no event flag is found.
     */
    static std::string get_event_flag_name(const fsw_event_flag& flag);

  private:
    std::string path;
    time_t evt_time;
    std::vector<fsw_event_flag> evt_flags;
    unsigned long correlation_id = 0;
    process_metadata process;
  };

  /**
   * @brief Overload of the `<<` operator to print an event using `iostreams`.
   *
   * @param out A reference to the output stream.
   * @param flag The flag to print.
   * @return A reference to the stream.
   */
  std::ostream& operator<<(std::ostream& out, const fsw_event_flag flag);
}

#endif  /* FSW_EVENT_H */
