// Copyright (C) 2021 Christian Brommer, Control of Networked Systems, University of Klagenfurt, Austria.
//
// All rights reserved.
//
// This software is licensed under the terms of the BSD-2-Clause-License with
// no commercial use allowed, the full terms of which are made available
// in the LICENSE file. No license in patents is granted.
//
// You can contact the author at <christian.brommer@ieee.org>

#ifndef BUFFERENTRYTYPE_H
#define BUFFERENTRYTYPE_H

#include <mars/sensors/sensor_abs_class.h>
#include <mars/time.h>
#include <mars/type_definitions/buffer_data_type.h>
#include <iostream>
#include <set>

namespace BufferMetadataTypes
{
///
/// \brief Possible metadata states
/// \note Ordered by likelihood of occurence such that the performance of the search function can benefit from it.
///
enum BufferMetadataType
{
  none,
  invalid,
  init,
  out_of_order,
  auto_add,  ///< auto generated measurement e.g. introduced by interpolation
};
}  // namespace BufferMetadataTypes

namespace mars
{
using BufferMetadataType = BufferMetadataTypes::BufferMetadataType;

class BufferEntryType
{
public:
  Time timestamp_{ 0.0 };
  BufferDataType data_{};
  std::shared_ptr<SensorAbsClass> sensor_handle_{ nullptr };
  int metadata_{ BufferMetadataType::invalid };

  BufferEntryType() = default;

  BufferEntryType(const Time& timestamp, BufferDataType data, std::shared_ptr<SensorAbsClass> sensor,
                  const int& metadata = BufferMetadataType::none);

  bool operator<(const BufferEntryType& rhs) const;
  bool operator<=(const BufferEntryType& rhs) const;
  bool operator>(const BufferEntryType& rhs) const;
  bool operator>=(const BufferEntryType& rhs) const;
  friend std::ostream& operator<<(std::ostream& out, const BufferEntryType& entry);

  ///
  /// \brief get_metadata_label decodes the 'BufferMetadataType' enum to strings
  /// \param label enum integer of 'BufferMetadataType'
  /// \return String description
  ///
  static std::string get_metadata_label(int label);

  ///
  /// \brief IsMeasurement
  /// \return True if the metadata can be found in the metadata_measurement_filter_. False otherwise.
  ///
  bool IsMeasurement() const;

  ///
  /// \brief IsValid Check if the entry is valid for usage
  ///
  /// \return true valid entry
  /// \return false invalid e.g. a measurement that was an outlier and no state was calculated
  ///
  bool IsValid() const;

  ///
  /// \brief IsAutoGenerated
  /// \return True if the entry is an auto generated entry
  ///
  bool IsAutoGenerated() const;

  ///
  /// \brief HasState checks if the BufferDataType has a (core) state
  ///
  /// \return true if the  BufferDataType contains a core state
  /// \return false otherwise
  ///
  bool HasStates() const;

  ///
  /// \brief ClearStates resets states of the buffer entry
  ///
  void ClearStates();

private:
  std::set<int> metadata_valid_filter_;
  std::set<int> metadata_auto_filter_;
};
}  // namespace mars
#endif  // BUFFERENTRYTYPE_H
