//===-- rosa/support/csv/CSVWriter.hpp --------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/csv/CSVWriter.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Facitilities to write CSV files.
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_SUPPORT_CSV_CSVWRITER_HPP
#define ROSA_SUPPORT_CSV_CSVWRITER_HPP

#include <ostream>

namespace rosa {
namespace csv {

/// Provides facilities to write values into a CSV file.
///
/// The writer emits a comma, the character `,`, between each written values.
/// The resulted stream is a flat CSV file as it consists of onlyone row, no new
/// line is emitted.
///
/// \tparam T type of values to write
template <typename T>
class CSVWriter {
public:
  /// Creates a new instance.
  ///
  /// \param [in,out] S output stream to write to
  ///
  /// \note The writer operates on non-binary outputs as long as \p S is in
  /// good state.
  CSVWriter(std::ostream &S)
      : Str(S.good() && !(S.flags() & std::ios::binary) ? &S : nullptr),
        IsFirst(true) {}

  /// Tells if the last operation was successful.
  ///
  /// \return if the last operation was successful
  bool good(void) const noexcept {
    return Str != nullptr;
  }

  /// Writes an entry to the output stream.
  ///
  /// The implementation does anything only if the last operation was
  /// successful. If so, \p V is written to \c rosa::csv::CSVWriter::Str.
  /// The emitted value is preceded with a comma if the actual call is not the
  /// first one for \p this object. Success of the operation is checked at the
  /// end.
  ///
  /// \param V value to write
  void write(const T &V) {
    if (Str) {
      if (!IsFirst) {
        *Str << ',';
      } else {
        IsFirst = false;
      }
      *Str << V;
      if (!Str->good()) {
        Str = nullptr;
      }
    }
  }

private:
  std::ostream *Str; ///< Output stream to write to.
  bool IsFirst;      ///< Denotes if the next write would be the first one.
};

/// Writes a value to a CSV file with \c rosa::csv::CSVWriter.
///
/// \see rosa::csv::CSVWriter
///
/// \tparam T type of value to write
///
/// \param [in,out] W object to write with
/// \param V value to write
///
/// \return \p W after writing \p V with it
template <typename T>
CSVWriter<T> &operator<<(CSVWriter<T> &W, const T& V) {
  W.write(V);
  return W;
}

} // End namespace csv
} // End namespace rosa

#endif // ROSA_SUPPORT_CSV_CSVWRITER_HPP
