text: #pragma once
  
  #include "section.hpp"
  #include "stream.hpp"
  
  namespace openpower::pels
  {
  
  /**
   * @class ExtendedUserData
   *
   * This represents the Extended User Data section in a PEL.  It is free form
   * data that the creator knows the contents of.  The component ID, version, and
   * sub-type fields in the section header are used to identify the format.
   *
   *  This section is used for one subsystem to add FFDC data to a PEL created
   *  by another subsystem.  It is basically the same as a UserData section,
   *  except it has the creator ID of the section creator stored in the section.
   *
   * The Section base class handles the section header structure that every
   * PEL section has at offset zero.
   */
  class ExtendedUserData : public Section
  {
    public:
      ExtendedUserData() = delete;
      ~ExtendedUserData() = default;
      ExtendedUserData(const ExtendedUserData&) = default;
      ExtendedUserData& operator=(const ExtendedUserData&) = default;
      ExtendedUserData(ExtendedUserData&&) = default;
      ExtendedUserData& operator=(ExtendedUserData&&) = default;
  
      /**
       * @brief Constructor
       *
       * Fills in this class's data fields from the stream.
       *
       * @param[in] pel - the PEL data stream
       */
      explicit ExtendedUserData(Stream& pel);
  
      /**
       * @brief Constructor
       *
       * Create a valid ExtendedUserData object with the passed in data.
       *
       * The component ID, subtype, and version are used to identify
       * the data to know which parser to call.
       *
       * @param[in] componentID - Component ID of the creator
       * @param[in] subType - The type of user data
       * @param[in] version - The version of the data
       */
      ExtendedUserData(uint16_t componentID, uint8_t subType, uint8_t version,
                       uint8_t creatorID, const std::vector<uint8_t>& data);
  
      /**
       * @brief Flatten the section into the stream
       *
       * @param[in] stream - The stream to write to
       */
      void flatten(Stream& stream) const override;
  
      /**
       * @brief Returns the size of this section when flattened into a PEL
       *
       * @return size_t - the size of the section
       */
      size_t flattenedSize()
      {
          return Section::flattenedSize() + sizeof(_creatorID) +
                 sizeof(_reserved1B) + sizeof(_reserved2B) + _data.size();
      }
  
      /**
       * @brief Returns the section creator ID field.
       *
       * @return uint8_t - The creator ID
       */
      uint8_t creatorID() const
      {
          return _creatorID;
      }
  
      /**
       * @brief Returns the raw section data
       *
       * This doesn't include the creator ID.
       *
       * @return std::vector<uint8_t>&
       */
      const std::vector<uint8_t>& data() const
      {
          return _data;
      }
  
      /**
       * @brief Returns the section data updated with new data
       *
       * @param[in] subType - The type of user data
       * @param[in] componentID - Component ID of the creator
       * @param[in] newData - The new data
       *
       */
      void updateDataSection(const uint8_t subType, const uint16_t componentId,
                             const std::vector<uint8_t>& newData)
      {
          auto origDataSize = 0;
  
          if (newData.size() >= 4)
          {
              // Update component Id & subtype in section header of ED
              _header.componentID = static_cast<uint16_t>(componentId);
              _header.subType = static_cast<uint8_t>(subType);
  
              if (newData.size() > _data.size())
              {
                  // Don't allow section to get bigger
                  origDataSize = _data.size();
                  _data = newData;
                  _data.resize(origDataSize);
              }
              else
              {
                  // Use shrink to handle 4B alignment and update the header size
                  auto status =
                      shrink(Section::flattenedSize() + 4 + newData.size());
                  if (status)
                  {
                      origDataSize = _data.size();
                      _data = newData;
                      _data.resize(origDataSize);
                  }
              }
          }
      }
  
      /**
       * @brief Get the section contents in JSON
       *
       * @param[in] creatorID - Creator Subsystem ID - unused (see the .cpp)
       * @param[in] plugins - Vector of strings of plugins found in filesystem
       *
       * @return The JSON as a string if a parser was found,
       *         otherwise std::nullopt.
       */
      std::optional<std::string>
          getJSON(uint8_t creatorID,
                  const std::vector<std::string>& plugins) const override;
  
      /**
       * @brief Shrink the section
       *
       * The new size must be between the current size and the minimum
       * size, which is 12 bytes.  If it isn't a 4 byte aligned value
       * the code will do the aligning before the resize takes place.
       *
       * @param[in] newSize - The new size in bytes
       *
       * @return bool - true if successful, false else.
       */
      bool shrink(size_t newSize) override;
  
    private:
      /**
       * @brief Fills in the object from the stream data
       *
       * @param[in] stream - The stream to read from
       */
      void unflatten(Stream& stream);
  
      /**
       * @brief Validates the section contents
       *
       * Updates _valid (in Section) with the results.
       */
      void validate() override;
  
      /**
       * @brief The subsystem creator ID of the code that
       *        created this section.
       */
      uint8_t _creatorID;
  
      /**
       * @brief Reserved
       */
      uint8_t _reserved1B;
  
      /**
       * @brief Reserved
       */
      uint16_t _reserved2B;
  
      /**
       * @brief The section data
       */
      std::vector<uint8_t> _data;
  };
  
  } // namespace openpower::pels
  